图的存储与遍历

  图的存储与遍历

一.实验目的

掌握图的存储结构以及图的深度优先搜索遍历、最小生成树算法。

二.实验要求与内容

自构造一无向图,采用邻接矩阵或者邻接表存储,完成图的深度优先搜索遍历以及广度优先搜索遍历算法的实现。

算法参见课本P214-225

三.实验步骤

1.数据结构

图的储存与遍历的邻接矩阵方式,在图的深度优先搜索中采用的是栈的方式进行结点的储存,在图的广度优先搜索中用的是队列方式进行储存。队列和栈用的都是stl中所定义好的,需要头文件#include<queue>和#include<stack>

在最小生成树中采用合并集的思想,定义一个结构体来储存边的开始点,结束点,以及权值大小。

2.算法设计

在深度优先搜索中用栈的方式进行储存以访问过的结点,找到一个结点A后进行访问标记并压入栈,访问与它相连的另一个结点B标记并压入栈,再访问结点B相连的任一结点标记并压入栈,重复,,直至没有结点N没有可供访问的结点。则从栈中弹出头结点,寻找结点N-1的另外可供访问的结点,如果没有则再弹出头结点直至栈为空。

在广度优先搜索中用队列的方式进行储存访问过的结点,找到一个结点A后进行访问标记并进入队列,访问与它相连的所有结点标记并进入队列,当与它相连的所有结点都进入队列后头结点出队,访问队列头结点的所有可供访问的结点并进入队列,,重复,直至队列为空

在这两种访问方式中设置一个visited用来标记该结点是否被访问过,如果未被访问过visited[i]=0否则visited[i]=1;

合并集求最小生成树,将每一个结点都看作成一棵树,将权值进行排序,求最小权值的start和end是否在一棵树中,如果不在一棵树中则将两个结点并为一棵树,重复找最小权值和合并树这两个步骤直至所有结点都在一棵树上为止。

详细过程解析看代码注释

3.程序

void DFS1(int v)//深度优先搜索

{

    cout<<b[v]<<" ";//访问第v个结点

    visited[v]=1;//设置该结点已经被访问过;

    s.push(v);

    int count=1;

    while(!(s.empty()&& count==n))

    {

        if(s.empty() && count!=n)//需要判断栈空但是结点并没有遍历完的情况

        {

            for(int i=1;i<=n;i++)

            {

                if(visited[i]==0)//如果该邻接结点都还没有被访问过

                {

                    cout<<b[i]<<" ";

                    visited[i]=1;

                    s.push(i);

                    count++;

                    break;

                }

            }

        }

        int w=node1(s.top());//求该结点的邻接结点

        while(w!=-1)//如果该结点存在邻接结点

        {

            if(!visited[w])

            {

                cout<<b[w]<<" ";

                s.push(w);

                visited[w]=1;

                count++;

            }

            w=node1(w);

        }

        s.pop();

    }

}

void DFS(int v)//广度优先搜索

{

    cout<<b[v]<<" ";//访问第v个结点

    visited[v]=1;//设置该结点已经被访问过;

    q.push(v);

    int count=1;

    while(!(q.empty()&&count==n))

    {

    if(q.empty() && count!=n)//需要判断队列空但是结点并没有遍历完的情况

    {

        for(int i=1;i<=n;i++)

        {

            if(visited[i]==0)

            {

                cout<<b[i]<<" ";

                visited[i]=1;

                q.push(i);

                count++;

                break;

            }

        }

    }

    int s=q.front();

    q.pop();

    int w=node1(s);//求该结点的邻接结点

    while(w!=-1)//如果该结点存在邻接结点

    {

    if(!visited[w])//如果该邻接结点都还没有被访问过

    {

        cout<<b[w]<<" ";

        q.push(w);

        visited[w]=1;

        count++;

    }

        w=node1(s);

    }

}

}

int find(int x)

{

    if(x!=pre[x])

        pre[x]=find(pre[x]);

    return pre[x];

}

void megre(int x,int y,int n)//查并集合并函数,n 用来记录最短路中应该加入哪个点

{

    int fx=find(x);

    int fy=find(y);

    if(fx!=fy)

    {

        pre[fx]=fy;

        sum=edge[n].power+sum;

    }

}

4.程序调试

测试数据、程序运行结果截图


四.结果与体会

在使用栈和队列的时候可以用stl中的栈的队列,,无需自己定义函数,但需要加头文件#include<queue>和#include<stack>

在求最小权值的时候可以用查并集的方法。

在广度优先搜索和深度优先搜索的时候要特别考虑如果栈或者队列为空时但是结点却没有遍历完。即输入的图并不是一棵树,可能是森林的情况下。

五.源程序

另附

#include<iostream>

#include<queue>

#include<stack>

using namespace std;

#define M 100

int a[M][M];//邻接矩阵

int b[M];//顶点数据

int visited[M];

queue<int> q;

stack<int>s;

int pre[M];

int sum=0;

struct node

{

    int start,end,power;

}edge[20];

int m,n;//无向图的顶点数和边数

int node1(int v)

{

    for(int i=1;i<=n;i++)

    {

        if(a[v][i]!=0 && visited[i]==0)

            return i;

    }

    return -1;//如果该结点的所有相连结点都被访问过

}

int cmp(node a,node b)//按权值排序

{

    return a.power<b.power;

}

int find(int x)

{

    if(x!=pre[x])

        pre[x]=find(pre[x]);

    return pre[x];

}

void megre(int x,int y,int n)//查并集合并函数,n 用来记录最短路中应该加入哪个点

{

    int fx=find(x);

    int fy=find(y);

    if(fx!=fy)

    {

        pre[fx]=fy;

        sum=edge[n].power+sum;

    }

}

void DFS1(int v)//深度优先搜索

{

    cout<<b[v]<<" ";//访问第v个结点

    visited[v]=1;//设置该结点已经被访问过;

    s.push(v);

    int count=1;

    while(!(s.empty()&& count==n))

    {

        if(s.empty() && count!=n)//需要判断栈空但是结点并没有遍历完的情况

        {

            for(int i=1;i<=n;i++)

            {

                if(visited[i]==0)//如果该邻接结点都还没有被访问过

                {

                    cout<<b[i]<<" ";

                    visited[i]=1;

                    s.push(i);

                    count++;

                    break;

                }

            }

        }

        int w=node1(s.top());//求该结点的邻接结点

        while(w!=-1)//如果该结点存在邻接结点

        {

            if(!visited[w])

            {

                cout<<b[w]<<" ";

                s.push(w);

                visited[w]=1;

                count++;

            }

            w=node1(w);

        }

        s.pop();

    }

}

void DFS(int v)//广度优先搜索

{

    cout<<b[v]<<" ";//访问第v个结点

    visited[v]=1;//设置该结点已经被访问过;

    q.push(v);

    int count=1;

    while(!(q.empty()&&count==n))

    {

    if(q.empty() && count!=n)//需要判断队列空但是结点并没有遍历完的情况

    {

        for(int i=1;i<=n;i++)

        {

            if(visited[i]==0)

            {

                cout<<b[i]<<" ";

                visited[i]=1;

                q.push(i);

                count++;

                break;

            }

        }

    }

    int s=q.front();

    q.pop();

    int w=node1(s);//求该结点的邻接结点

    while(w!=-1)//如果该结点存在邻接结点

    {

    if(!visited[w])//如果该邻接结点都还没有被访问过

    {

        cout<<b[w]<<" ";

        q.push(w);

        visited[w]=1;

        count++;

    }

        w=node1(s);

    }

}

}

int main()

{

    //构造无向图,邻接矩形

    cout<<"请输入无向图的顶点数和边数";

    cin>>n>>m;

    for(int i=1;i<=n;i++)//初始化邻接矩阵

        for(int j=1;j<=n;j++)

            a[i][j]=0;

    cout<<"请输入顶点的顺序";

    for(int i=1;i<=n;i++)

    {

        cin>>b[i];

    }

    cout<<"依次输入每一条边两个顶点的序列号和权值"<<endl;

    for(int i=1;i<=m;i++)

    {

        int x,y,weight;

        scanf("%d %d %d",&x,&y,&weight);

        edge[i].start=x;

        edge[i].end=y;

        edge[i].power=weight;

        a[x][y]=weight;

        a[y][x]=weight;

    }

    //图的广度优先搜索

   cout<<"广度优先遍历的结点顺序为:"<<endl;

    DFS(1);

    for(int i=1;i<=n;i++)

        visited[i]=0;

    //图的深度优先搜索

    cout<<endl;

    cout<<"深度优先遍历的结点顺序为:"<<endl;

    DFS1(1);

    cout<<endl;

    //求最小权值

    for(int i=1;i<=m;i++)

        pre[i]=i;

   sort(edge+1,edge+m+1,cmp);

    for(int i=1;i<=m;i++)

        megre(edge[i].start,edge[i].end,i);

    cout<<"最小权值为:";

    cout<<sum<<endl;

   return 0;

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 图的定义与术语 1、图按照有无方向分为无向图和有向图。无向图由顶点和边构成,有向图由顶点和弧构成。弧有弧尾和弧头之...
    unravelW阅读 435评论 0 0
  • 1.把二元查找树转变成排序的双向链表 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求不...
    曲终人散Li阅读 3,371评论 0 19
  • -DFS(Depth First Search):深度优先搜索 访问完一个顶点的所有邻接点之后,会按原路返回,对应...
    Spicy_Crayfish阅读 2,860评论 1 0
  • 1)这本书为什么值得看: Python语言描述,如果学的Python用这本书学数据结构更合适 2016年出版,内容...
    孙怀阔阅读 12,624评论 0 15
  • 2018-7-21 姓名:张文清 公司:宁波大发化纤有限公司20天】 【知~学习】 《六项精进》大纲背诵1遍,总(...
    z张文清阅读 82评论 0 0