第十一周项目实践2 用邻接表存储的图来实现基本应用

假设图G采用邻接表存储,分别设计实现以下要求的算法: 
  (1)输出出图G中每个顶点的出度; 
  (2)求出图G中出度最大的一个顶点,输出该顶点编号; 
  (3)计算图G中出度为0的顶点数; 
  (4)判断图G中是否存在边 <i,j> 。 
  利用下图作为测试用图,输出结果。

  这里写图片描述

#ifndef GRAPH_H_INCLUDED
#define GRAPH_H_INCLUDED

#define MAXV 100                //最大顶点个数
#define INF 32767       //INF表示∞
typedef int InfoType;

//以下定义邻接矩阵类型
typedef struct
{
    int no;                     //顶点编号
    InfoType info;              //顶点其他信息,在此存放带权图权值
} VertexType;                   //顶点类型

typedef struct                  //图的定义
{
    int edges[MAXV][MAXV];      //邻接矩阵
    int n,e;                    //顶点数,弧数
    VertexType vexs[MAXV];      //存放顶点信息
} MGraph;                       //图的邻接矩阵类型
//以下定义邻接表类型
typedef struct ANode            //弧的结点结构类型
{
    int adjvex;                 //该弧的终点位置
    struct ANode *nextarc;      //指向下一条弧的指针
    InfoType info;              //该弧的相关信息,这里用于存放权值
} ArcNode;

typedef int Vertex;

typedef struct Vnode            //邻接表头结点的类型
{
    Vertex data;                //顶点信息
    int count;                  //存放顶点入度,只在拓扑排序中用
    ArcNode *firstarc;          //指向第一条弧
} VNode;

typedef VNode AdjList[MAXV];    //AdjList是邻接表类型

typedef struct
{
    AdjList adjlist;            //邻接表
    int n,e;                    //图中顶点数n和边数e
} ALGraph;                      //图的邻接表类型    void ArrayToList(int *Arr, int n, ALGraph *&); //用普通数组构造图的邻接表
#endif // GRAPH_H_INCLUDED
graph.cpp

#include <stdio.h>
#include <malloc.h>
#include "graph.h"
//功能:由一个反映图中顶点邻接关系的二维数组,构造出用邻接矩阵存储的图
//参数:Arr - 数组名,由于形式参数为二维数组时必须给出每行的元素个数,在此将参数Arr声明为一维数组名(指向int的指针)
//      n - 矩阵的阶数
//      g - 要构造出来的邻接矩阵数据结构
void ArrayToList(int *Arr, int n, ALGraph *&G)
{
    int i,j,count=0;  //count用于统计边数,即矩阵中非0元素个数
    ArcNode *p;
    G=(ALGraph *)malloc(sizeof(ALGraph));
    G->n=n;
    for (i=0; i<n; i++)                 //给邻接表中所有头节点的指针域置初值
        G->adjlist[i].firstarc=NULL;
    for (i=0; i<n; i++)                 //检查邻接矩阵中每个元素
        for (j=n-1; j>=0; j--)
            if (Arr[i*n+j]!=0)      //存在一条边,将Arr看作n×n的二维数组,Arr[i*n+j]=Arr[i][j](n是有多少列)
            {
                p=(ArcNode *)malloc(sizeof(ArcNode));   //创建一个节点*p
                p->adjvex=j;
                p->info=Arr[i*n+j];
                p->nextarc=G->adjlist[i].firstarc;      //采用头插法插入*p,和链表的操作一样
                G->adjlist[i].firstarc=p;
            }
    G->e=count;
}
main.cpp
#include <stdio.h>
#include <malloc.h>
#include "graph.h"
//返回图G中编号为v的顶点的出度
int OutDegree(ALGraph *G,int v)
{
    ArcNode *p;
    int n=0;
    p=G->adjlist[v].firstarc;
    while (p!=NULL)
    {
        n++;
        p=p->nextarc;
    }
    return n;
}
//输出图G中每个顶点的出度
void OutDs(ALGraph *G)
{
    int i;
    for (i=0; i<G->n; i++)
        printf("  顶点%d:%d\n",i,OutDegree(G,i));
}
//输出图G中出度最大的一个顶点
void OutMaxDs(ALGraph *G)
{
    int maxv=0,maxds=0,i,x;
    for (i=0; i<G->n; i++)
    {
        x=OutDegree(G,i);
        if (x>maxds)
        {
            maxds=x;
            maxv=i;
        }
    }
    printf("顶点%d,出度=%d\n",maxv,maxds);
}
//输出图G中出度为0的顶点数
void ZeroDs(ALGraph *G)
{
    int i,x;
    for (i=0; i<G->n; i++)
    {
        x=OutDegree(G,i);
        if (x==0)
            printf("%2d",i);
    }
    printf("\n");
}
//返回图G中是否存在边<i,j>
bool Arc(ALGraph *G, int i,int j)
{
    ArcNode *p;
    bool found = false;
    p=G->adjlist[i].firstarc;
    while (p!=NULL)
    {
        if(p->adjvex==j)
        {
            found = true;
            break;
        }
        p=p->nextarc;
    }
    return found;
}
int main()
{
    ALGraph *G;
    int A[7][7]=
    {
        {0,1,1,1,0,0,0},
        {0,0,0,0,1,0,0},
        {0,0,0,0,1,1,0},
        {0,0,0,0,0,0,1},
        {0,0,0,0,0,0,0},
        {0,0,0,1,1,0,1},
        {0,1,0,0,0,0,0}
    };
    ArrayToList(A[0], 7, G);//建立邻接矩阵结构
    printf("(1)各顶点出度:\n");
    OutDs(G);
    printf("(2)最大出度的顶点信息:");
    OutMaxDs(G);
    printf("(3)出度为0的顶点:");
    ZeroDs(G);
    printf("(4)边<2,6>存在吗?");
    if(Arc(G,2,6))
        printf("是\n");
    else
        printf("否\n");
    printf("\n");
    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
...... ( B )3. 有8个结点的无向最多有 条边。 A.14 B. 28 C. 56 D. 112 ( C )4. 有8个结点的无向连通最少有 条边。 A.5 B. 6 C. 7 D. 8 ( C )5. 有8个结点的有向完全有 条边。 A.14 B. 28 C. 56 D. 112 ( B )6. 用邻接进行广度优先遍历时,通常是采用 来实现算法的。 A.栈 B. 队列 C. 树 D. ...... 二、填空题(每空1分,共20分) 1. 邻接矩阵 、 邻接存储结构,遍历有 深度优先遍历 、 广度优先遍历 等方法。 2. 有向G用邻接矩阵存储,其第i行的所有元素之和等于顶点i的 出度 。 3. 如果n个顶点的是一个环,则它有 n 棵生成树。 4. n个顶点e条边的,若采用邻接矩阵存储,则空间复杂度为 O(n2) 。 5. n个顶点e条边的,若采用邻接存储,则空间复杂度为 O(n+e) 。 ....... 1. 【严题集7.1①】已知如所示的有向,请给出该的: 每个顶点的入/出度; 邻接矩阵; 邻接; 逆邻接。 2. 【严题集7.7②】请对下的无向带权: 写出它的邻接矩阵,并按普里姆算法求其最小生成树; 写出它的邻接,并按克鲁斯卡尔算法求其最小生成树。 ........ 五、算法设计题(每题10分,共30分) 1. 【严题集7.14③】编写算法,由依次输入的顶点数目、弧的数目、各顶点的信息和各条弧的信息建立有向邻接。 解:Status Build_AdjList(ALGraph &G) //输入有向的顶点数,边数,顶点信息和边的信息建立邻接 { InitALGraph(G); scanf("%d",&v); if(v<0) return ERROR; //顶点数不能为负 G.vexnum=v; scanf("%d",&a); if(a<0) return ERROR; //边数不能为负 G.arcnum=a; for(m=0;m<v;m++) G.vertices[m].data=getchar(); //输入各顶点的符号 for(m=1;m<=a;m++) { t=getchar();h=getchar(); //t为弧尾,h为弧头 if((i=LocateVex(G,t))<0) return ERROR; if((j=LocateVex(G,h))nextarc;q=q->nextarc); q->nextarc=p; } p->adjvex=j;p->nextarc=NULL; }//while return OK; }//Build_AdjList 2. 【严题集7.15③】试在邻接矩阵存储结构上实现基本操作:DeleteArc(G,v,w)。 (刘提示:删除所有从第i个顶点出发的边的方法是 将邻接矩阵的第i行全部置0 ) ........
### 回答1: 邻接是一种常用的存储结构,它将每个顶点的邻接点列存储在一个链中。广度优先遍历算法是一种基于队列的遍历算法,它从的某个顶点开始,依次访问该顶点的所有邻接点,然后再依次访问这些邻接点的邻接点,以此类推,直到遍历完整个。 在邻接存储的情况下,实现广度优先遍历算法的步骤如下: 1. 创建一个队列,将起始顶点入队。 2. 标记起始顶点为已访问。 3. 从队列中取出一个顶点,访问它的所有邻接点,并将未访问过的邻接点入队。 4. 标记所有已访问的邻接点为已访问。 5. 重复步骤3和步骤4,直到队列为空。 在实现过程中,可以使用一个数组来记录每个顶点是否已经被访问过,以避免重复访问。同时,可以使用一个指针数组来存储每个顶点的邻接点链的头指针,以便快速访问每个顶点的邻接点。 综上所述,邻接存储的广度优先遍历算法是一种基于队列的遍历算法,它可以快速遍历整个,并且可以避免重复访问。 ### 回答2: 广度优先遍历(BFS)是的一种基本遍历方式,它从指定的起始节点开始遍历,逐层地访问每个与该节点相邻的节点,直到遍历完整张。在的效率比较高的数据结构存储方法中,邻接是最常用的,下面就为大家介绍用邻接存储,并实现广度优先遍历算法的过程。 邻接是一种用于示某种的数据结构,它将每个节点与它所连接到的所有节点连接成一个链实现邻接存储基本流程如下: (1)用结构体数组V存放顶点信息,结构体中至少包含节点名称和一个指针域,用来指向连接该节点的边。 (2)建立一个链数组E,数组大小为顶点个数,链头指向存储该节点信息的结构体,链节点指向与该节点相邻的节点。 (3)建立一个示已经访问过的节点的数组visited,数组元素初始化为false。 (4)定义一个队列queue作为广度优先遍历的缓存,将起始节点加入队列。 (5)重复以下步骤直到队列为空 a)弹出队头元素,输出该元素; b)将刚才弹出的元素的所有邻居添加到队尾,如果邻居尚未被访问,则将其标记为访问过,并将其加入队列中。 具体代码实现如下: ```C++ #include <iostream> #include <queue> using namespace std; #define MAXV 100 //最大顶点数 struct EdgeNode{ int adjvex; //连接边的顶点编号 EdgeNode* next; //链中下一个节点的地址 }; struct VertexNode{ int data; //顶点的编号或其它相关信息 EdgeNode* firstEdge; //指向该节点的第一条边 }; VertexNode V[MAXV]; //存储顶点的数组 bool visited[MAXV] = {false};//记录节点是否被访问过 queue<int> Q; //定义一个队列存放待访问的节点 //添加一条有向边 void addEdge(int u, int v){ EdgeNode* e = new EdgeNode; e->adjvex = v; e->next = V[u].firstEdge; V[u].firstEdge = e; } //广度优先遍历 void BFS(int v){ visited[v] = true; //标记节点v为已访问 Q.push(v); //将节点v加入队列 while(!Q.empty()){ int u = Q.front(); //获取队头元素 Q.pop(); //删除队头元素 cout<<V[u].data<<" "; //输出队头元素的值 //遍历该节点的所有邻居节点 EdgeNode* e = V[u].firstEdge; while(e != nullptr){ int w = e->adjvex; //获取邻居节点 if(!visited[w]){ //如果该节点未访问过,则加入队列 visited[w] = true; //标记节点为已访问 Q.push(w); //将邻居节点加入队列 } e = e->next; //继续遍历邻居节点 } } } int main(){ int n, m; cin>>n>>m; //输入顶点数和边数 for(int i=1; i<=n; i++){ cin>>V[i].data; //输入每个节点的数据 V[i].firstEdge = nullptr; //初始化第一条边为空 } for(int i=1; i<=m; i++){ int u, v; cin>>u>>v; //输入一条边的起点和终点 addEdge(u, v); //添加边到邻接中 } BFS(1); //从第一个节点开始进行广度优先遍历 return 0; } ``` 总的来说,用邻接存储,并实现广度优先遍历算法的核心就是维护好邻接结构,注意访问过的节点,队列的使用等。通过这种方式高效地存储和遍历可以在解决很多实际问题时发挥作用。 ### 回答3: 邻接是一种存储有向或无向的数据结构,它是一个数组列,其中每个数组元素示该元素对应顶点的邻接点。在邻接中,每个顶点v的所有邻接点被存储在一个链中。因此,当需要遍历时,可以使用广度优先遍历算法,从的某个初始顶点开始,按照广度优先的顺序依次访问所有与该顶点直接相邻的顶点。 邻接实现可以使用链或数组实现。使用邻接存储时,每个顶点v对应一个链,该链包含v的所有邻接点。当需要访问v的相邻节点时,只需要遍历v对应链即可。使用邻接数组来存储时,邻接数组的每个元素包含一个布尔值以示该点是否为邻接点以及存储该点的权值。 实现的广度优先遍历算法的基本思路是:从的某个顶点开始,将该顶点的所有邻接点入队,然后将队首元素出队,继续重复该操作,直到所有顶点均被访问到为止。为了避免重复遍历顶点,需要使用一个布尔类型列visited,记录每个顶点是否被访问过。 具体实现过程如下: 1. 从起始顶点开始,将该顶点标记为已访问,并将该顶点入队。 2. 从队首取出一个顶点v,遍历该顶点v的所有邻接点w,并将未访问过的邻接点w加入队列,并标记为已访问。 3. 重复以上步骤,直到队列为空。 邻接存储的优点在于它能够节省存储空间,并且可以快速地查询所有相邻节点。同时,使用邻接存储的时间复杂度为O(E+V),其中E为边数,V为顶点数。因此,在大多数情况下,使用邻接存储并基于广度优先遍历算法实现的遍历是一种较为高效和实用的方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值