對於比較稠密的圖,通常采用鄰接矩陣來表示,如下左圖所示,無權的路徑通常用1表示兩點有連接,0表示沒有連接,若是加權圖,則把1改成權重就好,如下右圖。

鄰接表結構用來表示稀疏的圖,圖的拓撲排序是指按每一個頂點的入度來對頂點進行排序,無權最短路徑指的是所有路徑的權重都是1,求某一點到另外一點的最短路徑
下述程序用的圖及對應的鄰接表如下所示,其中加權圖9-20每條邊的方向還是按圖9-1的方向。



// Graph.cpp : 定義控制台應用程序的入口點。
//
#include "stdafx.h"
#include<iostream>
#include<queue>
using namespace std;
typedef int Vertex;
#define NotAVertex 0
#define INF 65536
//定義鏈表節點////////////////////////////////////
typedef struct TreeNode *Position;
struct TreeNode {
int vertex;
int weight;
Position Next;
};
//定義鄰接表結構/////////////////////////////////////
typedef struct adjaceency_list *adjaceency;
struct adjaceency_list {
int numVertex; //大小
Position* table; //表地址
};
//鄰接表初始化函數////////////////////////////////////
adjaceency initAdjaceency_list(int numVertex)
{
//申請一個鄰接表地址,給鄰接表賦初值
adjaceency adja = (adjaceency)malloc(sizeof(adjaceency_list));
adja->numVertex = numVertex;
if (adja == NULL)
cout << "Error";
//申請一個table地址
adja->table = (Position*)malloc(sizeof(Position)*(adja->numVertex+1));
if (adja->table == NULL)
cout << "Error";
//給鄰接表每一個表項添加一個鏈表表頭
for (int i = 1; i <= adja->numVertex; i++) {
adja->table[i] = (Position)malloc(sizeof(TreeNode));
if (adja->table[i] == NULL)
cout << "Error";
else {
adja->table[i]->vertex = i;
adja->table[i]->weight = 0; //給每個鄰接表項的鏈表頭的權重設為0
adja->table[i]->Next = NULL;
}
}
return adja;
}
//鄰接表的插入函數,制定一個頂點per_ver,把鄰接的頂點aft_ver插入其后//////////////////////////////////
void Insert(adjaceency adja, Vertex per_ver, Vertex aft_ver, int weight)
{
//申請一個鏈表節點地址
Position inser = (Position)malloc(sizeof(TreeNode));
if (inser == NULL)
cout << "Error";
//從頭插入,修改指針
inser->vertex = aft_ver;
inser->weight = weight; //從per_ver指向aft_ver的權重
inser->Next = adja->table[per_ver]->Next;
adja->table[per_ver]->Next = inser;
}
//計算每個頂點入度的函數//////////////////////////////////////
void findIndegree(adjaceency adja)
{
//用表頭來存儲入度,先給每個表頭賦初值0
for (int i = 1; i <= adja->numVertex; i++) adja->table[i]->vertex = 0;
//從鄰接表表項1-N遍歷,每一項又由鏈表遍歷,鏈表遍歷時遇到某頂點就把某頂點對應的表頭加1
for (int i = 1; i <= adja->numVertex; i++)
{
Position p = adja->table[i]->Next;
while (p != NULL) {
adja->table[p->vertex]->vertex++;
p = p->Next;
}
}
}
//圖的拓撲排序///////////////////////////////////
int* Topsort(adjaceency adja)
{
//用隊列來存放入度為0的頂點
queue<Vertex> que;
int counter = 0;
//申請一個數組來存放頂點的次序,如TopNum[1]=6代表1號頂點排在第6位
int *TopNum = (int*)malloc(sizeof(int)*(adja->numVertex + 1));
for (int i = 1; i <= adja->numVertex; i++) TopNum[i] = 0;
//先檢查初始入度為0的頂點並入隊
for (Vertex ver = 1; ver <= adja->numVertex; ver++)
if (adja->table[ver]->vertex == 0)
que.push(ver);
while (!que.empty())
{
//按出隊順序來決定頂點的拓撲排序
Vertex v = que.front();
que.pop();
TopNum[v] = ++counter;
//去掉該頂點后與該頂點鄰接的點的入度減一
Position p = adja->table[v]->Next;
while (p != NULL)
{
if (--adja->table[p->vertex]->vertex == 0) //檢查p->vertex的入度是否為0,為0入隊
que.push(p->vertex);
p = p->Next;
}
}
//檢查有沒有圈
if (counter != adja->numVertex)
cout << "Graph has a cycle";
return TopNum;
}
//打印鄰接表//////////////////////////////////////////
void print(adjaceency adja)
{
cout << "Vertex"<<endl;
for (int i = 1; i <= adja->numVertex; i++)
{
Position p = adja->table[i];
while (p != NULL) {
cout << p->vertex << '\t';
p = p->Next;
}
cout << endl;
}
cout << endl;
}
//定義用於無權最短路徑的表的表項結構//////////////////////////////////////
typedef struct routeTable *route;
struct routeTable
{
Vertex ver;
bool Know;
int Dist;
int Path;
};
//初始化用於無權最短路徑的表,並申請一片表空間///////////////////////////
route initRouteTable(int numVertex,Vertex start)
{
route Route = (route)malloc(sizeof(routeTable)*(numVertex + 1));
for (Vertex ver = 1; ver <= numVertex; ver++)
{
Route[ver].ver = ver;
Route[ver].Know = false;
Route[ver].Dist = INF;
Route[ver].Path = 0;
}
//起始點的距離設為0;
Route[start].Dist = 0;
return Route;
}
//無權最短路徑算法1,時間復雜度較高////////////////////////////
void Unweighted(route Route, adjaceency adja)
{
int CurrDist;
for(CurrDist=0;CurrDist<adja->numVertex;CurrDist++)
for(Vertex ver=1;ver<= adja->numVertex;ver++)
if (!Route[ver].Know&&Route[ver].Dist == CurrDist)
{
//Route[ver].Dist == CurrDist,則找到指定距離的點
Route[ver].Know = true;
//把與該點鄰接的所有點在該點上的距離加1,以便於下次循環能找到這些點
Position p = adja->table[ver]->Next;
while (p)
{
if (Route[p->vertex].Dist == INF)
{
Route[p->vertex].Dist = CurrDist + 1;
Route[p->vertex].Path = ver;
}
p = p->Next;
}
}
}
//無權最短路徑算法2,時間復雜度較低,用隊列實現////////////////////////////
void Unweighted2(route Route, adjaceency adja, Vertex start)
{
//先把第一個點入隊
queue<Vertex> que;
que.push(start);
while (!que.empty())
{
//按距離長短出隊,距離越晚出隊越晚
Vertex ver = que.front();
que.pop();
Route[ver].Know = true;
//從起點的臨接點找起,然后把鄰接點入隊,再找鄰接點的鄰接點,如此循環
Position p = adja->table[ver]->Next;
while (p)
{
if (Route[p->vertex].Dist == INF)
{
//設置鄰接點的表項,鄰接點的距離等於該點的距離加1。
Route[p->vertex].Dist = Route[ver].Dist + 1;
Route[p->vertex].Path = ver;
//鄰接點入隊
que.push(p->vertex);
}
//指向下一個鄰接點
p = p->Next;
}
}
}
//打印無權最短路徑的表////////////////////////////////////////////
void printRouteTable(route Route, int numVertex)
{
cout << "Vertex\tKnow\tDist\tPath\t" << endl;
for (Vertex ver = 1; ver <= numVertex; ver++)
{
//按行打印無權最短路徑的表
cout << Route[ver].ver << '\t' << Route[ver].Know << '\t' << Route[ver].Dist << '\t' << Route[ver].Path << endl;
}
cout << endl;
}
//打印從start到某點end的路線/////////////////////////////////////////////
void printRoute(route Route, Vertex start, Vertex end)
{
if (end == start)
cout << start << '\t';
else
{
printRoute(Route, start, Route[end].Path);
cout << Route[end].ver<<'\t';
}
}
//加權最短路徑算法表///////////////////////////////////////////////////////////
typedef struct TableEntry *WeightTable;
struct TableEntry
{
adjaceency adja;
bool Know;
int Dist;
Vertex Path;
};
//加權最短路徑算法表初始化函數////////////////////////////////////////////////
WeightTable InitTable(Vertex start, adjaceency adja)
{
WeightTable weightTable = (WeightTable)malloc(sizeof(TableEntry)*(adja->numVertex + 1));
for (int i = 1; i <= adja->numVertex; i++)
{
weightTable[i].Know = false;
weightTable[i].Dist = INF;
weightTable[i].Path = NotAVertex;
}
weightTable[start].Dist = 0; //只有起點的距離設為0,其他設為無窮
return weightTable;
}
//尋找距離最近的未知節點的函數,這里用的方法是掃描整個表,看哪個距離最近,
//但時間復雜度較高,可以用有限隊列的deleteMin()來實現,時間復雜度較小。
Vertex smallest_dist_vertec(WeightTable weightTable, adjaceency adja)
{
int temp=INF;
Vertex minver=NotAVertex;
for(int ver=1;ver<=adja->numVertex;ver++)
if (!weightTable[ver].Know&&temp > weightTable[ver].Dist)
{
temp = weightTable[ver].Dist;
minver = ver;
}
return minver;
}
//計算最短加權的函數////////////////////////////////////////////////////
void Dijkstra(WeightTable weightTable, adjaceency adja)
{
for (;;)
{
//循環結束的條件沒有未知的點
Vertex smallest_ver = smallest_dist_vertec(weightTable, adja);
if (smallest_ver == NotAVertex)
break;
weightTable[smallest_ver].Know = true;
//得到未知的最近的點V后,令p逐一指向V的所有鄰接點W,更新所有鄰接點的距離。
//這里要注意的是由於是從最近節點一層一層往下找的,所以每一個w的距離最多只更新一次
Position p = adja->table[smallest_ver]->Next;
while (p)
{
if (!weightTable[p->vertex].Know)
if (weightTable[smallest_ver].Dist + p->weight < weightTable[p->vertex].Dist)
{
weightTable[p->vertex].Dist = weightTable[smallest_ver].Dist + p->weight;
weightTable[p->vertex].Path = smallest_ver;
}
p = p->Next;
}
}
}
//打印最短加權路徑表的函數//////////////////////////////////////////
void printWeightTable(WeightTable weightTable, adjaceency adja)
{
cout << "Vertex\tKnow\tDist\tPath\t" << endl;
for (Vertex ver = 1; ver <= adja->numVertex; ver++)
{
//按行打印加權最短路徑的表
cout << ver << '\t' << weightTable[ver].Know << '\t' << weightTable[ver].Dist << '\t' << weightTable[ver].Path << endl;
}
cout << endl;
}
int main()
{
//初始化鄰接表////////////////////////////////////////
adjaceency adja = initAdjaceency_list(7);
Insert(adja, 1, 3, 4); Insert(adja, 1, 4, 1); Insert(adja, 1, 2, 2);
Insert(adja, 2, 5, 10); Insert(adja, 2, 4, 3);
Insert(adja, 3, 6, 5);
Insert(adja, 4, 3, 2); Insert(adja, 4, 7, 4); Insert(adja, 4, 6, 8);
Insert(adja, 5, 7, 6); Insert(adja, 5, 4, 2);
Insert(adja, 7, 6, 1);
print(adja);
//檢查每一個頂點的入度////////////////////////////////////
findIndegree(adja);
for (int i = 1; i <= adja->numVertex; i++)
cout << i<<"入度:"<< adja->table[i]->vertex<<"\t\t";
cout << endl;
//按拓撲排序打印輸出//////////////////////////////////////
int* TopNum = Topsort(adja);
for (Vertex ver = 1; ver <= adja->numVertex; ver++)
adja->table[ver]->vertex = ver;
int start;
for (Vertex ver = 1; ver <= adja->numVertex; ver++)
{
cout << TopNum[ver] << '\t';
//找圖的起點
if (TopNum[ver] == 1)
start = ver;
}
cout << endl;
//求無權最短路徑表/////////////////////////////////////
route Route = initRouteTable(adja->numVertex, start);
printRouteTable(Route, adja->numVertex);
//Unweighted(Route, adja);
Unweighted2(Route, adja, start);
printRouteTable(Route, adja->numVertex);
printRoute(Route, start, adja->numVertex);
cout << endl;
//求加權最短路徑表/////////////////////////////////////
WeightTable weightTable = InitTable(start, adja);
Dijkstra(weightTable, adja);
printWeightTable(weightTable, adja);
while (1);
return 0;
}

