摘要: 图在我们生活中很常用到,树其实就是一中特殊的图。我们本次讲到图在计算机里面的一种存储方式:布尔矩阵(即二维数组)。
图,几乎上综合了我们前面学的所有数据结构,比如二维数组,栈,队列,树的相关操作(遍历)以及链表(这里没用到链表,下一次我们讲图的邻接表存储会用到)。所以如果你对以前的数据结构都掌握得不错的话,写起来就比较轻松,如果对以前的数据结构掌握有所欠缺的话,那就难了。
上代码!
一.代码块
1)结构体定义
这个visited数组是用来记录某位置是否被访问过了,为什么要记录呢,因为图不像二叉树那样,由上往下只能通过双亲到达儿子,并且每一个结点只有一个双亲。
图的话,很有可能可以通过多个结点访问到你。所以是否被访问过了我们是很有必要记录的。这种在各个函数都会用到,并且随时会更改的变量设置为全局变量很舒服
这里我们用的是 n×n的布尔矩阵来表示每两个点之间的连通性,第n行就代表第n个元素分别与其他元素(包括自己)是否连通
#define MAXSIZE 10
int* visited;
typedef struct graph
{
int** connections;
int numNodes;
}*graphPtr;
2)队列及其相关操作
进行广度遍历的时候会用到队列,我们把循环队列的相关操作给出来。
/*这里是我们在广度遍历要用到的循环队列的相关操作*/
typedef struct graphQueue
{
int *node;
int front;
int rear;
}*graphQueuePtr;
graphQueuePtr queueInit()
{
graphQueuePtr resultQueue = (graphQueuePtr)malloc(sizeof(struct graphQueue));
resultQueue->node = (int*)malloc(MAXSIZE * sizeof(int));
resultQueue->front = 0;
resultQueue->rear = 0;
return resultQueue;
}
void enqueue(graphQueuePtr paraQueue,int paraData)
{
if((paraQueue->rear + 1) % MAXSIZE == (paraQueue->front) % MAXSIZE)
{
printf("队列满了,无法入队!\n");
return ;
}
paraQueue->node[(paraQueue->rear) % MAXSIZE] = paraData;
paraQueue->rear = (paraQueue->rear + 1) % MAXSIZE;
}
int dequeue(graphQueuePtr paraQueue)
{
if(paraQueue->front == paraQueue->rear)
{
printf("队列为空,无法出队!\n");
return ;
}
int temp = paraQueue->node[(paraQueue->front) % MAXSIZE];
paraQueue->front = (paraQueue->front + 1) % MAXSIZE;
return temp;
}
3)初始化visited数组
这里就是分配空间,并且初始化为0代表都没访问过
void visitedInit(graphPtr paraGraph)
{
int i;
visited = (int*)malloc(paraGraph->numNodes * sizeof(int));
for(i = 0;i < paraGraph->numNodes;i ++)
{
visited[i] = 0;
}
}
4)图的初始化
传入一个动态二维数组和元素个数,然后初始化的时候将其拷贝到图结构里面就行了,其实这个初始化就是动态分配空间和拷贝
graphPtr graphInit(int **paraConnections,int paraNumNodes)
{
int i,j;
graphPtr resultGraph = (graphPtr)malloc(sizeof(struct graph));
resultGraph->numNodes = paraNumNodes;
//这里如何给二维数组动态分配空间如果不明白可以参考我以前的二维数组文章
resultGraph->connections = (int**)malloc(resultGraph->numNodes * sizeof(int*));
for(i = 0;i < resultGraph->numNodes;i ++)