1.代码如下
#include <stdio.h>
#include <stdbool.h>
#include<malloc.h>
#define QUEUE_SIZE 10
int *visitedPtr;
/**N
*A queue with a number of inddices.
*/
typedef struct GraphNodeQueue{
int *nodes;
int front;
int rear;
}GraphNodeQueue,*QueuePtr;
/**
*Initalize the queue.
*/
QueuePtr initQueue(){
QueuePtr resultQueuePtr = (QueuePtr) malloc(sizeof(struct GraphNodeQueue));
resultQueuePtr->nodes = (int*)malloc(QUEUE_SIZE *sizeof(int)) ;
resultQueuePtr->front = 0;
resultQueuePtr->rear = 1;
return resultQueuePtr;
}//of initQueue
/**
*Is the queue empty?
*/
bool isQueueEmpty(QueuePtr paraQueuePtr){
if((paraQueuePtr->front +1)%QUEUE_SIZE == paraQueuePtr->rear) {
return true;
}//of if
return false;
}//of isQueueEmpty
/**
*Add a node to the node.
*/
void enqueue(QueuePtr paraQueuePtr,int paraNode){
if((paraQueuePtr->rear +1)%QUEUE_SIZE == paraQueuePtr->front%QUEUE_SIZE){
printf("Error,trying to enqueue %d.queue full.\r\n",paraNode);
return ;
}//of if
paraQueuePtr->nodes[paraQueuePtr->rear] =paraNode;
paraQueuePtr->rear=(paraQueuePtr->rear+1)%QUEUE_SIZE;
}//of enqueue
/**
*Remove an element from the queue and return.
*/
int dequeue(QueuePtr paraQueuePtr){
if(isQueueEmpty(paraQueuePtr)){
printf("Error,empty queue.\r\n");
return -1;
}//of if
paraQueuePtr->front=(paraQueuePtr->front+1)%QUEUE_SIZE;
return paraQueuePtr->nodes[paraQueuePtr->front];
}//of dequeue
/**
*The structure of a graph
*/
typedef struct Graph{
int **connections;
int numNodes;
}*GraphPtr;
GraphPtr initGraph(int paraSize,int **paraData){
int i,j;
GraphPtr resultPtr =(GraphPtr)malloc(sizeof(struct Graph));
resultPtr->numNodes =paraSize;
resultPtr->connections=(int **)malloc(paraSize * sizeof(int));
for(i=0;i<paraSize;i++){
resultPtr->connections[i]=(int*)malloc(paraSize*sizeof(int));
for(j=0;j<paraSize;j++){
resultPtr->connections[i][j]=paraData[i][j];
}//of for j
}//of for i
return resultPtr;
}//of initGraph
/**
*Initalize the tranverse.
*/
void initTranverse(GraphPtr paraGraphPtr) {
int i;
//initalize data.
visitedPtr =(int *)malloc(paraGraphPtr->numNodes*sizeof(int));
for(i=0;i<paraGraphPtr->numNodes;i++){
visitedPtr[i] =0;
}//of for i
}//of initTranverse
/**
*Depth first tranverse
*/
void depthFirstTranverse(GraphPtr paraGraphPtr,int paraNode){
int i;
visitedPtr[paraNode] =1;
printf("%d\t",paraNode);
for(i=0;i<paraGraphPtr->numNodes;i++){
if(!visitedPtr[i]){
if(paraGraphPtr->connections[paraNode][i]){
depthFirstTranverse(paraGraphPtr,i);
}//of if
}//of if
}//of for i
}//of depthFirstTranverse
/**
*Width first tranverse
*/
void widthFirstTranverse(GraphPtr paraGraphPtr,int paraStart){
int i,j,tempNode;
i=0;
QueuePtr tempQueuePtr =initQueue();
printf("%d\t",paraStart);
visitedPtr[paraStart]=1;
enqueue(tempQueuePtr,paraStart);
while(!isQueueEmpty(tempQueuePtr)){
tempNode =dequeue(tempQueuePtr);
visitedPtr[tempNode] = 1;
//For output
i++;
for(j=0;j<paraGraphPtr->numNodes;j++){
if(visitedPtr[j])
continue;
if(paraGraphPtr->connections[tempNode][j]==0)
continue;
printf("%d\t",j);
visitedPtr[j]=1;
enqueue(tempQueuePtr,j);
}//of for i
}//of while
}//of widethFiratTranverse
void testGraphTranverse(){
int i,j;
int myGraph[5][5]={
{0,1,0,1,0},
{1,0,1,0,1},
{0,1,0,1,1},
{1,0,1,0,0},
{0,1,1,0,0}};
int **tempPtr;
printf("Preparing data\r\n");
tempPtr =(int**)malloc(5 * sizeof(int *));
for(i=0;i<5;i++){
tempPtr[i] =(int*)malloc(sizeof(int));
}//of for i
for(i=0;i<5;i++){
for(j=0;j<5;j++){
tempPtr[i][j] = myGraph[i][j];
}//of for j
}//of for i
printf("Data ready\r\n");
GraphPtr tempGraphPtr=initGraph(5,tempPtr);
printf("num nodes =%d\r\n",tempGraphPtr->numNodes);
printf("Graph initialized\r\n");
printf("Depth first visit\r\n");
initTranverse(tempGraphPtr);
depthFirstTranverse(tempGraphPtr,4);
printf("\r\nWidth first visit:\r\n");
initTranverse(tempGraphPtr);
widthFirstTranverse(tempGraphPtr,4);
}//of testGraphTranverse
int main(){
testGraphTranverse();
return 1;
}//of main
2.运行结果
3.小结
数据结构中的图是一种非常重要的非线性数据结构,它用于表示对象之间的关系。以下是关于数据结构图的小结:
1)基本概念:图由顶点和边组成,其中顶点表示对象,边表示对象之间的关系。分为无向图和有向图,无向图中的边没有方向,而有向图中的边有方向。图的表示方法主要有邻接矩阵和邻接表两种。
2)图的遍历:图的遍历主要有深度优先遍历(DFS)和广度优先遍历(BFS)两种。
深度优先遍历(DFS):这种遍历方式类似于树的先序遍历。它从图的某个顶点开始,访问这个顶点,并尽可能深地搜索图的分支。当节点v的所在边都已被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。
广度优先遍历(BFS):这种遍历方式是从图的某一顶点出发,首先访问这个顶点,然后找出这个顶点的所有未被访问过的相邻顶点,访问完后再从这些相邻顶点出发,继续寻找它们的未被访问过的相邻顶点,如此类推,直至图中所有已被访问过的顶点的邻接点都被访问到。广度优先遍历通常使用队列来实现。
这两种遍历方式各有特点,深度优先遍历在寻找路径时更偏向于深入搜索,而广度优先遍历则更偏向于先搜索近的节点再搜索远的节点。在解决不同的问题时,我们可以根据需要选择适合的遍历方式。
3)图的连通性:
无向图中,如果从任意顶点都存在路径到达另一顶点,则称该图是连通的。
有向图中,如果从任意顶点都存在路径到达另一顶点,则称该图是强连通的。
无向图中的极大连通子图称为连通分量,而有向图中的极大连通子图称为强连通分量。
4)图的生成树和生成森林:
连通图的生成树是包含图中全部顶点的一个极小连通子图,且不含环。
对于非连通图,由各个连通分量的生成树组成的集合称为生成森林。
5)图的度:
在无向图中,顶点的度是与该顶点相连的边的数目。
在有向图中,顶点的度分为入度和出度,入度是以该顶点为终点的边的数目,出度是以该顶点为起点的边的数目。
6)图的特殊类型:
完全图:在无向图中,如果任意两个顶点之间都存在边,则称该图为完全图。
简单图:不存在重复边、不存在顶点到自身的边的图称为简单图。