圖的鄰接表儲存及基本操作
阿新 • • 發佈:2019-01-29
圖的儲存方式有很多種,這裡事宜鄰接表儲存為例實現的。圖的基本操作包括初始化一個空圖、插入一節點、插入條邊、深度優先遍歷、廣度優先遍歷、銷燬圖等
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR -1
#define MAX_VEX 10//最大頂點數
typedef int InfoType;
typedef char VexType;//頂點的型別
typedef int WeightType;//權值的型別
圖的種類(有向圖、無向圖、加權有向圖、加權無向圖),採用列舉法
typedef enum
{
DG = 1, AG, WDG, WAG//有向圖 無向圖 帶權有向圖 帶權無向圖
}GraphKind;
鄰接表的前半部分是順序表,所以定義一個順序表的結構體
typedef struct VexNode
{
VexType data;//頂點的值
int indegree;//頂點的度
LinkNode *firstarc;//指向第一個表節點,有向圖是入度或出度或沒有
}VexNode;//頂點節點型別定義
鄰接表後半部分是連結串列,所以定一個連結串列的結構體
typedef struct LinkNode
{
int adjvex;//鄰接點在頭結點陣列中的位置(下標)
InfoType info;//節點資訊 如權值
struct LinkNode *nextarc;//指向下一個表節點
}LinkNode;
接下來定義圖的結構體
typedef struct
{
GraphKind kind;
int vexnum;//頂點的個數
VexNode AdjList[MAX_VEX];//頭結點的型別的陣列
}ALGraph;
在圖的一系列基本操作中需要佇列的幫助
//佇列的結構體
typedef struct SqQueue
{
VexType array[MAX_VEX];
int front;
int rear;
}SqQueue;
//初始化一個空佇列
SqQueue Creat_SqQueue()
{
SqQueue Q;
Q.front = 0;
Q.rear = 0;
return Q;
}
//入佇列 若成功返回1 否則返回-1
int InsertQueue(SqQueue *Q, VexType e)
{
if ((Q->rear+1)%MAX_VEX == Q->front)
{
printf("The queue is full.\n");
return ERROR;
}
else
{
Q->array[Q->rear] = e;
Q->rear = (Q->rear + 1) % MAX_VEX;
//printf("Insert success!\n\n");
}
return OK;
}
//出佇列 若成功返回彈出的元素 若不成功返回-1
VexType DeletaQueue(SqQueue *Q)
{
VexType e = 0;
if (Q->front == Q->rear)
{
printf("This queue is empty!\n");
return ERROR;
}
else
{
e = Q->array[Q->front];
Q->front = (Q->front + 1) % MAX_VEX;
//printf("Delete success!\n");
}
return e;
}
建立一個空圖
ALGraph CreatGraph() {
ALGraph G;
int i;//迴圈變數
int a = 0;
printf("1.DG\n2.AG\n3.WDG\n4.WAG\n");
printf("please enter the type of graph(according to the code):\n");
scanf("%d", &a);//確定圖的型別
switch (a)
{
case 1:
G.kind = DG;
break;
case 2:
G.kind = AG;
break;
case 3:
G.kind = WDG;
break;
case 4:
G.kind = WAG;
break;
default:
printf("The type of the graph is error\n");
break;
}
G.vexnum = 0;//結點個數置為0
for (i = 0; i < MAX_VEX; i++)//把所有節點的度置為0
{
G.AdjList[i].indegree = 0;
G.AdjList[i].firstarc = NULL;
}
return G;
}
插入節點時需要判斷節點是否在,若不存在插入,如存在插入失敗
//定位節點 若存在返回1 若不存在返回-1
int LocateVex(ALGraph *G, VexType v) {
int i = 0;
int a = 0;
printf("v = %c\n", v);
for (i = 0; i < G->vexnum; i++)
{
if (G->AdjList[i].data == v)
{
a++;
break;
}
}
if (a == 0)
{
return ERROR;
}
return OK;
}
在圖中插入一個節點
void InsertVex(ALGraph *G){
int res = 0;
if (G->vexnum + 1 == MAX_VEX)
{
printf("The graph is overflow!\n");
}
else
{
VexType u = '\0';
printf("please enter data:\n");
getchar();
scanf("%c", &u);
res = LocateVex(G, u);
if (res == -1)//沒有節點 新增
{
G->AdjList[G->vexnum].data = u;
G->AdjList[G->vexnum].firstarc = NULL;
G->vexnum++;
//printf("insert vertex success\n");
}
else
{
printf("insert vertex fail\n");
}
}
}
在圖中插入一條邊時,要判斷圖的型別,不同的型別,插入操作是不一樣的
void InsertArc(ALGraph *G) {
if (G->kind == DG)//有向圖
{
LinkNode *p;
LinkNode *r;
int tail = 0;//弧尾(起點)
int head = 0;//弧頭(終點)
p = (LinkNode *)malloc(sizeof(LinkNode));
printf("please enter the tail:");
scanf("%d", &tail);
printf("please enter the head:");
scanf("%d", &head);
if (tail < G->vexnum && head < G->vexnum)
{
p->adjvex = head;
p->nextarc = NULL;
p->info = 0;
r = G->AdjList[tail].firstarc;
p->nextarc = r;
G->AdjList[tail].firstarc = p;
G->AdjList[tail].indegree++;
printf("insert arc success\n");
}
else
{
printf("vertex is not exit.");
}
}
else if(G->kind == AG)//無向圖
{
LinkNode *p;
LinkNode *q;
LinkNode *r;
LinkNode *s;
int tail = 0;
int head = 0;
p = (LinkNode *)malloc(sizeof(LinkNode));
q = (LinkNode *)malloc(sizeof(LinkNode));
s = (LinkNode *)malloc(sizeof(LinkNode));
printf("please enter the tail:");
scanf("%d", &tail);
printf("please enter the head:");
scanf("%d", &head);
if (tail < G->vexnum && head < G->vexnum)
{
p->adjvex = head;
p->info = 0;
p->nextarc = NULL;
r = G->AdjList[tail].firstarc;
p->nextarc = r;
G->AdjList[tail].firstarc = p;
s->adjvex = tail;
s->info = 0;
q = G->AdjList[head].firstarc;
s->nextarc = q;
G->AdjList[head].firstarc = s;
G->AdjList[tail].indegree++;
G->AdjList[head].indegree++;
printf("insert arc success\n");
}
else
{
printf("vertex is not exit.\n");
}
}
else if (G->kind == WDG)//加權有向圖
{
LinkNode *p;
LinkNode *r;
int info = 0;
int tail = 0;//弧尾(起點)
int head = 0;//弧頭(終點)
p = (LinkNode *)malloc(sizeof(LinkNode));
printf("please enter the tail:");
scanf("%d", &tail);
printf("please enter the head:");
scanf("%d", &head);
printf("please enter the information:");
scanf("%d", &info);
if (tail < G->vexnum && head < G->vexnum)
{
p->adjvex = head;
p->nextarc = NULL;
p->info = info;
r = G->AdjList[tail].firstarc;
p->nextarc = r;
G->AdjList[tail].firstarc = p;
G->AdjList[tail].indegree++;
printf("insert arc success\n");
}
else
{
printf("vertex is not exit.\n");
}
}
else if(G->kind == WAG)//加權無向圖
{
LinkNode *p;
LinkNode *q;
LinkNode *r;
LinkNode *s;
int info = 0;
int tail = 0;
int head = 0;
p = (LinkNode *)malloc(sizeof(LinkNode));
q = (LinkNode *)malloc(sizeof(LinkNode));
s = (LinkNode *)malloc(sizeof(LinkNode));
printf("please enter the tail:");
scanf("%d", &tail);
printf("please enter the head:");
scanf("%d", &head);
printf("please enter the information:");
scanf("%d", &info);
if (tail < G->vexnum && head < G->vexnum)
{
p->adjvex = head;
p->nextarc = NULL;
p->info = info;
r = G->AdjList[tail].firstarc;
p->nextarc = r;
G->AdjList[tail].firstarc = p;
s->adjvex = tail;
s->info = info;
q = G->AdjList[head].firstarc;
s->nextarc = q;
G->AdjList[head].firstarc = s;
G->AdjList[tail].indegree++;
G->AdjList[head].indegree++;
printf("insert arc success\n");
}
else
{
printf("vertex is not exit.\n");
}
}
else
{
printf("The type of the graph is error\n");
}
}
圖的深度優先遍歷
void DFSTraverse(ALGraph *G, int v, int visit[]) {
LinkNode *p;
if (visit[v] == 0)
{
printf("%c\n", G->AdjList[v].data);
visit[v] = 1;
p = G->AdjList[v].firstarc;
while (p != NULL)
{
if (visit[p->adjvex] == 0)
{
DFSTraverse(G, p->adjvex, visit);
}
p = p->nextarc;
}
}
}
圖的廣度優先遍歷
void BFSTraverse(ALGraph *G){
int i = 0;//迴圈變數
int k = 0;//迴圈變數
SqQueue Q = Creat_SqQueue();
//visited為訪問標誌陣列,為0則該節點沒被訪問過,為1則被訪問過
int visited[MAX_VEX];
LinkNode *p;
for (i = 0; i < MAX_VEX; i++)//訪問標誌初始化
{
visited[i] = 0;
}
//廣度優先遍歷圖
for (k = 0; k < G->vexnum; k++)
{
if (visited[k] == 0)//若該節點沒有被訪問過
{
InsertQueue(&Q, k);
visited[k] = 1;
if (G->AdjList[k].firstarc != NULL)
{
p = G->AdjList[k].firstarc;
while (p != NULL)
{
if(visited[p->adjvex] == 0)
{
InsertQueue(&Q, p->adjvex);
visited[p->adjvex] = 1;
}
p = p->nextarc;
}
}
}
else//若該節點被訪問過
{
if (G->AdjList[k].firstarc != NULL)
{
p = G->AdjList[k].firstarc;
while (p != NULL)
{
if(visited[p->adjvex] == 0)
{
InsertQueue(&Q, p->adjvex);
visited[p->adjvex] = 1;
}
p = p->nextarc;
}
}
}
}
while (Q.front != Q.rear)//迴圈彈出佇列中的元素
{
printf("%c\n", G->AdjList[DeletaQueue(&Q)].data);
}
}
銷燬一個圖
int DestroyGeaph(ALGraph *G) {
int i = 0;//迴圈變數
for (i = 0; i < G->vexnum; i++)
{
G->AdjList[i].data = 0;
G->AdjList[i].indegree = 0;
G->AdjList[i].firstarc = NULL;
}
G->vexnum = 0;
return OK;
}
以鄰接表的形式輸出圖
void OutPutGraph(ALGraph G)
{
int i = 0;//迴圈變數
printf("value\tindegree\tfirstarc\n");
for (i = 0; i < G.vexnum; i++)
{
printf("%c\t", G.AdjList[i].data);
printf("%d\t\t", G.AdjList[i].indegree);
LinkNode *p;
p = G.AdjList[i].firstarc;
while (p != NULL)
{
printf("->");
printf("%c \t", G.AdjList[p->adjvex].data);
p = p->nextarc;
}
printf("\n");
printf("----------------------\n");
}
}
示例:
執行結果:
以上就是圖的基本操作了,主方法就不寫了,大家根據可以自己的需要寫,希望大家看了以後能幫得上忙。