圖的簡述:
圖是一種複雜的數據結構,圖(Graph)是由頂點(Vertex)組成的非空有窮集合和頂點之間的邊(Edge)組成。
圖的邊可以由權值(weight),也可以沒有,有權值的圖稱爲網圖。
圖的邊也可以有方向,沒有方向的爲無向圖,有方向的爲有向圖。
圖很複雜,就需要複雜的方式來表示圖,一般簡單的使用鄰接矩陣和鄰接表來表示,還有十字鏈表和鄰接多重表等,這裏只介紹前兩種的實現。
無向圖的鄰接矩陣結構表示:
鄰接矩陣簡單也方便理解,即用一個一維數組儲存頂點,用另一個二維數組儲存各個頂點之間的邊的信息。
無向圖的鄰接矩陣是一個對稱矩陣,即arc[i][j]=arc
C++實現:
typedef char VertexType; //頂點類型 ,默認爲char
typedef int EdgeType; //邊的權值 默認int
#define MAXVERTEX 100 //最大的頂點數
//鄰接矩陣的結構
typedef struct MGraph
{
VertexType vexs[MAXVERTEX]; //頂點數組
EdgeType arc[MAXVERTEX][MAXVERTEX]; //鄰接矩陣 即邊數組
int vertexNum; //頂點數
int edgeNum; //邊數
};
無向鄰接矩陣的深度優先遍歷:
深度優先所搜(DepthFirstSearch)表示用某種規則把一個頂點所連接的後面頂點都遍歷一遍,並用一個標識符來表示是否遍歷過該節點。特點是不放過任何一個節點。從一個節點出發,遍歷所有未訪問的節點,結束後如果遍歷完後仍有節點未被訪問,則換一個節點作爲起始點,重複此步驟直至所有節點都被訪問。
bool visited[MAXVERTEX];
//深度優先遍歷鄰接矩陣
void DFSTraverse(MGraph G)
{
int i;
for (i = 0; i < G.vertexNum; i++)
{
visited[i] = false;
}
for (i = 0; i < G.vertexNum; i++)
{
if (visited[i] != true)
{
DepthFirstSearch(G, i); //如果該頂點延伸出去所有頂點都訪問過,則訪問下一個頂點
}
}
}
DepthFirstSearch函數用遞歸實現:
//深度優先搜索鄰接矩陣
void DepthFirstSearch(MGraph G,int i)
{
int j;
visited[i] = true; //把該頂點標識符置爲true
cout << G.vexs[i]; //遍歷到後打印該頂點
for (j = 0; j < G.vertexNum; j++)
{
if (G.arc[i][j] == 1 && visited[j] != true)
{
DepthFirstSearch(G, j); //遞歸遍歷未訪問的節點直到沒有
}
}
}
無向鄰接矩陣的廣度優先遍歷:
//廣度優先遍歷鄰接矩陣
void BFSTraverse(MGraph G)
{
int i, j;
queue<VertexType> q; //臨時隊列
for (i = 0; i < G.vertexNum; i++)
{
visited[i] = false;
}
for (i = 0; i < G.vertexNum; i++)
{
if (!visited[i])
{
visited[i] = true; //標識符設爲true
cout << G.vexs[i]; //遍歷到該頂點,打印頂點
q.push(G.vexs[i]); //入隊
while (q.empty() != true) //如果隊列不爲空
{
q.pop();
for (j = 0; j < G.vertexNum; j++)
{
if (G.arc[i][j] == 1 && !visited[j])
{
visited[j] = true;
cout << G.vexs[j]; //遍歷並打印
q.push(G.vexs[j]);
}
}
}
}
}
}
無向圖的鄰接表結構表示:
鄰接表類似於鏈表,存在頂點節點和邊節點,用頂點節點的指針指向該頂點所連接的邊節點。
//鄰接表的結構
typedef struct EdgeNode //邊表節點
{
int adjvex; //該鄰接點對應的頂點下標
EdgeType weight; //頂點到該鄰接點的權值
EdgeNode *Next; //指向頂點的下一個鄰接點
};
typedef struct VertexNode //頂點表節點
{
VertexType data; //頂點節點及信息
EdgeNode *firstEdge; //邊表頭指針,指向頂點的第一個邊表
}AdjList[MAXVERTEX];
typedef struct GraphAdjList //鄰接表
{
AdjList adjList; //頂電錶數組
int vertexNum; //頂點數
int EdgeNum; //邊數
};
無向網圖鄰接表的創建:
//無向圖的鄰接表的創建
void CreateALGraph(GraphAdjList *G)
{
int i, j, k;
EdgeNode *e;
cout << "輸入頂點數和邊數:";
cin >> G->vertexNum >> G->EdgeNum; //讀入頂點數和邊數
//創建頂點表
for (i = 0; i < G->vertexNum; i++)
{
cin >> G->adjList[i].data; //讀入頂點節點信息
G->adjList[i].firstEdge = NULL; //邊表初始化爲NULL表
}
//創建邊表
for (k = 0; k < G->EdgeNum; k++)
{
cout << "輸入邊(vi,vj)上的頂點序號:" << endl;
cin >> i >> j; //讀入邊的頂點序號
e = new EdgeNode(); //生成邊表節點
//無向圖,所以一條邊對應兩個節點i和j
//頭插法
e->adjvex = j; //鄰接點下標爲j
e->Next = G->adjList[i].firstEdge; //e指向G的firstedge
G->adjList[i].firstEdge = e; //firstEdge指向該邊節點
e = new EdgeNode();
e->adjvex = i;
e->Next = G->adjList[j].firstEdge;
G->adjList[j].firstEdge = e;
}
}
無向鄰接表的深度優先遍歷:
和鄰接矩陣的遍歷很相似
//深度優先遍歷鄰接表
void DepthFirstSearchAdjList(GraphAdjList GAL, int i)
{
EdgeNode *e;
visited[i] = true; //標識符設爲true
cout << GAL.adjList[i].data; //遍歷到後打印頂點信息
e = GAL.adjList[i].firstEdge;
while (e)
{
if (!visited[e->adjvex])
{
DepthFirstSearchAdjList(GAL, e->adjvex); //遞歸遍歷未訪問的鄰接點
}
e = e->Next;
}
}
//深度優先搜索鄰接表
void DFSTraverse(GraphAdjList GAL)
{
int i;
for (i = 0; i < GAL.vertexNum; i++)
{
visited[i] = false;
}
for (i = 0; i < GAL.vertexNum; i++)
{
if (!visited[i])
{
DepthFirstSearchAdjList(GAL, i);
}
}
}
無向鄰接表的廣度優先遍歷:
//廣度優先遍歷鄰接表
void BFSTraverse(GraphAdjList GAL)
{
int i;
EdgeNode *p;
queue<int> q;
for (i = 0; i < GAL.vertexNum; i++)
{
visited[i] = false;
}
for (i = 0; i < GAL.vertexNum; i++)
{
if (!visited[i])
{
visited[i] = true;
cout << GAL.adjList[i].data<< endl;
q.push[GAL.adjList[i]];
while (q.empty() != true)
{
q.pop();
p = GAL.adjList[i].firstEdge;
while (p)
{
if (!visited[p->adjvex])
{
visited[p->adjvex] = true;
cout << GAL.adjList[p->adjvex].data;
q.push(p->adjvex);
}
p = p->Next;
}
}
}
}
}