写在前面——
本文主要是在记录进一步学习图结构的一些心得。
1.邻接表
邻接表是由每个顶点以及它的相邻顶点组成的。前一章我们知道了可以用邻接矩阵表示了图结构,但是它有一个致命的缺点,那就是矩阵中存在着大量的0,这在程序中会占据大量的内存。所以我们采用了邻接表的方法,从而很好的来解决邻接矩阵的缺陷。
2.代码实现
#include#include #define QUEUE_SIZE 10 int* visitedPtr; typedef struct Graph{ int** connections; int numNodes; } *GraphPtr; void deepFirst(GraphPtr paraGraphPtr, int paraNode); GraphPtr initGraph(int paraSize, int** paraData) { int i, j; GraphPtr resultPtr = (GraphPtr)malloc(sizeof(struct Graph)); resultPtr -> numNodes = paraSize; resultPtr -> connections = (int**)malloc(paraSize * paraSize * sizeof(int)); 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]; } } return resultPtr; } typedef struct GraphNodeQueue{ int* nodes; int front; int rear; }GraphNodeQueue, *QueuePtr; 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; } bool isQueueEmpty(QueuePtr paraQueuePtr){ if ((paraQueuePtr->front + 1) % QUEUE_SIZE == paraQueuePtr->rear) { return true; } return false; } void enqueue(QueuePtr paraQueuePtr, int paraNode){ printf("front = %d, rear = %d.rn", paraQueuePtr->front, paraQueuePtr->rear); if ((paraQueuePtr->rear + 1) % QUEUE_SIZE == paraQueuePtr->front % QUEUE_SIZE) { printf("Error, trying to enqueue %d. queue full.rn", paraNode); return; } paraQueuePtr->nodes[paraQueuePtr->rear] = paraNode; paraQueuePtr->rear = (paraQueuePtr->rear + 1) % QUEUE_SIZE; printf("enqueue %d ends.rn", paraNode); } int dequeue(QueuePtr paraQueuePtr){ if (isQueueEmpty(paraQueuePtr)) { printf("Error, empty queuern"); return NULL; } paraQueuePtr->front = (paraQueuePtr->front + 1) % QUEUE_SIZE; printf("dequeue %d ends.rn", paraQueuePtr->nodes[paraQueuePtr->front]); return paraQueuePtr->nodes[paraQueuePtr->front]; } typedef struct AdjacencyNode { int column; AdjacencyNode* next; }AdjacencyNode, *AdjacentNodePtr; typedef struct AdjacencyList { int numNodes; AdjacencyNode* headers; }AdjacencyList, *AdjacencyListPtr; AdjacencyListPtr graphToAdjacentList(GraphPtr paraPtr) { int i, j, tempNum; AdjacentNodePtr p, q; tempNum = paraPtr->numNodes; AdjacencyListPtr resultPtr = (AdjacencyListPtr)malloc(sizeof(struct AdjacencyList)); resultPtr->numNodes = tempNum; resultPtr->headers = (AdjacencyNode*)malloc(tempNum * sizeof(struct AdjacencyNode)); for (i = 0; i < tempNum; i ++) { p = &(resultPtr->headers[i]); p->column = -1; p->next = NULL; for (j = 0; j < tempNum; j ++) { if (paraPtr->connections[i][j] > 0) { q = (AdjacentNodePtr)malloc(sizeof(struct AdjacencyNode)); q->column = j; q->next = NULL; p->next = q; p = q; } } } return resultPtr; } void printAdjacentList(AdjacencyListPtr paraPtr) { int i; AdjacentNodePtr p; int tempNum = paraPtr->numNodes; printf("This is the graph:rn"); for (i = 0; i < tempNum; i ++) { p = paraPtr->headers[i].next; while (p != NULL) { printf("%d, ", p->column); p = p->next; } printf("rn"); } } void widthFirstTranverse(AdjacencyListPtr paraListPtr, int paraStart){ printf("width first rn"); int i, j, tempNode; AdjacentNodePtr p; i = 0; visitedPtr = (int*) malloc(paraListPtr->numNodes * sizeof(int)); for (i = 0; i < paraListPtr->numNodes; i ++) { visitedPtr[i] = 0; } QueuePtr tempQueuePtr = initQueue(); printf("%dt", paraStart); visitedPtr[paraStart] = 1; enqueue(tempQueuePtr, paraStart); printf("After enqueuern"); while (!isQueueEmpty(tempQueuePtr)) { printf("First whilern"); tempNode = dequeue(tempQueuePtr); for (p = &(paraListPtr->headers[tempNode]); p != NULL; p = p->next) { j = p->column; if (visitedPtr[j]) continue; printf("%dt", j); visitedPtr[j] = 1; enqueue(tempQueuePtr, j); } } } 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 datarn"); tempPtr = (int**)malloc(5 * sizeof(int*)); for (i = 0; i < 5; i ++) { tempPtr[i] = (int*)malloc(5 * sizeof(int)); } for (i = 0; i < 5; i ++) { for (j = 0; j < 5; j ++) { printf("i = %d, j = %d, ", i, j); printf("%drn", tempPtr[i][j]); tempPtr[i][j] = myGraph[i][j]; printf("i = %d, j = %d, %drn", i, j, tempPtr[i][j]); } } printf("Data readyrn"); GraphPtr tempGraphPtr = initGraph(5, tempPtr); AdjacencyListPtr tempListPtr = graphToAdjacentList(tempGraphPtr); printAdjacentList(tempListPtr); widthFirstTranverse(tempListPtr, 4); } int main(){ testGraphTranverse(); return 1; }
3.广度优先遍历
本质上就是从第一个顶点开始,尝试访问尽可能靠近它的顶点,即先访问最靠近它的所有顶点,再访问第二靠近它的所有顶点,以此类推,直到访问完所有的顶点。
以下图为例
第一次先搜索离 顶点1 最近的两个顶点,即 顶点2 和 顶点7
然后再搜索离 顶点1 第二近的所有顶点,也就是离 顶点2 和 顶点7 最近的所有顶点
离顶点2 最近的顶点为 顶点3 和 顶点5 ,离 顶点7 最近的顶点为 顶点8 ,因此这几个点以此被遍历
再继续往下搜索离 顶点1 第三近的所有顶点,也就是离 顶点3 、顶点5 和 顶点8 最近的所有顶点
由图可知,离 顶点3 最近的顶点有 顶点6 ;离 顶点5 最近的顶点有 顶点4 ;离 顶点8 最近的顶点有 顶点9,因此它们也逐一被遍历
到此为止,整个图结构就已经被遍历完成了,这就是一个广度优先搜索完整的过程



