最近忙於做數據結構的作業,因此想要總結一下自己在寫代碼時遇到的一些困難,c++可能不能順利總結了嗚嗚嗚~ 就從最近的事情開始吧。
【任務描述】
擴充深度優先搜索算法,在遍歷圖的過程中建立生成森林的左子女-右兄弟鏈表。
【想法】
首先得出這個結構為一個樹的結構,然后思考這個樹應該用什么樣的結構來存儲呢?
任務里給出答案——鏈表,當然在圖的章節里還有鄰接矩陣的數據結構,但拿來存圖卻有時顯得浪費,因此個人推薦用鏈表來生成一個森林。
閑話少說,讓我們開始完成這個任務吧~
第一步:
建立結構:
由於要生成森林,同時使用圖的鄰接表來存儲圖,因此有兩部分結構
圖:
#define MAXMIZE 20
//創建圖的鄰接表結構 typedef struct ArcNode { int adjvex;//邊指向的頂點位置 struct ArcNode *nextarc=NULL;//指向下一條邊的指針 int *info;//該邊相關信息的指針 }ArcNode; typedef struct VNode { int data;//頂點信息 ArcNode *firstarc;//指向第一條依附該頂點的邊的指針 }VNode,AdjList[MAXMIZE]; typedef struct{ AdjList vertices;//可以間接使用數組 int vexnum,arcnum;//頂點,邊 }ALGraph;
由於樹是左子女-右兄弟,因此要對之前的二叉樹做一個小小的改動:
//創建一個樹的左子女,右兄弟結構 typedef struct node { int data; node *firstChild=NULL; node *nextSibling=NULL; }TreeNode,*BinTree;
那么這樣結構就出來了~
第二步:
建立一個圖
話不多說,直接上代碼:
//按照圖的結構創建鄰接表表示的圖 void creatGraph(ALGraph &G) { cout << "請輸入圖的頂點數目:" ; cin >> G.vexnum ;//ok cout << "請輸入圖的邊的數目:" ; cin >> G.arcnum ;//ok cout << "頂點賦值:" ; for(int i=1;i<=G.vexnum;i++) { cin >> G.vertices[i].data; G.vertices[i].firstarc=NULL;//ok } for(int j=1;j<=G.arcnum;j++)//創建領接表,每一條邊 { int point1,point2; cout << "邊賦值:" ; cin>> point1 >> point2 ; ArcNode *a1 = new ArcNode;//創建新邊,從1到2 a1->adjvex=point2; a1->nextarc=G.vertices[point1].firstarc; G.vertices[point1].firstarc=a1; ArcNode *a2 = new ArcNode;//創建新邊,從2到1 a2->adjvex=point1; a2->nextarc=G.vertices[point2].firstarc; G.vertices[point2].firstarc=a2; } cout << endl; } //銷毀圖 void Destroy(ALGraph &G) { for(int i=1;i<=G.vexnum;i++) { G.vertices[i].firstarc->nextarc=NULL; } cout << "銷毀成功!" << endl; }
這部分還是比較簡單的,那么讓我們大家頭疼的自然是第三步:生成一棵樹。
看到這里大家不禁會問:題目說的生成森林,那你這一棵樹有什么用呢?
不知道大家注意到沒有:左子女-右兄弟這種類型的樹,正好就是用來存儲森林的最好方式!
由於右面用來存儲兄弟,而根節點顯然沒有兄弟,那么我們正好可以將另一個樹連接到這個樹的右兄弟空着的節點上去,看起來非常巧妙對不對!
那么我們還是,直接上代碼!
void Dfs(ALGraph G,int i,BinTree &T) { visited[i]=1; bool first=true;//表示是否為當前節點第一個孩子 TreeNode *locat;//同樣是定位作用 while(G.vertices[i].firstarc!=NULL)//從此節點出發,訪問鄰接節點。 { if(visited[G.vertices[i].firstarc->adjvex]==0) { visited[G.vertices[i].firstarc->adjvex]=1; TreeNode *t=new TreeNode;//建立一顆小樹 t->data=G.vertices[i].firstarc->adjvex; if(first)//是當前節點第一個孩子 { T->nextSibling=t;//建立右孩子 first=false;//表示不是傳進來的第一個孩子,則是孩子們的兄弟 } else { locat->nextSibling=t; } locat=t; Dfs(G,G.vertices[i].firstarc->adjvex,t);//繼續對小樹找兄弟 } G.vertices[i].firstarc=G.vertices[i].firstarc->nextarc; } } void DFS_Traverse(ALGraph G,BinTree &T) { TreeNode *locat;//此處定義一個定位指針,用來定位當前樹的位置 for(int i=1;i<=G.vexnum;i++) { visited[i]=0; } for(int i=1;i<=G.vexnum;i++) { if(visited[i]==0) { TreeNode *t=new TreeNode;//這代表一個小樹 t->data=G.vertices[i].data; if(T==NULL) { T=t;//若樹為空,建立頭節點 } else { locat->nextSibling=t;//若樹不空,則是森林,插入右兄弟 } locat=t;//定位至小樹 Dfs(G,i,locat);//建立小樹 } } } //建立圖深度優先搜索森林 void DFSForest(ALGraph G,BinTree &T) { DFS_Traverse(G,T); }
這里博主用了遞歸的方式來建立森林,因此非常需要注重順序的要求呦~
那么我們怎么知道我們的森林是什么樣子呢?
讓我們來寫一個函數來幫我們檢查一下~
void Display(BinTree T) { if(T) { cout << T->data << ' '; Display(T->firstChild); Display(T->nextSibling); } }
好了,這就是深度優先遍歷生成森林的完整程序啦~
那么讓我們看看整個的程序吧:
#include <iostream> using namespace std; #define MAXMIZE 20 int visited[MAXMIZE]; //創建一個樹的左子女,右兄弟結構 typedef struct node { int data; node *firstChild=NULL; node *nextSibling=NULL; }TreeNode,*BinTree; //創建圖的鄰接表結構 typedef struct ArcNode { int adjvex;//邊指向的頂點位置 struct ArcNode *nextarc=NULL;//指向下一條邊的指針 int *info;//該邊相關信息的指針 }ArcNode; typedef struct VNode { int data;//頂點信息 ArcNode *firstarc;//指向第一條依附該頂點的邊的指針 }VNode,AdjList[MAXMIZE]; typedef struct{ AdjList vertices;//可以間接使用數組 int vexnum,arcnum;//頂點,邊 }ALGraph; //按照圖的結構創建鄰接表表示的圖 void creatGraph(ALGraph &G) { cout << "請輸入圖的頂點數目:" ; cin >> G.vexnum ;//ok cout << "請輸入圖的邊的數目:" ; cin >> G.arcnum ;//ok cout << "頂點賦值:" ; for(int i=1;i<=G.vexnum;i++) { cin >> G.vertices[i].data; G.vertices[i].firstarc=NULL;//ok } for(int j=1;j<=G.arcnum;j++)//創建領接表,每一條邊 { int point1,point2; cout << "邊賦值:" ; cin>> point1 >> point2 ; ArcNode *a1 = new ArcNode;//創建新邊,從1到2 a1->adjvex=point2; a1->nextarc=G.vertices[point1].firstarc; G.vertices[point1].firstarc=a1; ArcNode *a2 = new ArcNode;//創建新邊,從2到1 a2->adjvex=point1; a2->nextarc=G.vertices[point2].firstarc; G.vertices[point2].firstarc=a2; } cout << endl; } //銷毀圖 void Destroy(ALGraph &G) { for(int i=1;i<=G.vexnum;i++) { G.vertices[i].firstarc->nextarc=NULL; } cout << "銷毀成功!" << endl; } void Dfs(ALGraph G,int i,BinTree &T) { visited[i]=1; bool first=true;//表示是否為當前節點第一個孩子 TreeNode *locat;//同樣是定位作用 while(G.vertices[i].firstarc!=NULL)//從此節點出發,訪問鄰接節點。 { if(visited[G.vertices[i].firstarc->adjvex]==0) { visited[G.vertices[i].firstarc->adjvex]=1; TreeNode *t=new TreeNode;//建立一顆小樹 t->data=G.vertices[i].firstarc->adjvex; if(first)//是當前節點第一個孩子 { T->nextSibling=t;//建立右孩子 first=false;//表示不是傳進來的第一個孩子,則是孩子們的兄弟 } else { locat->nextSibling=t; } locat=t; Dfs(G,G.vertices[i].firstarc->adjvex,t);//繼續對小樹找兄弟 } G.vertices[i].firstarc=G.vertices[i].firstarc->nextarc; } } void DFS_Traverse(ALGraph G,BinTree &T) { TreeNode *locat;//此處定義一個定位指針,用來定位當前樹的位置 for(int i=1;i<=G.vexnum;i++) { visited[i]=0; } for(int i=1;i<=G.vexnum;i++) { if(visited[i]==0) { TreeNode *t=new TreeNode;//這代表一個小樹 t->data=G.vertices[i].data; if(T==NULL) { T=t;//若樹為空,建立頭節點 } else { locat->nextSibling=t;//若樹不空,則是森林,插入右兄弟 } locat=t;//定位至小樹 Dfs(G,i,locat);//建立小樹 } } } //建立圖深度優先搜索森林 void DFSForest(ALGraph G,BinTree &T) { DFS_Traverse(G,T); } void Display(BinTree T) { if(T) { cout << T->data << ' '; Display(T->firstChild); Display(T->nextSibling); } } int main() { ALGraph G; BinTree T; creatGraph(G); DFSForest(G,T); Display(T); return 0; }
以上!
(博主是某大一菜狗一枚,第一次寫博客,錯誤一定非常的多,希望能和大家互相學習,共同進步鴨,希望博主期末能夠及格==)
最后當然要老婆了對不對~