第五章.圖基本算法

一.圖的存儲結構

1. 鄰接矩陣(順序存儲結構)

typedef struct
{
	int no; //頂點編號
	char info; //頂點其他信息
}VertexType; //頂點類型
typedef struct
{
	int edges[maxSize][maxSize]; //鄰接矩陣定義
	int n,e; //分別爲頂點數和邊數
	VertexType vex[maxSize]; //存放結點信息
}MGraph; //圖的鄰接矩陣類型

2. 鄰接表(鏈式存儲結構)

typedef struct ArcNode
{ //邊結點表
	int adjvex; //該邊所指向的結點的位置
	struct ArcNode *nextarc; //指向下一條邊的指針
	int info; //該邊的相關信息
}ArcNode;
typedef struct
{ //頂點表
	char data; //頂點信息
	ArcNode *firstarc; //指向第一條邊的指針
}VNode;
typedef struct
{
	VNode adjlist[maxSize]; //鄰接表
	int n,e; //頂點數和邊數
}AGraph; //圖的鄰接表類型

二.圖的遍歷算法

1. DFS深度優先搜索遍歷
算法執行過程:任取一個頂點,訪問之,然後檢查這個頂點的所有鄰接頂點,遞歸訪問其中未被訪問過的頂點。

int visit[maxSize];
/* v是起點編號,visit[]是一個全局數組,作爲頂點的訪問標記,初始時所有元素*/
/* 均爲0,表示所有頂點都未被訪問過。因圖中可能存在迴路,當前經過的頂點在將*/
/* 來還可能再次經過,所以要對每個頂點進行標記,以免重複訪問*/
void DFS(AGraph *G,int v)
{
	ArcNode *p;
	visit[v] = 1; //置已訪問標記
	Visit(v); 
	p = G->adjlist[v].firstarc; //p指向頂點v的第一條邊
	while(p != NULL)
	{
		if(visit[p->adjvex] == 0) //若頂點未訪問,則遞歸訪問它
			DFS(G,p->adjvex);
		p = p->nextarc; //p指向頂點v的下一條邊的終點
	}
}

2. BFS廣度優先搜索遍歷
算法執行過程:
1). 任取圖中一個頂點訪問,入隊,並將這個頂點標記爲已訪問
2). 當隊列不空時循環執行:出隊,依次檢查出隊結點的所有鄰接頂點,訪問沒有被訪問過的鄰接頂點並將其入隊
3). 當隊列爲空時跳出循環,廣度優先搜索即完成

void BFS(AGraph *G,int v,int visit[maxSize])
{ //visit[]數組被初始化爲全0
	ArcNode *p;
	int que[maxSize];
	int front = 0,rear = 0;
	int j;
	Visit(v);
	visit[v] = 1;
	rear = (rear + 1) % maxSize;
	que[rear] = v;
	while(front != rear) //隊空的時候說明遍歷完成
	{
		front = (front + 1) % maxSize; //頂點出隊
		j = que[front];
		p = G->adjlist[j].firstarc; //p指向出隊頂點j的第一條邊
		while(p != NULL)
		{
			if(visit[p->adjvex] == 0) //當前鄰接頂點未被訪問,則入隊
			{
				Visit(p->adjvex);
				visit[p->adjvex] = 1;
				rear = (rear + 1) % maxSize; //該頂點入隊
				que[rear] = p->adjvex;
			}
			p = p->nextarc; //p指向j的下一條邊
		}
	}
}

3.
在這裏插入圖片描述
在這裏插入圖片描述

int BFS(AGraph *G,int v)
{
	/*本題用鄰接表作爲圖的存儲結構*/
	ArcNode *p;
	int que[maxSize],front = 0,rear = 0;
	int visit[maxSize];
	int i,j;
	for(i=0;i<G->n;++i)
		visit[i] = 0; //將visit數組全部初始化爲0
	rear = (rear + 1) % maxSize;
	que[rear] = v;
	visit[v] = 1;
	while(front != rear)
	{
		front = (front + 1) % maxSize;
		j = que[front];
		p = G->adjlist[j].firstarc;
		while(p != NULL)
		{
			if(visit[p->adjvex] == 0)
			{
				visit[p->adjvex] = 1;
				rear = (rear + 1) % maxSize;
				que[rear] = p->adjvex;
			}
			p = p->nextarc;
		}
	}
	return j; //隊空時,j保存了遍歷過程中的最後一個頂點
}

4.
在這裏插入圖片描述

void DFS(AGraph *G,int v,int &vn,int &en)
{
	ArcNode *p;
	visit[v] = 1;
	++vn; //本題中對當前頂點的訪問即爲vn計數器自增1
	p = G->adjlist[v].firstarc;
	while(p != NULL)
	{
		++en; //邊數自增1
		if(visit[p->adjvex] == 0)
			DFS(G,p->adjvex,vn,en);
		p = p->nextarc;
	}
}
int GisTree(AGraph *G)
{
	int vn = 0,en = 0;
	for(i=0;i<G->n;++i)
		visit[i] = 0;
	DFS(G,1,vn,en);
	if(vn == G->n && (G->n-1) == en/2) //在每次來到一個新頂點,en累加了當前訪問頂點的所有邊,也就是說每條邊訪問了兩次
	/*如果遍歷過程中訪問過的頂點數和圖中的頂點數相等,且邊數等於頂點數減1,則證明是樹*/
		return 1;
	else
		return 0;
}

5.
在這裏插入圖片描述

int DFSTrave(AGraph *G,int i,int j)
{
	int k;
	for(k=0;k<G->n;++k)
		visit[k] = 0;
	DFS(G,i);
	if(visit[j] == 1) //visit[j]等於1則證明訪問過程中遇到了j
		return 1;
	else
		return 0;
}

三.最小生成樹

1.普里姆算法
在這裏插入圖片描述
在這裏插入圖片描述

void Prim(MGraph g,int v0,int &sum)
{
	int lowcost[maxSize],vset[maxSize],v;
	int i,j,k,min;
	v = v0;
	for(i=0;i<g.n;++i)
	{
		lowcost[i] = g.edges[v0][i]; //頂點v0到其餘各定點的長度
		vset[i] = 0; //vset全部置爲0
	}
	vset[v0] = 1; //將v0併入樹中
	sum = 0; //sum清零用來累計樹的權值
	for(i=0;i<g.n-1;++i) //循環n-1次
	{
		min = INF;
		/*下面這個循環用於選出侯選邊中的最小值*/
		for(j=0;j<g.n;++j)
		{
			if(vset[j] == 0 && lowcost[j] < min) //選出當前生成樹到其餘各頂點最短邊中的最短的一條
			{
				min = lowcost[j];
				k = j;
			}
		}
		vset[k] = 1;
		v = k;
		sum += min; //這裏用sum記錄了最小生成樹的權值
		/*下面這個循環以剛併入的頂點v爲媒介更新候選邊*/
		for(j=0;j<g.n;++j)
		{
			if(vset[j] == 0 && g.edges[v][j] < lowcost[j]) //併入生成樹的頂點無需更新
				lowcost[j] = g.edges[v][j];
		}
	}
}

2.克魯斯卡爾算法

typedef struct
{
	int a,b; //a,b爲一條邊所連的兩個頂點
	int w; //邊的權值
}Road;
Road road[maxSize];
int v[maxSize]; //定義並查集數組
int getRoot(int a)
{
	while(a != v[a])
		a = v[a];
	return a;
}
void Kruskal(MGraph g,int &sum,Road road[])
{
	int i;
	int N,E,a,b;
	N = g.n; //頂點數
	E = g.e; //邊數
	sum = 0;
	for(i=0;i<N;++i)
		v[i] = i;
	sort(road,E); //對road數組中的E條邊按其權值從小到大排序
	for(i=0;i<E;++i)
	{
		a = getRoot(road[i].a);
		b = getRoot(road[i].b);
		if(a != b)
		{
			v[a] = b; //把b賦值給a,即將b作爲a的父結點
			sum += road[i].w;
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章