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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章