zoukankan      html  css  js  c++  java
  • 数据结构之图

    1.图的邻接矩阵表示

    #include <iostream>
    #include<queue>
    using namespace std;

    /*
    图的邻接矩阵表示法
    */

    const int MaxVertexNum = 100; //顶点数最大为100
    const int INFINITY = 65535; //两点之间的权重值设为65535时,两点之间无边
    typedef int Vertex; //用顶点的下表表示顶点,为整型
    typedef int WeightType; //边的权值设为整型
    typedef char DataType; //顶点存储的数据类型设为字符型

    //边的定义
    typedef struct ENode* PtrToENode;
    struct ENode
    {
    Vertex V1, V2; //边的两个顶点
    WeightType Weight; //边上的权重
    };
    typedef PtrToENode Edge; //定义了一个数据类型,指向边结构体的指针

    //图结点的定义,用邻接矩阵表示
    typedef struct GNode* PtrToGNode;
    struct GNode
    {
    int Nv; //顶点数量
    int Ne; //边的数量
    WeightType G[MaxVertexNum][MaxVertexNum]; //两条边之间的权重
    DataType Data[MaxVertexNum]; //每个顶点存放的数据
    };
    typedef PtrToGNode MGraph; //定义了一个数据类型,指向图的指针

    bool Visited[MaxVertexNum] = { false }; //顶点是否遍历过的标志,遍历过为true,没有遍历过为false

    //初始化图,只有顶点没有边
    MGraph CreatGraph(int VertexNum)
    {
    Vertex V, M;
    MGraph Graph = (MGraph)malloc(sizeof(struct GNode));
    Graph->Nv = VertexNum;
    Graph->Ne = 0;

    for (V = 0; V < VertexNum; V++)
    {
    for (M = 0; M < VertexNum; M++)
    {
    Graph->G[V][M] = INFINITY;
    }
    }
    return Graph;
    }

    //把边插入到图中,无向图
    void InsertEdge(MGraph Graph, Edge E)
    {
    Graph->G[E->V1][E->V2] = E->Weight;
    Graph->G[E->V2][E->V1] = E->Weight;
    }

    //根据输入的数据创建图
    MGraph BuildGraph()
    {
    MGraph Graph;
    Edge E;
    int Nv, i;

    cin >> Nv;
    Graph = CreatGraph(Nv);
    cin >> Graph->Ne;
    if (Graph->Ne)
    {
    E = (Edge)malloc(sizeof(struct ENode));
    for (i = 0; i < Graph->Ne; i++)
    {
    cin >> E->V1 >> E->V2 >> E->Weight;
    InsertEdge(Graph, E);
    }
    free(E);
    }
    return Graph;
    }

    //判断两个顶点之间是否有边
    bool IsEdge(MGraph Graph, Vertex V1, Vertex V2)
    {
    return Graph->G[V1][V2] != INFINITY;
    }

    //将所有顶点初始化为都没有遍历过
    void IniVisited()
    {
    for (int i = 0; i < MaxVertexNum; i++)
    {
    Visited[i] = false;
    }
    }

    //输出顶点
    void Visit(Vertex V)
    {
    cout << V << " ";
    }

    //图连通时的DFS和BFS
    //BFS(Breadth First Search)广度优先 初始顶点S
    void BFS(MGraph Graph, Vertex S, void(*Visit)(Vertex))
    {
    queue<Vertex> Q;
    Vertex V, W;
    Q.push(S);
    Visited[S] = true;

    while (!Q.empty())
    {
    V = Q.front();
    Visit(V);
    Q.pop();
    for (W = 0; W < Graph->Nv; W++)
    {
    if (!Visited[W] && IsEdge(Graph, V, W))
    {
    Q.push(W);
    Visited[W] = true;
    }
    }
    }
    }

    //DFS(Depth First Search) 深度优先
    void DFS(MGraph Graph, Vertex S, void(*Visit)(Vertex))
    {
    Visit(S);
    Visited[S] = true;
    for (Vertex W = 0; W < Graph->Nv; W++)
    {
    if (!Visited[W] && IsEdge(Graph, S, W))
    {
    DFS(Graph, W, Visit);
    }
    }
    return;
    }

    //图不连通时的DFS和BFS
    void BFSListComponents(MGraph Graph, void(*Visit)(Vertex))
    {
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    if (!Visited[V])
    {
    BFS(Graph, V, Visit);
    cout << endl;
    }
    }
    }
    void DFSListComponents(MGraph Graph, void(*Visit)(Vertex))
    {
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    if (!Visited[V])
    {
    DFS(Graph, V, Visit);
    cout << endl;
    }
    }
    }
    int main()
    {
    MGraph Graph = BuildGraph();
    IniVisited();
    BFSListComponents(Graph, Visit);
    IniVisited();
    DFSListComponents(Graph, Visit);
    free(Graph); //释放动态数组开辟的内存
    system("pause");
    return 0;
    }

    2.图的邻接表表示

    #include <iostream>
    #include <queue>
    using namespace std;

    typedef int Vertex;
    typedef int WeightType;
    typedef char DataType;
    const int INFINITY = 65535;
    const int MaxVertexNum = 100;
    bool Visited[MaxVertexNum] = {false};

    //定义边
    typedef struct ENode* PtrToENode;
    struct ENode
    {
    Vertex V1, V2;
    WeightType Weight;
    };
    typedef PtrToENode Edge;

    //定义邻接顶点结点
    typedef struct AdjVNode* PtrToAdjVNode;
    struct AdjVNode
    {
    Vertex AdjV; //邻接点下标
    WeightType Weight;
    PtrToAdjVNode Next;
    };

    //定义邻接表表头的结点
    typedef struct VNode
    {
    PtrToAdjVNode FisrtEdge;
    DataType data;
    }AdjList[MaxVertexNum];

    //图的定义
    typedef struct GNode* PtrToGNode;
    struct GNode
    {
    int Nv; //顶点数量
    int Ne; //边的数量
    AdjList G; //邻接表
    };
    typedef PtrToGNode LGraph;

    //初始化图,只有顶点没有边
    LGraph CreateLGraph(int VertexNum)
    {
    LGraph Graph = (LGraph)malloc(sizeof(struct GNode));
    Graph->Nv = VertexNum;
    Graph->Ne = 0;
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    Graph->G[V].FisrtEdge = NULL;
    }
    return Graph;
    }

    //在图中插入一条边,无向图
    void InsertEdge(LGraph Graph, Edge E)
    {
    PtrToAdjVNode NewNode;

    //<V1, V2>
    NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
    NewNode->AdjV = E->V2;
    NewNode->Weight = E->Weight;
    NewNode->Next = Graph->G[E->V1].FisrtEdge;
    Graph->G[E->V1].FisrtEdge = NewNode;

    //<V2, V1>
    NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
    NewNode->AdjV = E->V1;
    NewNode->Weight = E->Weight;
    NewNode->Next = Graph->G[E->V2].FisrtEdge;
    Graph->G[E->V2].FisrtEdge = NewNode;
    }

    //输入数据并建立图
    LGraph BuildLGraph()
    {
    int Nv;
    LGraph Graph;
    Edge E = (Edge)malloc(sizeof(struct ENode));

    cin >> Nv;
    Graph = CreateLGraph(Nv);
    cin >> Graph->Ne;
    for (int i = 0; i < Graph->Ne; i++)
    {
    cin >> E->V1 >> E->V2 >> E->Weight;
    InsertEdge(Graph, E);
    }
    return Graph;
    }

    //图的遍历,广度优先和深度优先
    void IniVisited()
    {
    for (int i = 0; i < MaxVertexNum; i++)
    {
    Visited[i] = false;
    }
    }
    void Visit(Vertex V)
    {
    cout << V << " ";
    }
    //图整个连通时的BFS和DFS
    void BFS(LGraph Graph, Vertex S, void(*Visit)(Vertex))
    {
    queue<Vertex> Q;
    Vertex V;

    Q.push(S);
    Visited[S] = true;
    while (!Q.empty())
    {
    V = Q.front();
    Visit(V);
    Q.pop();
    PtrToAdjVNode P = Graph->G[V].FisrtEdge;
    while(P)
    {
    if (!Visited[P->AdjV])
    {
    Q.push(P->AdjV);
    Visited[P->AdjV] = true;
    }
    P = P->Next;
    }
    }
    }
    //递归
    void DFS(LGraph Graph, Vertex S, void(*Visit)(Vertex))
    {
    Visit(S);
    Visited[S] = true;
    PtrToAdjVNode P = Graph->G[S].FisrtEdge;
    while (P)
    {
    if (!Visited[P->AdjV])
    {
    DFS(Graph, P->AdjV, Visit);
    }
    P = P->Next;
    }
    }

    //图不连通时的遍历
    void BFSListComponent(LGraph Graph, void(*Visit)(Vertex))
    {
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    if (!Visited[V])
    {
    BFS(Graph, V, Visit);
    cout << endl;
    }
    }
    }
    void DFSListComponent(LGraph Graph, void(*Visit)(Vertex))
    {
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    if (!Visited[V])
    {
    DFS(Graph, V, Visit);
    cout << endl;
    }
    }
    }
    //释放动态分配的内存空间
    void DestoryGraph(LGraph Graph)
    {
    PtrToAdjVNode P;
    PtrToAdjVNode Temp;
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    P = Graph->G[V].FisrtEdge;
    while (P)
    {
    Temp = P->Next;
    free(P);
    P = Temp;
    }
    }
    }

    int main()
    {
    LGraph Graph = BuildLGraph();
    IniVisited();
    BFSListComponent(Graph, Visit);
    IniVisited();
    DFSListComponent(Graph, Visit);
    DestoryGraph(Graph);
    free(Graph);
    system("pause");
    return 0;
    }

    3. 无权图的单元最短路径算法

    #include <iostream>
    #include <queue>
    #include <stack>
    using namespace std;
    /*
    无权图的单元最短路径算法, 图是采用邻接表存储的,算法的时间复杂度为O(V + E)(结点+边)
    */
    typedef int Vertex;
    const int MaxVertexNum = 100;
    int dist[MaxVertexNum + 1];
    Vertex path[MaxVertexNum + 1];

    typedef struct AdjVNode* ptrToAdjVNode;
    struct AdjVNode
    {
    Vertex V;
    ptrToAdjVNode Next;
    };

    typedef struct VNode
    {
    ptrToAdjVNode FistAdjVNode;
    }AdjList[MaxVertexNum + 1];

    typedef struct GNode* ptrToGNode;
    struct GNode
    {
    int Nv;
    int Ne;
    AdjList G;
    };
    typedef ptrToGNode LGraph;

    //初始化图,只有结点,没有边
    LGraph CreatLGraph(int Nv)
    {
    LGraph Graph = (LGraph)malloc(sizeof(struct GNode));
    Graph->Nv = Nv;
    Graph->Ne = 0;
    for (int i = 0; i < MaxVertexNum; i++)
    {
    Graph->G[i].FistAdjVNode = NULL;
    }
    return Graph;
    }
    void InsertNode(LGraph Graph, Vertex L, Vertex R)
    {
    ptrToAdjVNode Temp = (ptrToAdjVNode)malloc(sizeof(struct AdjVNode));
    Temp->V = R;
    Temp->Next = Graph->G[L].FistAdjVNode;
    Graph->G[L].FistAdjVNode = Temp;
    }
    LGraph BuildGraph()
    {
    int N; //图的结点的数量
    Vertex L, R;
    cin >> N;
    LGraph Graph = CreatLGraph(N);
    cin >> Graph->Ne;
    for (int i = 0; i < Graph->Ne; i++)
    {
    cin >> L >> R; //L和R是图中边的两端的顶点
    InsertNode(Graph, L, R);
    }
    return Graph;
    }
    void FreeGraph(LGraph &Graph)
    {
    for (int i = 1; i <= Graph->Nv; i++)
    {
    ptrToAdjVNode Temp = Graph->G[i].FistAdjVNode;
    ptrToAdjVNode pNext;
    while (Temp)
    {
    pNext = Temp->Next;
    free(Temp);
    Temp = pNext;
    }
    }
    free(Graph);
    Graph = NULL;
    }
    void InitDistAndPath()
    {
    for (int i = 0; i <= MaxVertexNum; i++)
    {
    dist[i] = -1;
    path[i] = -1;
    }
    }
    void Unweight(LGraph Graph, int dist[], int path[], Vertex S)
    {
    queue<Vertex> Q;
    Vertex V;
    Vertex W;
    ptrToAdjVNode Temp;
    dist[S] = 0;
    Q.push(S);
    while (!Q.empty())
    {
    V = Q.front();
    Q.pop();
    Temp = Graph->G[V].FistAdjVNode;
    while (Temp)
    {
    W = Temp->V;
    if(dist[W] == -1)
    {
    dist[W] = dist[V] + 1;
    path[W] = V;
    Q.push(W);
    }
    Temp = Temp->Next;
    }
    }
    }
    void MinPath(Vertex V)
    {
    cout << "3到" << V << "的最短路径长度为:" << dist[V] << endl;
    stack<Vertex> s;
    Vertex W;
    s.push(V);
    W = path[V];
    while (W != 3)
    {
    s.push(W);
    W = path[W];
    }
    cout << "最短路径为: " << 3 << "->";
    while (!s.empty())
    {
    W = s.top();
    s.pop();
    if (W == V)
    {
    cout << W;
    }
    else
    {
    cout << W << "->";
    }
    }
    cout << endl;
    }
    int main()
    {
    LGraph Graph = BuildGraph();
    InitDistAndPath();
    Unweight(Graph, dist, path, 3);
    MinPath(7);
    free(Graph);
    system("pause");
    return 0;
    }

    4.有权图的单元最短路径算法

    #include <iostream>
    #include <stack>
    using namespace std;
    /*
    有权图的最短路径算法
    时间复杂度:若直接扫描所有未收录顶点 T= O(V^2 + E) 若将dist存在最小堆中 T = O(ElogV)
    用矩阵存储图
    DijKstra算法计算有权图的最短路径
    */
    typedef int Vertex;
    typedef int WeightType;
    const int MaxVertexNum = 100;
    const int INFINITY = 65535;

    //定义边
    typedef struct ENode* ptrToENode;
    struct ENode
    {
    Vertex V1, V2;
    WeightType weight;
    };
    typedef ptrToENode Edge;

    //定义图结点
    typedef struct GNode* ptrToGNode;
    struct GNode
    {
    int Nv;
    int Ne;
    WeightType G[MaxVertexNum][MaxVertexNum];
    };
    typedef ptrToGNode MGraph;

    /* 邻接矩阵存储 --有权图的单源最短路径算法*/
    Vertex FindMinDist(MGraph Graph, int dist[], int collected[])
    {
    /*将所有顶点遍历,返回未被收录顶点中dist最小者*/
    Vertex MinV;
    int Mindist = INFINITY;
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    if (!collected[V] && dist[V] < Mindist)
    {
    Mindist = dist[V];
    MinV = V;
    }
    }
    if (Mindist == INFINITY)
    {
    return -1;
    }
    else
    {
    return MinV;
    }
    }

    bool DijKstra(MGraph Graph, int dist[], int path[], Vertex S)
    {
    Vertex V;
    int collected[MaxVertexNum];
    for (Vertex W = 0; W < Graph->Nv; W++)
    {
    dist[W] = Graph->G[S][W]; //初始化所有的dist
    if (dist[W] < INFINITY) //初始化所有的path
    {
    path[W] = S;
    }
    else
    {
    path[W] = -1;
    }
    collected[W] = false; //初始化collected
    }
    while (1)
    {
    V = FindMinDist(Graph, dist, collected); //未收录的顶点中的dist的最小的
    if (V == -1)
    {
    break;
    }
    collected[V] = true;
    for (Vertex W = 0; W < Graph->Nv; W ++)
    {
    if (Graph->G[V][W] < INFINITY && collected[W] == false)
    {
    if (Graph->G[V][W] < 0)
    {
    return false;
    }
    if (dist[V] + Graph->G[V][W] < dist[W])
    {
    dist[W] = dist[V] + Graph->G[V][W];
    path[W] = V;
    }
    }
    }
    }
    return true;
    }
    void ShowPath(MGraph Graph, int path[], Vertex S, Vertex V) //从S到V的最短路径
    {
    if (S == V)
    {
    return;
    }
    stack<Vertex> s;
    Vertex tempV = V;
    s.push(tempV);
    while (path[tempV] != S)
    {
    tempV = path[tempV];
    s.push(tempV);
    }
    s.push(S);
    while (!s.empty())
    {
    tempV = s.top();
    s.pop();
    cout << tempV << " ";
    }
    }
    int main()
    {
    //输入图
    int Nv;
    int dist[MaxVertexNum];
    Vertex path[MaxVertexNum];
    Vertex V1, V2;
    WeightType Weight;
    MGraph Graph = (MGraph)malloc(sizeof(struct GNode));
    cin >> Nv;
    Graph->Nv = Nv;
    cin >> Graph->Ne;
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    for (Vertex W = 0; W < Graph->Nv; W++)
    {
    Graph->G[V][W] = INFINITY;
    }
    }
    for (int i = 0; i < Graph->Ne; i++)
    {
    cin >> V1 >> V2 >> Weight;
    Graph->G[V1][V2] = Weight;
    }
    if (DijKstra(Graph, dist, path, 0))
    {
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    ShowPath(Graph, path, 0, V);
    if (V == 0)
    {
    continue;
    }
    cout << dist[V] << endl;
    }

    }
    else
    {
    cout << "最短路径寻找失败!!!" << endl;
    }

    system("pause");
    return 0;
    }

    5. 多源最短路径算法

    #include <iostream>
    #include <stack>
    using namespace std;
    /*
    无向有权图的最短路径算法
    时间复杂度:若直接扫描所有未收录顶点 T= O(V^2 + E) 若将dist存在最小堆中 T = O(ElogV)
    用矩阵存储图
    DijKstra算法计算有权图的最短路径
    */
    typedef int Vertex;
    typedef int WeightType;
    const int MaxVertexNum = 100;
    const int INFINITY = 65535;

    //定义边
    typedef struct ENode* ptrToENode;
    struct ENode
    {
    Vertex V1, V2;
    WeightType weight;
    };
    typedef ptrToENode Edge;

    //定义图结点
    typedef struct GNode* ptrToGNode;
    struct GNode
    {
    int Nv;
    int Ne;
    WeightType G[MaxVertexNum][MaxVertexNum];
    };
    typedef ptrToGNode MGraph;

    bool Floyd( MGraph Graph, WeightType D[][MaxVertexNum], Vertex path[][MaxVertexNum] )
    {
    /*
    D[MaxVertexNum][MaxVertexNum]存储的是从i到j的距离
    path[MaxVertexNum][MaxVertexNum]存储的是i到j之间经过的顶点k
    */

    Vertex i, j, k;
    /* 初始化 */
    for ( i=0; i<Graph->Nv; i++ )
    for( j=0; j<Graph->Nv; j++ )
    {
    D[i][j] = Graph->G[i][j];
    path[i][j] = -1;
    }

    for( k=0; k<Graph->Nv; k++ )
    for( i=0; i<Graph->Nv; i++ )
    for( j=0; j<Graph->Nv; j++ )
    if( D[i][k] + D[k][j] < D[i][j] )
    {
    D[i][j] = D[i][k] + D[k][j];
    if ( i == j && D[i][j] < 0 ) /* 若发现负值圈 */
    return false; /* 不能正确解决,返回错误标记 */
    path[i][j] = k;
    }

    return true; /* 算法执行完毕,返回正确标记 */
    }


    int main()
    {
    //输入图
    int Nv;
    int D[MaxVertexNum][MaxVertexNum];
    Vertex path[MaxVertexNum][MaxVertexNum];
    Vertex V1, V2;
    WeightType Weight;
    MGraph Graph = (MGraph)malloc(sizeof(struct GNode));
    cin >> Nv;
    Graph->Nv = Nv;
    cin >> Graph->Ne;
    for (Vertex V = 0; V < Graph->Nv; V++)
    {
    for (Vertex W = 0; W < Graph->Nv; W++)
    {
    if (V == W)
    {
    Graph->G[V][W] = 0;
    }
    else
    {
    Graph->G[V][W] = INFINITY;
    }
    }
    }
    for (int i = 0; i < Graph->Ne; i++)
    {
    cin >> V1 >> V2 >> Weight;
    Graph->G[V1][V2] = Weight;
    Graph->G[V2][V1] = Weight;
    }
    Floyd(Graph, D, path);
    system("pause");
    return 0;
    }

  • 相关阅读:
    golang基础之第一个go程序
    golang基础之工程结构
    golang基础之初识
    Prometheus神器之监控K8s集群
    Kubernetes使用GlusterFS实现数据持久化
    Go使用Makefile构建
    快排的2种分区图解
    密钥交换之DH算法
    go mod使用
    socket常见选项之SO_REUSEADDR,SO_REUSEPORT
  • 原文地址:https://www.cnblogs.com/mengjuanjuan/p/9979743.html
Copyright © 2011-2022 走看看