【数据结构】十字链表
十字鏈表
上篇文章講解了圖的鄰接表的鏈式存儲方式,這篇文章講解圖的十字鏈存儲方式。
基本概念
十字鏈表是為了便于求得圖中頂點的度(出度和入度)而提出來的。它是綜合鄰接表和逆鄰接表形式的一種鏈式存儲結構。
在十字鏈表存儲結構中,有向圖中的頂點的結構如下所示:其中data表示頂點的具體數據信息,而firstIn則表示指向以該頂點為弧頭的第一個弧節點。而firstOut則表示指向以該頂點為弧尾的第一個弧節點。為了表示有向圖中所有的頂點,采用一個頂點數組存儲每一個結點,如下圖所示。
另外,在十字鏈表存儲結構中,有向圖中的每一條弧都有一個弧結點與之對應,具體的弧結點結構如下所示:
其中的tailVex表示該弧的弧尾頂點在頂點數組xList中的位置,headVex表示該弧的弧頭頂點在頂點數組中的位置。hLink則表示指向弧頭相同的下一條弧,tLink則表示指向弧尾相同的下一條弧。
從十字鏈表的數據結構來看,每一個頂點對應兩個鏈表:以該頂點為弧尾的弧結點所組成的鏈表以及以該頂點為弧頭的弧結點所組成的鏈表。
如下圖所示的一個有向圖:
其對應的頂點以及弧結點如下所示。拿結點A說明,該結點對應兩個鏈表(綠色和黃色標記的)。綠色鏈表表示以結點A為弧頭的弧組成的鏈表。黃色鏈表表示以結點A為弧尾的弧組成的鏈表。
基本操作
1、創建圖的十字鏈表
Status createDG(OLGraph &G, int vexNum, int arcNum){G.vexNum = vexNum;G.arcNum = arcNum;for(int i = 0; i<G.vexNum; i++){cin>>G.xList[i].data;G.xList[i].firstIn = NULL;G.xList[i].firstOut = NULL;}//初始化for(int i = 0; i<G.arcNum; i++){vexNode node1, node2;cout<<"please input two nodes of "<<i+1<<"-th arc"<<endl;cin>>node1.data>>node2.data;insertArc(G, node1, node2); }return 1; }測試結果:
如下圖所示首先輸入四個頂點:A、B、C、D,然后輸入7條弧。
既可以構建如下的有向圖。
2、按照十字鏈表形式打印圖
Status printDG(OLGraph &G){for(int i = 0; i<G.vexNum; i++){arcBox *ptail = G.xList[i].firstOut;arcBox *phead = G.xList[i].firstIn;//打印以結點i為弧尾的鏈cout<<"以結點"<<i<<"為弧尾的鏈 "<<G.xList[i].data;while(ptail){cout<<"-->"<<"|"<<ptail->tailVex<<"|"<<ptail->headVex;ptail = ptail-> tLink;}cout<<"-->NULL"<<endl;//打印以結點i為弧頭的鏈cout<<"以結點"<<i<<"為弧頭的鏈 "<<G.xList[i].data;while(phead){cout<<"-->"<<"|"<<phead->tailVex<<"|"<<phead->headVex;phead = phead->hLink;}cout<<"-->NULL"<<endl;}return 1; }測試結果:
每一個頂點對應兩個鏈表(以該結點為弧頭的鏈表和以該結點位弧尾的鏈表),分別將其打印出來。
3、向圖中插入一個結點
Status insertNode(OLGraph &G, vexNode node){G.xList[G.vexNum].data = node.data;G.xList[G.vexNum].firstIn = NULL;G.xList[G.vexNum].firstOut = NULL;G.vexNum = G.vexNum + 1;return 1; }測試結果:
向原來的有向圖插入一個新的結點E。新插入的節點沒有與之前圖中的頂點建立弧,因此其打印結果如下所示。
此時有向圖變成了:
4、向圖中結點之間插入一條弧
測試結果:
插入一條結點B到結點C的弧。再次打印該有向圖時,結果如下所示。
此時有向圖變成了:
5、刪除一條弧
void deleteOutArcAction(OLGraph &G, int index1, int index2){arcBox *cur = G.xList[index1].firstOut;arcBox *pre = cur;int count = 0;if(!cur)return;else{while(cur){count++;if(cur->headVex == index2)break;pre = cur;cur = cur->tLink;}}if(!cur)return;//該結點沒有對應的弧else if(count <=1)G.xList[index1].firstOut = pre->tLink;//刪除第一個弧結點elsepre->tLink = cur->tLink;//刪除非第一個弧結點 }void deleteInArcAction(OLGraph &G, int index1, int index2){arcBox *cur = G.xList[index2].firstIn;arcBox *pre = cur;int count = 0;if(!cur)return;else{while(cur){count++;if(cur->tailVex == index1)break;pre = cur;cur = cur->hLink;}}if(!cur)return;//該結點沒有對應的弧else if(count <=1)G.xList[index2].firstIn = pre->hLink;elsepre->hLink = cur->hLink; }Status deleteArc(OLGraph &G, vexNode node1, vexNode node2){//刪除從結點1到結點2的弧(有方向)int index1 = locateVertex(G, node1);int index2 = locateVertex(G, node2);deleteOutArcAction(G, index1, index2);//刪除兩條鏈表里面的值deleteInArcAction(G, index1, index2);return 1; }測試結果:
刪除從結點A到結點B的弧。重新打印該有向圖,結果如下所示:
此時有向圖變成了:
6、刪除一個頂點
Status deleteNode(OLGraph &G, vexNode node){//刪除結點后,該xList頂點數組中該結點后面的結點不前移,而只是將該被刪除的結點的data設置成為一個較大的值int index = locateVertex(G, node);for(int i = 0; i<G.vexNum; i++){if(i == index)continue;else{deleteArc(G, G.xList[index], G.xList[i]);//刪除以該結點為弧尾的弧deleteArc(G, G.xList[i], G.xList[index]);//刪除以該結點為弧頭的弧}}G.xList[index].data = '0';//置'0'表示該結點被刪除G.xList[index].firstIn = NULL;G.xList[index].firstOut = NULL;return 1; }測試結果:
刪除結點D,重新打印該有向圖,其結果如下所示(只剩下3條弧,4個有效結點,結點D被刪除后,該結點的內容變從‘D’變為‘0’):
測試有向圖變成了:
7、全部代碼
// 十字鏈表.cpp : Defines the entry point for the console application. //#include "stdafx.h" #include <iostream>using namespace std;#define MAX_VERTEX_NUM 20typedef int Status; typedef int infoType; typedef char vertexType;typedef struct arcBox{int tailVex, headVex;struct arcBox *hLink, *tLink;infoType *info; }arcBox;//弧結點typedef struct vexNode{vertexType data;arcBox *firstIn, *firstOut; }vexNode;//頂點節點typedef struct{vexNode xList[MAX_VERTEX_NUM];int vexNum, arcNum; }OLGraph;//十字鏈int locateVertex(OLGraph &G, vexNode node){int index = -1;for(int i = 0; i<G.vexNum; i++){if(node.data == G.xList[i].data){index = i;break;}}return index; }void insertArcAction(OLGraph &G, int index1, int index2); Status insertArc(OLGraph &G, vexNode node1, vexNode node2);Status createDG(OLGraph &G, int vexNum, int arcNum){G.vexNum = vexNum;G.arcNum = arcNum;for(int i = 0; i<G.vexNum; i++){cin>>G.xList[i].data;G.xList[i].firstIn = NULL;G.xList[i].firstOut = NULL;}//初始化for(int i = 0; i<G.arcNum; i++){vexNode node1, node2;cout<<"please input two nodes of "<<i+1<<"-th arc"<<endl;cin>>node1.data>>node2.data;insertArc(G, node1, node2); }return 1; }Status printDG(OLGraph &G){for(int i = 0; i<G.vexNum; i++){arcBox *ptail = G.xList[i].firstOut;arcBox *phead = G.xList[i].firstIn;//打印以結點i為弧尾的鏈cout<<"以結點"<<i<<"為弧尾的鏈 "<<G.xList[i].data;while(ptail){cout<<"-->"<<"|"<<ptail->tailVex<<"|"<<ptail->headVex;ptail = ptail-> tLink;}cout<<"-->NULL"<<endl;//打印以結點i為弧頭的鏈cout<<"以結點"<<i<<"為弧頭的鏈 "<<G.xList[i].data;while(phead){cout<<"-->"<<"|"<<phead->tailVex<<"|"<<phead->headVex;phead = phead->hLink;}cout<<"-->NULL"<<endl;}return 1; }void insertArcAction(OLGraph &G, int index1, int index2){arcBox* pArc = new arcBox[1];pArc->tailVex = index1;pArc->headVex = index2;pArc->info = NULL;arcBox *ptail = G.xList[index1].firstOut;arcBox *phead = G.xList[index2].firstIn;if(!ptail){pArc->tLink = NULL;}else{pArc->tLink = ptail;}if(!phead){pArc->hLink = NULL;}else{pArc->hLink = phead;}G.xList[index1].firstOut = pArc;//鏈頭部插入弧結點G.xList[index2].firstIn = pArc; }Status insertArc(OLGraph &G, vexNode node1, vexNode node2){int index1 = locateVertex(G, node1);int index2 = locateVertex(G, node2);insertArcAction(G, index1, index2);return 1; }Status insertNode(OLGraph &G, vexNode node){G.xList[G.vexNum].data = node.data;G.xList[G.vexNum].firstIn = NULL;G.xList[G.vexNum].firstOut = NULL;G.vexNum = G.vexNum + 1;return 1; }Status deleteArc(OLGraph &G, vexNode node1, vexNode node2);Status deleteNode(OLGraph &G, vexNode node){//刪除結點后,該xList頂點數組中該結點后面的結點不前移,而只是將該被刪除的結點的data設置成為一個較大的值int index = locateVertex(G, node);for(int i = 0; i<G.vexNum; i++){if(i == index)continue;else{deleteArc(G, G.xList[index], G.xList[i]);//刪除以該結點為弧尾的弧deleteArc(G, G.xList[i], G.xList[index]);//刪除以該結點為弧頭的弧}}G.xList[index].data = '0';//置'0'表示該結點被刪除G.xList[index].firstIn = NULL;G.xList[index].firstOut = NULL;return 1; }void deleteOutArcAction(OLGraph &G, int index1, int index2){arcBox *cur = G.xList[index1].firstOut;arcBox *pre = cur;int count = 0;if(!cur)return;else{while(cur){count++;if(cur->headVex == index2)break;pre = cur;cur = cur->tLink;}}if(!cur)return;//該結點沒有對應的弧else if(count <=1)G.xList[index1].firstOut = pre->tLink;//刪除第一個弧結點elsepre->tLink = cur->tLink;//刪除非第一個弧結點 }void deleteInArcAction(OLGraph &G, int index1, int index2){arcBox *cur = G.xList[index2].firstIn;arcBox *pre = cur;int count = 0;if(!cur)return;else{while(cur){count++;if(cur->tailVex == index1)break;pre = cur;cur = cur->hLink;}}if(!cur)return;//該結點沒有對應的弧else if(count <=1)G.xList[index2].firstIn = pre->hLink;elsepre->hLink = cur->hLink; }Status deleteArc(OLGraph &G, vexNode node1, vexNode node2){//刪除從結點1到結點2的弧(有方向)int index1 = locateVertex(G, node1);int index2 = locateVertex(G, node2);deleteOutArcAction(G, index1, index2);//刪除兩條鏈表里面的值deleteInArcAction(G, index1, index2);return 1; }int _tmain(int argc, _TCHAR* argv[]) { int vexNum = 4;int arcNum = 7;OLGraph G;cout<<"Try to create a Orthogonal List of a graph..."<<endl;createDG(G, vexNum, arcNum);cout<<"Try to print the Orthogonal List of the very graph..."<<endl;printDG(G);cout<<"Try to insert a node into the graph..."<<endl;vexNode node;cout<<" please input the data of the node to insert:"<<endl;cin>>node.data;insertNode(G, node);printDG(G);cout<<"Try to insert a arc into the graph..."<<endl;vexNode node1, node2;cout<<" please choose two node:"<<endl;cin>>node1.data>>node2.data;insertArc(G, node1, node2);printDG(G);cout<<"Try to delete the arc between two nodes..."<<endl;vexNode node3, node4;cout<<" please choose a arc with specifing two nodes:"<<endl;cin>>node3.data>>node4.data;deleteArc(G, node3, node4);printDG(G);cout<<"Try to delete a node of the graph..."<<endl;vexNode node5;cout<<" please choose a node:"<<endl;cin>>node5.data;deleteNode(G, node5);printDG(G);system("pause");return 0; }總結
以上是生活随笔為你收集整理的【数据结构】十字链表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java參数传递机制浅析
- 下一篇: 并口学习之一