hnu 数据结构 实验六

实验6 图的应用

分别提交两个附件:
1:设计文档(提交PDF格式的文件,文件名要规范,参看规范)。
2:实验源码包。(文件名也要规范,可以参考报告文件的格式)

实验6 通信网络

一、问题分析
分析并确定要处理的对象(数据)是什么
输入的数据分别为部门的个数和部门之间关系的数量,此外还有存在关系的部门的编号。考虑到数据之间多对多的关系,考虑采用图的数据结构储存,故需要处理的数据转化为图的结点和各个结点之间的权值。

分析并确定要实现的功能是什么
根据题目意思,不同的部门之间存在单向消息传递的关系,而存在传递关系的部门知道彼此的存在,不能互传消息的部门不知道彼此存在,我们需要统计知道所有部门的存在的部门个数,实则需要我们统计,这个图中的所有节点,有多少个和其他所有节点有关系(其他节点可以或直接或间接地到达或者被该节点传达消息)。

分析并确定处理后的结果如何显示
根据题目意思,直接输出一个知道所有部门的部门数量即可。

二、数据结构和算法设计
抽象数据类型设计
考虑到数据之间多对多的关系,可以采用图的数据结构储存。该图可以通过邻接矩阵的实现方法进行实现。

物理数据对象设计(不用给出基本操作的实现)
采用邻接矩阵实现数据之间的关系储存。通过整型的**matrix存储结点之间的关系,即结点间的权值,其初始值为0。
用两个整型变量numvertex,numedge,分别存储图的结点数和边数。
输入边权值的同时,将权值存储在矩阵中,即可完成图关系的建立。

算法思想的设计
本题要实现可间接到达的结点即有关系,并最终统计和所有结点都有关系的结点的个数。

【步骤1.】可直接到达的结点之间的关系已经存储在了邻接矩阵中,接下来只要考虑如何将可间接到达的结点在矩阵中建立起关系即可。初步设计是,若存在A->B,B->C两条直达边,那么在A,C之间也建立起一条边,使A->B可直达,即A,B之间存在A到B的关系。
如样例中所示,以2为中转结点,1->2可直达,2->4可直达,那么就建立起一条新的边1->4,让1->4可以直达,如图所示:
在这里插入图片描述

【步骤2.】所有结点都可以自己到达自己(即所有部门都知道自己部门存在),通过setedge(v,v)实现即可。

【步骤3.】对所有结点进行如此的遍历,以结点i为中转结点,将可以到达i的j结点和i可以到达的k结点直接连起来,建立j->k的新节点。

【步骤4.】如此则建立起了从起点到终点之间,路径上中间结点的关系建立。接下来考虑逆向的关系建立。(如A->B通过矩阵(A,B)值为1,但根据题目意思,B和A之间也是存在可传递的练习的,此时矩阵(B,A)还没有表现出来,我们可以根据刚才正向的矩阵关系建立)。
通过双层for循环对所有结点进行遍历,如果(A,B)存在关系,但(B,A)值为0,则通过setedge(B,A,1)建立逆向关系。

【步骤5.】此时,正向和逆向的关系都已经实现。再次对numvertex个结点进行遍历,若这个结点和所有结点都有关系,则计数遍历sum++,遍历完成后输出sum即可。

请用题目中样例,基于所设计的算法,详细给出样例求解过程。
在这里插入图片描述

1.将所有结点的关系存储在矩阵中,矩阵如图所示:
在这里插入图片描述

2.所有结点可以到达本身,矩阵更新如下:
在这里插入图片描述

3.间接到达的边1->4可通过中转结点2或者3,完成直达边的建立。如图所示:
在这里插入图片描述
在这里插入图片描述

4.完成逆向关系的建立,矩阵更新如下:
在这里插入图片描述

5.对四个结点和其他节点的关系进行判断,若此结点和其他所有结点都有关系,则初值为0的sum变量+1,如上图矩阵所示,结点1和结点4和四个结点都有关系,sum值为2。输出2。

关键功能的算法步骤(不能用源码)

【步骤3】中采用三重循环遍历,完成间接结点之间的直接关联。伪代码如下:
for(int i = 0 ; i < numv ; i++)
{
for(int j = 0 ; j < numv ; j++)
{
if(mymap.isedge(j,i))
{
for(int k = 0 ; k < numv ; k++)
{
if(mymap.isedge(i,k)&&!mymap.isedge(j,k))
mymap.setedge(j,k,1);
}
}
}
}

【步骤4】逆向关系矩阵的更新,伪代码如下:
for(int i = 0 ; i < numv ; i++)
{
for(int j = 0 ; j < numv ; j++)
{
if(mymap.isedge(i,j)&&!mymap.isedge(j,i))
mymap.setedge(j,i,1);
}
}

三、算法性能分析。
1.将|E|个结点存储在矩阵中,时间复杂度T=|E|

2.步骤3中通过三重遍历实现间接结点的连接,时间复杂度T=在这里插入图片描述

3.步骤4中通过双重循环实现逆向矩阵的实现,时间复杂度T=在这里插入图片描述

4.通过双重循环判断结点是否和所有结点相连,时间复杂度T=在这里插入图片描述

5.总的时间复杂度T=|E|++2,化简后时间复杂度为O(|E|+)

6.算法过程中开辟了一个大小为|E|的二维数组存储边权,时间复杂度为O(|E|)

代码实现部分:
graph.h

#ifndef GRAPH_H_INCLUDED
#define GRAPH_H_INCLUDED
#include <iostream>

class graph
{
private:
    void operator = (const graph&){}
    graph(const graph&){}

public:
    graph(){}
    virtual ~graph(){}

    virtual void init(int n) =0;

    virtual int n() = 0;
    virtual int e() = 0;

    virtual int first(int v) = 0;
    virtual int next(int v,int w) = 0;

    virtual void setedge(int v1,int v2,int wght) = 0;
    virtual void deledge(int v1,int v2) = 0;

    virtual bool isedge(int i,int j) = 0;
    virtual int weight(int v1,int v2) = 0;
    virtual void setmark(int v,int val) = 0;

    virtual void print() = 0;
    virtual int find_out() = 0;
    virtual int find_out_num() = 0;

    virtual void find_know() = 0;
};

#endif // GRAPH_H_INCLUDED

graphm.h

#ifndef GRAPHM_H_INCLUDED
#define GRAPHM_H_INCLUDED
#define UNVISITED 0
#include "graph.h"
#include <iostream>

using namespace std;

class graphm : public graph//脕脷陆脫戮脴脮贸
{
private:
    int numvertex,numedge;
    int **matrix;
    int *mark;
public:
    graphm(int numvert)
    {
        init(numvert);
    }
    ~graphm()
    {
        delete []mark;
        for(int i = 0 ; i < numvertex; i++)
            delete [] matrix[i];
        delete [] matrix;
    }

    void init(int n)
    {
        int i;
        numvertex = n;
        numedge = 0;
        mark = new int [n];
        for(i = 0 ; i < numvertex; i++)
            mark[i] = UNVISITED;
        matrix = (int**)new int *[numvertex];
        for(i = 0 ; i < numvertex ; i++)
            matrix[i] = new int[numvertex];
        for(i = 0 ; i < numvertex ; i++)
            for(int j = 0; j < numvertex; j++)
              matrix[i][j] = 0;
    }
    int n()  {return numvertex;}
    int e()  {return numedge;}

    int first(int v)
    {
        for(int i = 0; i < numvertex; i++)
            if(matrix[v][i] != 0)
              return i;
        return numvertex;
    }
    int next(int v,int w)
    {
        for(int i = w+1; i < numvertex; i++)
            if(matrix[v][i] != 0)
              return i;
        return numvertex;
    }

    void setedge(int v1,int v2,int wt)
    {
        //Assert(wt > 0,"Illegal weight value");
        if(matrix[v1][v2] == 0)  numedge++;
        matrix[v1][v2] = wt;
    }
    void deledge(int v1,int v2)
    {
        if(matrix[v1][v2] != 0)  numedge--;
        matrix[v1][v2] = 0;
    }

    bool isedge(int i,int j)
    {
        return matrix[i][j] != 0;
    }
    void print()
    {
        for(int i = 0 ; i < numvertex ; i++)
        {
            for(int j = 0 ; j < numvertex ; j++)
            {
                cout << matrix[i][j] << " ";
            }
            cout << endl;
        }
    }
    int find_out()
    {
        int answer = 0;int mymax = 0;
        for(int i = 0 ; i < numvertex ; i++)
        {
            int sum = 0;
            for(int j = 0 ; j < numvertex ; j++)
                if(matrix[i][j] != 0)  sum++;
            if(mymax <= sum)
            {
                answer = i ;
                mymax = sum;
            }
        }
        return answer;
    }
    int find_out_num()
    {
        int answer = 0;int mymax = 0;
        for(int i = 0 ; i < numvertex ; i++)
        {
            int sum = 0;
            for(int j = 0 ; j < numvertex ; j++)
                if(matrix[i][j] != 0)  sum++;
            if(mymax <= sum)
            {
                answer = sum ;
                mymax = sum;
            }
        }
        return answer;
    }
    void find_know()
    {
        int sum = 0;
        for(int i = 0 ;i < numvertex ; i++)
        {
            int mymax = 0;
            for(int j = 0 ; j < numvertex ; j++)
            {
                if(matrix[i][j] == 1)
                    mymax++;
            }
            if(mymax == numvertex)
                sum++;
        }
        cout << sum << endl;
    }

    int weight(int v1,int v2) {return matrix[v1][v2];}
    int getmark(int v) {return mark[v];}
    void setmark(int v,int val)  {mark[v] = val;}
};


#endif // GRAPHM_H_INCLUDED

main.c

#include <iostream>
#include "graphm.h"

using namespace std;

int main()
{
    int numv,nume;
    cin >> numv >> nume;
    graphm mymap(numv);
    int key[nume][2];
    for(int i = 0 ; i < nume ; i++)
    {
        cin >> key[i][0] >> key[i][1];
        key[i][0]--; key[i][1]--;
        mymap.setedge(key[i][0],key[i][1],1);
    }
    for(int i = 0 ; i < numv ; i++)
        mymap.setedge(i,i,1);
    for(int i = 0 ; i < numv ; i++)
    {
        for(int j = 0 ; j < numv ; j++)
        {
            if(mymap.isedge(j,i))
            {
                for(int k = 0 ; k < numv ; k++)
                {
                    if(mymap.isedge(i,k)&&!mymap.isedge(j,k))
                        mymap.setedge(j,k,1);
                }
            }
        }
    }
    for(int i = 0 ; i < numv ; i++)
    {
        for(int j = 0 ; j < numv ; j++)
        {
            if(mymap.isedge(i,j)&&!mymap.isedge(j,i))
                mymap.setedge(j,i,1);
        }
    }
    mymap.find_know();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值