C++鄰接表與有向圖

C++鄰接表與有向圖

參照《算法》實現了C++鄰接表表示的有向圖,實現了書中有向圖的各種算法,包括判斷有向圖可達性,尋找有向圖中的環,頂點的先序、後序和逆後序排列以及Kosaraju算法尋找強連通域。

具體算法不再記錄,直接參考《算法》有向圖一章,C++代碼及註釋如下:

#include<iostream>
#include<queue>
#include<algorithm>
#include<map>
#include<stack>
#include<vector>
using namespace std;
/*
char
頂點       中間節點
VNode     ENode
0 | A --> 2(C) 1(B)
1 | B --> 4(E) 3(D) 0(A)
2 | C --> 6(G) 5(F) 0(A)
3 | D --> 7(H) 1(B)
4 | E --> 7(H) 1(B)
5 | F --> 6(G) 2(C)
6 | G --> 5(F) 2(C)
7 | H --> 4(E) 3(D)

int
頂點       中間節點
VNode     ENode
0 | 0 --> 2 1
1 | 1 --> 4 3 0
2 | 2 --> 6 5 0
3 | 3 --> 7 1
4 | 4 --> 7 1
5 | 5 --> 6 2
6 | 6 --> 5 2
7 | 7 --> 4 3
*/
const int MAX = 20;
struct ENode      //鄰接表的中間節點
{
    int adjvex;   //對應索引
    ENode* next;
};
typedef struct VNode //鄰接表頂點
{
    int vertex;     //值
    ENode* firstarc; //指向第一個中間節點
}AdjList[MAX];


class ALGraph         //圖
{
private:
    AdjList adjList;                        //鄰接表數組
    AdjList reverse_adjList;                //反向鄰接表數組
    int vexNum;                             //節點數量
    int arcNum;                             //連邊數量
    bool visited[MAX];                      //標記被訪問
    bool onStack[MAX];                      //標記遞歸調用的棧上的所有頂點
    int edgeTo[MAX];                        //記錄環中的點
    vector<stack<int>> cycles;              //環
    queue<int> pre;                         //所有點的前序排列
    queue<int> post;                        //所有點的後序排列
    stack<int> reversePost;                 //所有點的逆後序排列
    vector<int> SConnectedField;            //強連通域
    vector<vector<int>> SConnectedFileds;   //強連通域集合
public:
    void CreateGraph();                     //創建圖
    void PrintGraph();                      //打印圖
    void DirectedReach(int v);              //有向圖的可達性
    void reachDFS(int v);                   //有向圖可達性DFS
    void DirectedCycle();                   //尋找圖中有向環
    void cycleDFS(int v);                   //判斷環DFS
    void PrintCycles();                     //打印所有環
    void Order(bool reverse);               //頂點排序
    void orderDFS(int v, bool reverse);     //頂點排序的DFS
    void PrintOrder();                      //打印序列
    void Kosaraju();                        //Kosaraju算法尋找強連通域
    void KosarajuDFS(int v);                //Kosaraju算法DFS
    void PrintConnectedFields();            //打印強連通域
};

void ALGraph::CreateGraph()
{
    cout << "請輸入圖的頂點數:" << endl;
    cin >> this->vexNum;
    cout << "請輸入圖的弧數:" << endl;
    cin >> this->arcNum;
    cout << "請輸入頂點信息:" << endl;
    for (int i = 0; i<this->vexNum; i++)  //構建頂點數組
    {
        cin >> this->adjList[i].vertex;
        this->reverse_adjList[i].vertex = this->adjList[i].vertex;
        this->adjList[i].firstarc = nullptr;
        this->reverse_adjList[i].firstarc = nullptr;
    }
    cout << "請輸入" << this->arcNum << "個弧的信息:" << endl;
    for (int i = 0; i<this->arcNum; i++)  //構建每條鄰接表
    {
        int h1, h2;
        cin >> h1 >> h2;
        ENode* temp = new ENode();               //構建正向圖
        temp->adjvex = h2;
        temp->next = this->adjList[h1].firstarc;
        this->adjList[h1].firstarc = temp;

        temp = new ENode();                      //構建反向圖
        temp->adjvex = h1;
        temp->next = this->reverse_adjList[h2].firstarc;
        this->reverse_adjList[h2].firstarc = temp;
    }
}
void ALGraph::PrintGraph()
{
    cout << "---------正序圖---------" << endl;
    for (int i = 0; i<this->vexNum; i++)
    {
        cout << this->adjList[i].vertex << "--------->";
        ENode* p = this->adjList[i].firstarc;
        while (p)
        {
            cout << this->adjList[p->adjvex].vertex << " ";
            p = p->next;
        }
        cout << endl;
    }
    cout << "---------逆序圖---------" << endl;
    for (int i = 0; i<this->vexNum; i++)
    {
        cout << this->reverse_adjList[i].vertex << "--------->";
        ENode* p = this->reverse_adjList[i].firstarc;
        while (p)
        {
            cout << this->reverse_adjList[p->adjvex].vertex << " ";
            p = p->next;
        }
        cout << endl;
    }
}
void ALGraph::DirectedReach(int v)
{
    for (int i = 0; i<this->vexNum; i++)
    {
        visited[i] = false;
    }
    reachDFS(v);
}
void ALGraph::reachDFS(int v)   //深度優先搜索判斷可達的點
{
    visited[v] = true;
    cout << this->adjList[v].vertex << " ";
    ENode* p = this->adjList[v].firstarc;
    while (p)
    {
        if (!visited[p->adjvex])
        {
            reachDFS(p->adjvex);
        }
        p = p->next;
    }
}
void ALGraph::DirectedCycle()
{
    for (int i = 0; i<this->vexNum; i++)
    {
        onStack[i] = false;
        edgeTo[i] = 0;
        visited[i] = false;
    }
    for (int i = 0; i<this->vexNum; i++)
    {
        if (!visited[i])
            cycleDFS(i);
    }
}
void ALGraph::cycleDFS(int v)    //深度優先搜索尋找環
{
    onStack[v] = true;
    visited[v] = true;
    ENode* p = this->adjList[v].firstarc;
    while (p)
    {
        if (!visited[p->adjvex])
        {
            edgeTo[p->adjvex] = v;
            cycleDFS(p->adjvex);
        }
        else if (onStack[p->adjvex])   //下一個頂點在棧中,表示形成一個環
        {
            stack<int> cycle;
            for (int x = v; x != p->adjvex; x = edgeTo[x])  //記錄環的各個點
                cycle.push(x);
            cycle.push(p->adjvex);
            cycle.push(v);
            cycles.push_back(cycle);
        }
        onStack[v] = false;
        p = p->next;
    }
}
void ALGraph::PrintCycles()
{
    vector<stack<int>>::iterator it = cycles.begin();
    for (; it != cycles.end(); it++)
    {
        while (!(*it).empty())
        {
            cout << (*it).top() << " ";
            (*it).pop();
        }
        cout << endl;
    }
}
void ALGraph::Order(bool reverse)
{
    for (int i = 0; i<this->vexNum; i++)
    {
        visited[i] = false;
    }
    for (int i = 0; i<this->vexNum; i++)
    {
        if (!visited[i])
            orderDFS(i, reverse);
    }
}
void ALGraph::orderDFS(int v, bool reverse)
{
    pre.push(v);               //前序排列,在遞歸之前加入隊列
    visited[v] = true;
    ENode* p = nullptr;
    if (!reverse)
        p = this->adjList[v].firstarc;
    else
        p = this->reverse_adjList[v].firstarc;
    while (p)
    {
        if (!visited[p->adjvex])
            orderDFS(p->adjvex, reverse);
        p = p->next;
    }
    post.push(v);               //後序排列,在遞歸之後加入隊列
    reversePost.push(v);        //逆後序排列,遞歸之後加入棧
}
void ALGraph::PrintOrder()
{
    cout << "前序排列:" << endl;
    while (!pre.empty())
    {
        cout << pre.front() << " ";
        pre.pop();
    }
    cout << endl << "後序排列:" << endl;
    while (!post.empty())
    {
        cout << post.front() << " ";
        post.pop();
    }
    cout << endl << "逆後序排列:" << endl;
    while (!reversePost.empty())
    {
        cout << reversePost.top() << " ";
        reversePost.pop();
    }
    cout << endl;
}
void ALGraph::Kosaraju()          //Kosaraju算法尋找強連通域
{
    this->Order(true);            //首先進行拓撲排序,獲取反向圖的逆反排序
    for (int i = 0; i<this->vexNum; i++)
    {
        visited[i] = false;
    }

    while (!reversePost.empty())    //按照逆反排序對正向圖進行DFS
    {
        int v = reversePost.top();
        reversePost.pop();
        if (!visited[v])
        {
            KosarajuDFS(v);
            SConnectedFileds.push_back(SConnectedField); //加入一個連通域
            SConnectedField.clear();
        }

    }
}
void ALGraph::KosarajuDFS(int v)      //Kosaraju的DFS
{
    visited[v] = true;
    SConnectedField.push_back(v);       //同一連通域插入
    ENode* p = this->adjList[v].firstarc;
    while (p)
    {
        if (!visited[p->adjvex])
            KosarajuDFS(p->adjvex);
        p = p->next;
    }
}
void ALGraph::PrintConnectedFields()
{
    for (int i = 0; i<SConnectedFileds.size(); i++)
    {
        for (int j = 0; j<SConnectedFileds[i].size(); j++)
        {
            cout << SConnectedFileds[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}

int main()
{
    ALGraph* grapth = new ALGraph();
    grapth->CreateGraph();
    grapth->PrintGraph();
    grapth->Kosaraju();
    grapth->PrintConnectedFields();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章