第十二周项目2——操作用邻接表存储的图

问题:

/*    
* Copyright (c)2016,烟台大学计算机与控制工程学院    
* All rights reserved.    
* 文件名称:项目2.cpp    
* 作    者:陈晨    
* 完成日期:2016年11月16日    
* 版 本 号:v1.0     
*问题描述:假设图G采用邻接表存储,分别设计实现以下要求的算法: 
  (1)输出出图G中每个顶点的出度; 
  (2)求出图G中出度最大的一个顶点,输出该顶点编号; 
  (3)计算图G中出度为0的顶点数; 
  (4)判断图G中是否存在边<i,j>。 
  
*输入描述:无    
*程序输出:测试数据    
*/   

利用下图作为测试图,输出结果。



头文件graph.h以及其函数功能实现详见图算法库

源文件main.cpp代码:

#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;
}

运行结果:


知识点总结:

利用图算法库解决问题。

学习心得:

只要明白如何计算各个顶点的出度。

### 创建实现DFS和BFS 为了在C语言中创建实现深度优先搜索(DFS)和广度优先搜索(BFS),可以采用两种不同的方式来表示的数据结构:邻接矩阵和十字链表。 #### 邻接矩阵表示法 邻接矩阵是一种二维数组,用于表示中的边。对于无向而言,如果存在一条连接顶点`i`到顶点`j`的边,则设置`matrix[i][j]=1`;反之则设为0。有向的情况与此相似,只是方向性决定了哪一端被置位[^1]。 ```c #define MAX_VEX 100 // 假定最大顶点数量不超过此值 typedef struct { char vexs[MAX_VEX]; /* 存储顶点信息 */ int matrix[MAX_VEX][MAX_VEX];/* 邻接矩阵 */ int vexnum, arcnum; /* 当前实际存在的顶点数目和弧的数量 */ } MGraph; ``` #### 十字链表表示法 十字链表是另一种有效的形数据结构表达形式,它不仅能够很好地支持稀疏,而且便于动态增删操作。每个节点由五个部分组成——指向下一个同列节点指针、下一行节点指针、入边标志、出边标志以及该位置上的权重或其它属性字段[^2]。 ```c // 定义边结点EdgeNode 和头结点头HeadNode 结构体 typedef struct EdgeNode{ int adjvex; /* 边所依附的另一个顶点的位置 */ struct EdgeNode *next; /* 指向下一条边的指针 */ }; typedef struct HeadNode{ char data; /* 数据域 */ struct EdgeNode *firstedge;/* 表示第一条依附于该顶点的边 */ }* PtrToAdjList; typedef struct GraphAdjList{ PtrToAdjList adjlist[MAX_VEX]; int n,e; /* 中当前顶点数n和边数e */ } ALGraph; ``` #### 实现DFS递归版本 当使用邻接矩阵作为底层存储机制时,可以通过简单的函数调用来完成递归式的DFS: ```c void DFS(MGraph g,int v){ printf("%d ",g.vexs[v]); visited[v]=true; for(int w=FirstNeighbor(g,v);w>=0;w=NextNeighbor(g,v,w)){ if(!visited[w]){ DFS(g,w); } } } ``` 而对于基于十字链表构建的来说,由于其内部采用了链式列表的形式保存相邻关系,因此需要稍微调整上述逻辑以适应新的遍历模式[^3]。 ```c void DFS(ALGraph G,int k){ EdgeNode* p=G.adjlist[k]->firstedge; Visited[k]=TRUE; VisitFunc(G,k); while(p!=NULL){ if(Visited[p->adjvex]==FALSE){ DFS(G,p->adjvex); } p=p->next; } } ``` #### BFS非递归版 无论是哪种类型的,在执行宽度优先搜索之前都需要先初始化一个队列,并将起始顶点加入其中。之后不断取出队首元素进行处理直至为空为止。这里给出针对邻接矩阵的具体做法如下所示: ```c void BFSTraverse(MGraph G){ Queue Q=(Queue)malloc(sizeof(Queue)); InitQueue(&Q); memset(vis,false,sizeof(bool)*G.n); for(int i=0;i<G.n;++i){ if(!vis[i]){ Enqueue(&Q,i); vis[i]=true; while(!IsEmpty(&Q)){ Dequeue(&Q,&u); ProcessVertex(u); for(w=FirstAdjVex(G,u);w!=-1;w=NextAdjVex(G,u,w)){ if(!vis[w]){ AddTwins(); Enqueue(&Q,w); vis[w]=true; } } } } } } ``` 同样的道理也可以应用于十字链表上,只需修改获取邻居的方式即可。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值