目錄:
- 代碼:
- 分析:
- 匯編:
MGrapth圖表示有鄰接矩陣的方式構成的圖結構。
鄰接矩陣用兩個數組保存數據,一個一維數組存儲圖中的頂點信息,一個二維數組存儲圖中邊或弧的信息。
無向圖中的二維數組是個對稱矩陣
1.0表示無邊,1表示有邊
2.頂點的度是行內數組之和
3.求取頂點鄰接占,將行內元素遍歷下
有向圖的鄰接矩陣(二維數組),
有分入度和出度,行內之和是出度,列內之和是入度
代碼:
LinkQueue.h
#ifndef _LINKQUEUE_H_
#define _LINKQUEUE_H_typedef void LinkQueue;LinkQueue* LinkQueue_Create();void LinkQueue_Destroy(LinkQueue* queue);void LinkQueue_Clear(LinkQueue* queue);int LinkQueue_Append(LinkQueue* queue, void* item);void* LinkQueue_Retrieve(LinkQueue* queue);void* LinkQueue_Header(LinkQueue* queue);int LinkQueue_Length(LinkQueue* queue);#endif
LinkQueue.c
#include <malloc.h>
#include <stdio.h>
#include "LinkQueue.h"typedef struct _tag_LinkQueueNode TLinkQueueNode;//定義隊列節點類型
struct _tag_LinkQueueNode
{TLinkQueueNode* next;void* item;
};typedef struct _tag_LinkQueue//定義隊列類型
{TLinkQueueNode* front;TLinkQueueNode* rear;int length;
} TLinkQueue;LinkQueue* LinkQueue_Create() //定義創建隊列函數
{TLinkQueue* ret = (TLinkQueue*)malloc(sizeof(TLinkQueue));if( ret != NULL ){ret->front = NULL;ret->rear = NULL;ret->length = 0;}return ret;
}void LinkQueue_Destroy(LinkQueue* queue) // 定義銷毀隊列函數
{LinkQueue_Clear(queue);free(queue);
}void LinkQueue_Clear(LinkQueue* queue) // 定義清空隊列函數
{while( LinkQueue_Length(queue) > 0 ){LinkQueue_Retrieve(queue);}
}int LinkQueue_Append(LinkQueue* queue, void* item) // 定義進隊列函數
{TLinkQueue* sQueue = (TLinkQueue*)queue;//取得隊列TLinkQueueNode* node = (TLinkQueueNode*)malloc(sizeof(TLinkQueueNode));//新建節點int ret = (sQueue != NULL ) && (item != NULL) && (node != NULL);if( ret ){node->item = item;//給新建節點保存的數據賦值if( sQueue->length > 0 )//如果長度大于0{sQueue->rear->next = node;//將隊列最后一個節點的next指向新建節點sQueue->rear = node;//設新建節點為最后節點 node->next = NULL;}else//否則 表示是第一個節點{sQueue->front = node;//設第一個節點為新建節點sQueue->rear = node;//設最后一個節點為新建節點node->next = NULL;}sQueue->length++;}if( !ret )//條件不成功{free(node);//釋放新建節點}return ret;
}void* LinkQueue_Retrieve(LinkQueue* queue) // 定義出隊列函數
{TLinkQueue* sQueue = (TLinkQueue*)queue;//取得隊列TLinkQueueNode* node = NULL;void* ret = NULL;if( (sQueue != NULL) && (sQueue->length > 0) ){node = sQueue->front;//取得出隊列節點sQueue->front = node->next;//將隊列第一個節點設為取出節點的下一個ret = node->item;//取得節點保存的數據free(node);//釋放出隊列節點sQueue->length--;if( sQueue->length == 0 )//如果是最后一個節點{sQueue->front = NULL;//將第一個節點指針清空sQueue->rear = NULL;//將最后一個節點指針清空}}return ret;
}void* LinkQueue_Header(LinkQueue* queue) // 定義獲取第一個節點數據函數
{TLinkQueue* sQueue = (TLinkQueue*)queue;void* ret = NULL;if( (sQueue != NULL) && (sQueue->length > 0) ){ret = sQueue->front->item;}return ret;
}int LinkQueue_Length(LinkQueue* queue) // 定義獲取隊列長度函數
{TLinkQueue* sQueue = (TLinkQueue*)queue;int ret = -1;if( sQueue != NULL ){ret = sQueue->length;}return ret;
}
MGraph.h
#ifndef _MGRAPH_H_
#define _MGRAPH_H_typedef void MGraph;//定義圖類型
typedef void MVertex;//定義頂點類型
typedef void (MGraph_Printf)(MVertex*);//定義有一個頂點類型指針參數并且無返回值的函數類型MGraph* MGraph_Create(MVertex** v, int n);//聲明創建圖函數void MGraph_Destroy(MGraph* graph);//聲明銷毀圖函數void MGraph_Clear(MGraph* graph);//聲明清空圖函數int MGraph_AddEdge(MGraph* graph, int v1, int v2, int w);//聲明添加邊函數int MGraph_RemoveEdge(MGraph* graph, int v1, int v2);//聲明移除邊函數int MGraph_GetEdge(MGraph* graph, int v1, int v2);//聲明獲取邊函數int MGraph_TD(MGraph* graph, int v);//聲明以一個數作為行與列檢測不等于0的值的數量函數int MGraph_VertexCount(MGraph* graph);//聲明獲取頂點數量函數int MGraph_EdgeCount(MGraph* graph);//聲明獲取邊數量函數void MGraph_DFS(MGraph* graph, int v, MGraph_Printf* pFunc);//聲明void MGraph_BFS(MGraph* graph, int v, MGraph_Printf* pFunc);//聲明void MGraph_Display(MGraph* graph, MGraph_Printf* pFunc);//聲明#endif
MGraph.c
#include <malloc.h>
#include <stdio.h>
#include "MGraph.h"
#include "LinkQueue.h"typedef struct _tag_MGraph//定義實際使用圖類型
{int count;//數量MVertex** v;//指向頂點指針的指針變量int** matrix;//指向整型指針的指針變量
} TMGraph;//遞歸遍歷矩陣函數
static void recursive_dfs(TMGraph* graph, int v, int visited[], MGraph_Printf* pFunc)
{int i = 0;pFunc(graph->v[v]);visited[v] = 1;printf(", ");for(i=0; i<graph->count; i++){if( (graph->matrix[v][i] != 0) && !visited[i] ){recursive_dfs(graph, i, visited, pFunc);}}
}
//用隊列遍歷矩陣
static void bfs(TMGraph* graph, int v, int visited[], MGraph_Printf* pFunc)
{LinkQueue* queue = LinkQueue_Create();//創建隊列if( queue != NULL )//創建成功{LinkQueue_Append(queue, graph->v + v);//將頂點信息存進隊列visited[v] = 1;//將對應行記錄為已查看while( LinkQueue_Length(queue) > 0 ){int i = 0;v = (MVertex**)LinkQueue_Retrieve(queue) - graph->v;pFunc(graph->v[v]);printf(", ");for(i=0; i<graph->count; i++){if( (graph->matrix[v][i] != 0) && !visited[i] ){LinkQueue_Append(queue, graph->v + i);visited[i] = 1;}}}}LinkQueue_Destroy(queue);
}MGraph* MGraph_Create(MVertex** v, int n) // 定義創建圖函數
{TMGraph* ret = NULL;if( (v != NULL ) && (n > 0) ){ret = (TMGraph*)malloc(sizeof(TMGraph));//新建圖if( ret != NULL )//新建成功{int* p = NULL;ret->count = n;//設置數量ret->v = (MVertex**)malloc(sizeof(MVertex*) * n);//創建n個頂點指針類型的空間,v指向第一個ret->matrix = (int**)malloc(sizeof(int*) * n);//創建n個整型指針類型的空間,matrix指向第一個p = (int*)calloc(n * n, sizeof(int));//創建n*n個int 類型空間,p指向第一個if( (ret->v != NULL) && (ret->matrix != NULL) && (p != NULL) )//全部創建成功{int i = 0;for(i=0; i<n; i++){ret->v[i] = v[i];//將傳來的頂點信息給新建的圖中的頂點賦值ret->matrix[i] = p + i * n;//將新建圖中的矩陣指向p創建的地址(0,6,12,18,24,30)}}else//如果創建失敗,將申請的空間全部釋放{free(p);free(ret->matrix);free(ret->v);free(ret);ret = NULL;//返回空}}}return ret;
}void MGraph_Destroy(MGraph* graph) //定義銷毀圖函數
{TMGraph* tGraph = (TMGraph*)graph;//取得圖if( tGraph != NULL )//圖不為空,將空間全部釋放{free(tGraph->v);free(tGraph->matrix[0]);free(tGraph->matrix);free(tGraph);}
}void MGraph_Clear(MGraph* graph) // 定義清空圖函數
{TMGraph* tGraph = (TMGraph*)graph;//取得圖if( tGraph != NULL )//圖不為空{int i = 0;int j = 0;for(i=0; i<tGraph->count; i++){for(j=0; j<tGraph->count; j++){tGraph->matrix[i][j] = 0;//將矩陣數值全設0}}}
}int MGraph_AddEdge(MGraph* graph, int v1, int v2, int w) // 定義添加邊函數
{TMGraph* tGraph = (TMGraph*)graph;//取得圖int ret = (tGraph != NULL);//判斷是否為空ret = ret && (0 <= v1) && (v1 < tGraph->count);//判斷行數是否正常ret = ret && (0 <= v2) && (v2 < tGraph->count);//判斷列數是否正常ret = ret && (0 <= w);//判斷添加的值是否大于等于0if( ret )//條件成功{tGraph->matrix[v1][v2] = w;//將對應行列值修改}return ret;//返回是否成功
}int MGraph_RemoveEdge(MGraph* graph, int v1, int v2) // 定義移除邊函數
{int ret = MGraph_GetEdge(graph, v1, v2);//獲取移除的值if( ret != 0 )//圖不為空{((TMGraph*)graph)->matrix[v1][v2] = 0;//將對應行列值重置0}return ret;//返回移除值
}int MGraph_GetEdge(MGraph* graph, int v1, int v2) // 定義獲取邊函數
{TMGraph* tGraph = (TMGraph*)graph;//獲取圖int condition = (tGraph != NULL);//判斷圖不為空int ret = 0;condition = condition && (0 <= v1) && (v1 < tGraph->count);//判斷行是否正常condition = condition && (0 <= v2) && (v2 < tGraph->count);//判斷列是否正常if( condition ){ret = tGraph->matrix[v1][v2];//獲取對應行列的值}return ret;//返回對應值
}int MGraph_TD(MGraph* graph, int v) // 定義以一個數作為行與列檢測不等于0的值的數量函數
{TMGraph* tGraph = (TMGraph*)graph;//取得圖int condition = (tGraph != NULL);//判斷圖不為空int ret = 0;condition = condition && (0 <= v) && (v < tGraph->count);//判斷v是否在范圍內if( condition ){int i = 0;for(i=0; i<tGraph->count; i++)//如果一個位置的數值有效在行列交叉處會增加兩次{if( tGraph->matrix[v][i] != 0 )//如果以v作為行數將對應行列的值不等于0{ret++;//數量增加}if( tGraph->matrix[i][v] != 0 )//如果以v作為列數將對應行列的值不等于0{ret++;//數量增加}}}return ret;//返回總數
}int MGraph_VertexCount(MGraph* graph) //定義獲取頂點數量
{TMGraph* tGraph = (TMGraph*)graph;int ret = 0;if( tGraph != NULL ){ret = tGraph->count;//取得數量}return ret;
}int MGraph_EdgeCount(MGraph* graph) //定義獲取邊數函數
{TMGraph* tGraph = (TMGraph*)graph;int ret = 0;if( tGraph != NULL ){int i = 0;int j = 0;for(i=0; i<tGraph->count; i++){for(j=0; j<tGraph->count; j++){if( tGraph->matrix[i][j] != 0 )//如果不等于0{ret++;//數量增加}}}}return ret;//返回總數
}//從v行開始遍歷矩陣,visited記錄查看過的行。輸出v行頂點信息,從v行i列開始,只要i列不等于0并且用i值作為行檢測
//i值行沒有看過。就跳到i行查看,此時i作為新v行又從v行i列開始檢測。循環檢測完矩陣每個元素
void MGraph_DFS(MGraph* graph, int v, MGraph_Printf* pFunc)
{TMGraph* tGraph = (TMGraph*)graph;//取得圖int* visited = NULL;int condition = (tGraph != NULL);//圖不為空condition = condition && (0 <= v) && (v < tGraph->count);//v是否在范圍內condition = condition && (pFunc != NULL);//函數指針不為空//判斷新申請的count個int類型是否成功condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL);if( condition ){int i = 0;recursive_dfs(tGraph, v, visited, pFunc);//調用遞歸檢測for(i=0; i<tGraph->count; i++)//如果還有行沒遍歷的,再從該行開始遍歷{if( !visited[i] ){recursive_dfs(tGraph, i, visited, pFunc);}}printf("\n");}free(visited);//釋放用于記錄查看行狀態的空間
}
//從v行開始遍歷,visited記錄查看過的行
//將v行對應頂點信息存進隊列,表示從該行開始遍歷,將v行記錄為已查看,輸出v行頂點信息
//然后從出隊列的行開始遍歷,如果v行i列不等于0并且將i作為行檢測是否查看過
//如果沒有將i作為要遍歷的行進隊列,當前v行檢測完,再從隊列取元素循環同樣操作
void MGraph_BFS(MGraph* graph, int v, MGraph_Printf* pFunc)
{TMGraph* tGraph = (TMGraph*)graph;//取得圖int* visited = NULL;int condition = (tGraph != NULL);condition = condition && (0 <= v) && (v < tGraph->count);condition = condition && (pFunc != NULL);condition = condition && ((visited = (int*)calloc(tGraph->count, sizeof(int))) != NULL);if( condition ){int i = 0;bfs(tGraph, v, visited, pFunc);for(i=0; i<tGraph->count; i++)//如果還有行沒遍歷的,再從該行開始遍歷{if( !visited[i] ){bfs(tGraph, i, visited, pFunc);}}printf("\n");}free(visited);//釋放用于記錄查看行狀態的空間
}
//將矩陣中不為0的數值,將其坐標與數值輸出
void MGraph_Display(MGraph* graph, MGraph_Printf* pFunc) // O(n*n)
{TMGraph* tGraph = (TMGraph*)graph;//取得圖if( (tGraph != NULL) && (pFunc != NULL) )//圖與函數指針不為空{int i = 0;int j = 0;for(i=0; i<tGraph->count; i++)//輸出所有頂點信息{printf("%d:", i);pFunc(tGraph->v[i]);printf(" ");}printf("\n");for(i=0; i<tGraph->count; i++){for(j=0; j<tGraph->count; j++){if( tGraph->matrix[i][j] != 0 )//將矩陣中不等于0的坐標與數據輸出{printf("<");pFunc(tGraph->v[i]);//輸出行printf(", ");pFunc(tGraph->v[j]);//輸出列printf(", %d", tGraph->matrix[i][j]);//輸出對應數據printf(">");printf(" ");}}}printf("\n");}
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include "MGraph.h"void print_data(MVertex* v)
{printf("%s", (char*)v);
}int main(int argc, char *argv[])
{MVertex* v[] = {"A", "B", "C", "D", "E", "F"};MGraph* graph = MGraph_Create(v, 6);MGraph_AddEdge(graph, 0, 1, 1);MGraph_AddEdge(graph, 0, 2, 1);MGraph_AddEdge(graph, 0, 3, 1);MGraph_AddEdge(graph, 1, 5, 1);MGraph_AddEdge(graph, 1, 4, 1);MGraph_AddEdge(graph, 2, 1, 1);MGraph_AddEdge(graph, 3, 4, 1);MGraph_AddEdge(graph, 4, 2, 1);MGraph_Display(graph, print_data);MGraph_DFS(graph, 0, print_data);//輸出:A,B,E,C,F,DMGraph_BFS(graph, 0, print_data);//輸出:A,B,C,D,E,FMGraph_Destroy(graph);getchar();return 0;
}
分析:
匯編: