zoukankan      html  css  js  c++  java
  • c++ 由无向图构造邻接表,实现深度优先遍历、广度优先遍历。

    /*
    首先,根据用户输入的顶点总数和边数,构造无向图,然后以用户输入的顶点
    为起始点,进行深度优先、广度优先搜索遍历,并输出遍历的结果。
    */
    #include <stdlib.h>
    #include <iostream>
    #define MVNum 100         //最大的顶点数
    using namespace std;
    
    /*——————图的邻接表存储表示——————*/
    //边的结点表-在顶点表后面
    typedef struct ArcNode
    {
        int adjvex;                 //邻接点域-该边所指向顶点的位置下标
        struct ArcNode* nextarc; //链域-邻接的下一顶点位置
        //otherInfo info;        //用来纪录权值
    }ArcNode;
    //单链表表头-结构体(类似于头结点)
    typedef struct VNode
    {
        char data;                //顶点的信息值
        ArcNode* firstarc;        //指向第一条依附该顶点的下一结点-指向类型为边ArcNode
    }VNode, AdjList[MVNum];        //AdjList邻接表类型
    //图ALGraph
    typedef struct
    {
        AdjList vertices;        //定义一个邻接表类型,vertices最多有MVNum个
        int vexnum;                //顶点数
        int arcnum;                //边数
    }ALGraph;
    //链队列结构体
    typedef struct QNode
    {
        int data;
        struct QNode* next;
    }QNode,*QueuePtr;
    //链队头指针结构体
    typedef struct
    {
        QueuePtr front;  //队头
        QueuePtr rear;      //队尾
    }LinkQueue;
    //寻找v1,v2的下标
    int LocateVex(ALGraph& G, char NodeInfo)
    {
        int flag = 0;
        //匹配NodeInfo
        for (int i = 0; i < G.vexnum; i++)
        {
            if (G.vertices[i].data == NodeInfo)
            {
                flag = i;
                return i;
                break;
            }
        }
        if (flag)
            return flag;
        else
            exit(errno);
    }
    //邻接表生成无边图
    void CreateUDG(ALGraph& G)
    {
        //输入数据
        cout << "请输入相应的顶点数与边数(以空格间隔):" << endl;
        cin >> G.vexnum >> G.arcnum;
    
        //初始化顶点信息
        cout << "请输入" << G.vexnum << "个顶点的信息(以空格间隔):" << endl;
        for (int i = 0; i < G.vexnum; i++)
        {
            cin >> G.vertices[i].data;
            G.vertices[i].firstarc = NULL;    //各顶点结点的指针域置空
        }
    
        //初始化边的连接信息
        for (int i = 0; i < G.arcnum; i++)
        {
            char v1, v2;                        //v1,v2为一条边连接的两个顶点
            cout << "请输入第" << i << "条边的两顶点信息(以空格间隔):";
            cin >> v1 >> v2;
    
            //求v1,v2在vertices的下标
            int idx_v1 = LocateVex(G, v1);
            int idx_v2 = LocateVex(G, v2);
    
            //调用边的结点表,生成以v1为头结点的单链表构成的邻接表
            ArcNode* p1 = new ArcNode;            //生成第一个边连接的结点(后面的那一个)
            p1->adjvex = idx_v2;                //存入结点的下标
            //关联头结点,用头插法,插入结点
            p1->nextarc = G.vertices[idx_v1].firstarc;
            G.vertices[idx_v1].firstarc = p1;
    
            //调用边的结点表,生成以v2为头结点的单链表构成的邻接表
            ArcNode* p2 = new ArcNode;            //生成第一个边连接的结点(后面的那一个)
            p2->adjvex = idx_v1;                //存入结点的下标
            //关联头结点,用头插法,插入结点
            p2->nextarc = G.vertices[idx_v2].firstarc;
            G.vertices[idx_v2].firstarc = p2;
        }
    }
    //邻接表的遍历
    void TraverseAdjList(ALGraph& G)
    {
        for (int i = 0; i < G.vexnum; i++)
        {
            cout << "" << G.vertices[i].data << "】→";
            //临时头指针用于遍历
            ArcNode* temp = G.vertices[i].firstarc;
            //当temp不为空,输出链表
    
            while (temp)
            {
                //输出顶点序号
                cout<<"["<<temp->adjvex<<"]";
                temp=temp->nextarc;
                if (temp)
                    cout << "";
            }
            putchar(10);
        }
    }
    //深度优先遍历
    int visisted_D[MVNum] = { 0 };    //辅助数组
    void DFS_AL(ALGraph& G, int v)
    {
        //从v顶点开始访问
        cout <<"("<< G.vertices[v].data <<")";
        //访问过后置1
        visisted_D[v] = 1;
        //临时结点用于遍历,指向头结点后一结点
        ArcNode *temp = G.vertices[v].firstarc;
    
        //循环遍历
        while (temp)
        {
            int w = temp->adjvex;
            //如果辅助数组visisted[w] == 0递归调用DFS_AL
            if (visisted_D[w] == 0)
            {
                DFS_AL(G, w);
            }
            //temp指向下一结点
            temp = temp->nextarc;
        }
    }
    //广度优先遍历
    int visisted_B[MVNum] = { 0 };    //辅助数组
    //队列初始化
    void InitQuenue(LinkQueue& Q)
    {
        Q.rear = new QNode;
        Q.front = Q.rear;
        Q.front->next = NULL;
    }
    //入队-尾插法
    void EnQuenue(LinkQueue& Q,int v)
    {
        QNode* cur = new QNode;
        cur->data = v;
        cur->next = NULL;
        Q.rear->next = cur;
        Q.rear = cur;
    }
    //出队-返回队头int u
    void DeQuenue(LinkQueue& Q, int &u)
    {
        QNode* temp = Q.front->next;
        Q.front->next = temp->next;
        //队头u更新
        u = temp->data;
        //如果最后一个被删,队尾指向队头
        if (Q.rear == temp)
        {
            Q.rear = Q.front;
        }
        delete temp;
    }
    //返回u的第一个邻结点
    int FirstAdjvex(ALGraph& G, int u)
    {
        int w = G.vertices[u].firstarc->adjvex;
        return w;
    }
    //返回u的下一个邻结点
    int NextAdjVex(ALGraph& G, int u, int w)
    {
        //临时结点temp指向头结点的第一个邻结点,w此时为第一结点序号
        ArcNode *temp = G.vertices[u].firstarc;
        while (temp->adjvex != w)
        {
            temp = temp->nextarc;
        }
        //若w结点的下一结点不为空,返回结点序号w的下一结点序号
        if (temp->nextarc)
            return temp->nextarc->adjvex;
        //否则返回-1,使其退出循环
        else 
            return -1;
        delete temp;
    }
    void BFS_AL(ALGraph& G, int v)
    {
        //从v顶点开始访问
        cout << "(" << G.vertices[v].data << ")";
        //访问过后置1
        visisted_B[v] = 1;
        //创建队列
        LinkQueue Q;
        InitQuenue(Q);
        EnQuenue(Q,v);
        int u = v;        //用于找邻接点
        //队列非空出队
        while (Q.rear != Q.front)
        {
            //出队,并把队头置为u
            DeQuenue(Q, u);
            for (int w = FirstAdjvex(G, u); w >= 0; w = NextAdjVex(G, u, w))
            {
                //若结点序号w未访问则进行访问
                if (!visisted_B[w])
                {
                    cout << "(" << G.vertices[w].data << ")";        //输出数据
                    visisted_B[w] = 1;                //打上访问标记
                    EnQuenue(Q, w);                    //将结点w入队
                }
            }//进行下一次w的邻结点查找
        }
    }
    void main()
    {
        ALGraph G;
        //邻接表生成无边图
    
        CreateUDG(G);
        //遍历邻接表
        TraverseAdjList(G);
        //深度优先遍历
        cout << "请问从第几个顶点开始深度优先遍历:";
        int v;
        cin >> v;
        cout << "DFS:";
        DFS_AL(G, v-1);
        putchar(10);
        //广度优先遍历
        cout << "请问从第几个顶点开始广度优先遍历:";
        cin >> v;
        cout << "BFS:";
        BFS_AL(G, v - 1);
        putchar(10);
        system("pause");
    }

    //深度优先遍历由递归实现。也可用栈来实现(与BFS队列操作类似)。

    //广度优先遍历由队列实现。需要先让开始进行遍历的顶点入队,再进行出队,但是出队需保存出队的结点序号值作为表头,用于遍历该层,并同时将辅助数组visisted_B[v]置为1,以表示已经访问,然后根据邻接表结构进行类似于树的层次遍历操作,每个结点访问过后都要将visisted_B[v]置为1,当其中一层遍历完过后,先进的第一个结点出队,并更新出队值,同时开始遍历以该结点序号为头结点的单链表,直到每层遍历完后结束。
    //在广度优先遍历过程中,进行出队操作时,一开始用形参int u来进行接收,导致队头值u(表头)无法更新,造成只能遍历初始顶点的那一条单链表,后改为形参 int &u解决队头值更新问题。

  • 相关阅读:
    (三)数据预处理过程简介
    (二)数据挖掘需要哪些技术
    (一) 什么是数据挖掘?
    怎样提问呢?
    什么是自我意识
    高效能人士的七个习惯
    “U”型读书法
    CMDB学习之一
    层级选择器
    css选择器
  • 原文地址:https://www.cnblogs.com/huxiaobai/p/10910689.html
Copyright © 2011-2022 走看看