图的存储与遍历

  图的存储与遍历

一.实验目的

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

二.实验要求与内容

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

算法参见课本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;

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容

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