(c++)資料結構與演算法之圖:鄰接矩陣、深度廣度遍歷、構造最小生成樹(prim、kruskal演算法)
阿新 • • 發佈:2019-02-15
第一次寫,寫的比較複雜,將就看吧。//圖的鄰接矩陣實現 //廣度遍歷bfs和深度遍歷dfs //構造最小生成樹的prim、kruskal演算法 #include <iostream> #include<stack> #include<queue> #define WEIGHTMAX 100 #define VERTEXMAX 50 #define VISITED 1 #define UNVISITED 0 using namespace std; class ufset //等價類 { private: int n; //個數 int *root,*next,*length; //等價類代表元、下一個元素、該元素所在等價類的元素個數 public: friend class graph; ufset(int s) //初始時均各自為等價類 { root=new int[s]; next=new int[s]; length=new int[s]; n=s; for(int i=0;i<s;i++) { root[i]=next[i]=i; length[i]=1; } } ~ufset() { delete [] root; delete [] next; delete [] length; } void show() //輸出 { cout<<"root:"<<endl; for(int i=0;i<n;i++) { cout<<root[i]<<" "; } cout<<endl; cout<<"next:"<<endl; for(int i=0;i<n;i++) { cout<<next[i]<<" "; } cout<<endl; cout<<"length:"<<endl; for(int i=0;i<n;i++) { cout<<length[i]<<" "; } cout<<endl; } void Union(int u,int v) //兩個等價類的合併 { if(length[root[u]]<length[root[v]]) { int temp=u; u=v; v=temp; } if(root[u]==root[v]) return; int p=next[root[u]]; //next next[root[u]]=next[root[v]]; next[root[v]]=p; length[root[v]]=1; //length length[root[u]]++; int oldroot=root[v]; //root for(int i=0;i<n;i++) if(root[i]==oldroot) root[i]=root[u]; } bool unionOK(int u,int v) //兩個元素是否在同一個等價類中 { if(root[v]==root[u]) return true; else return false; } }; class edge //邊類(資料公開) { public: int start,end; int weight; friend class graph; edge(){}; edge(int w) { weight=w; } edge(int s,int e,int w) { start=s; end=e; weight=w; } }; void visit(int v) { cout<<v<<"-->"; } class graph { private: int **matrix; //鄰接矩陣 int v_num,e_num; //結點數、邊數 int *mark; //用於判斷是否被訪問的陣列(0:未訪問 1:已訪問 ) public: graph(){}; graph(int v) { if(v>=VERTEXMAX) cout<<"construct false"<<endl; v_num=v; e_num=0; mark=new int[v_num]; for(int i=0;i<v_num;i++) mark[i]=0; matrix=new int*[v_num]; int i,j; for(i=0;i<v_num;i++) matrix[i]=new int[v_num]; for(i=0;i<v_num;i++) for(j=0;j<v_num;j++) matrix[i][j]=0; } ~graph() { delete mark; for(int i=0;i<v_num;i++) delete [] matrix[i]; delete [] matrix; } void resetMark() //重置節點標記陣列 { for(int i=0;i<v_num;i++) mark[i]=0; } bool isEdge(edge onee) //判斷是否為邊 { if(matrix[onee.start][onee.end]>0&& matrix[onee.start][onee.end]<WEIGHTMAX&& matrix[onee.end][onee.start]>0&& matrix[onee.end][onee.start]<WEIGHTMAX) return true; else return false; } void setEdge(int start,int end,int weight) //給圖新增一條邊 { if(matrix[start][end]==0&&matrix[end][start]==0) { e_num++; } matrix[start][end]=weight; matrix[end][start]=weight; } void delEdge(int start,int end) //刪除圖中一條邊 { if(matrix[start][end]!=0&&matrix[end][start]!=0) e_num--; else return; matrix[start][end]=0; matrix[end][start]=0; } void showEdge() //展示鄰接矩陣 { cout<<"鄰接矩陣如下: "<<endl; for(int i=0;i<v_num;i++) for(int j=0;j<v_num;j++) { cout<<matrix[i][j]<<" "; if(j==v_num-1) cout<<endl; } } edge firstEdge(int v) //返回該結點按順序的第一條邊 { edge e(v,v,0); for(int i=0;i<v_num;i++) { if(matrix[v][i]!=0) { e.end=i; e.weight=matrix[v][i]; return e; } } cout<<"this vertex dont have edge"<<endl; return e; } edge nextEdge(int v,edge onee) //返回該邊的下一條邊(同頭結點) { for(int i=onee.end+1;i<v_num;i++) { if(matrix[v][i]!=0) { edge e(v,i,matrix[v][i]); return e; } } cout<<"no next edge"<<endl; return onee; } void dfs_traverse(graph g,int fir) //遞迴深度遍歷 { mark[fir]=1; cout<<fir<<"-->"; for(int i=0;i<v_num;i++) { if(g.matrix[fir][i]>=1&&!mark[i]) dfs_traverse(g,i); } } void dfs_notraverse() //非遞迴深度遍歷(用棧實現) { resetMark(); stack<int> s; for(int i=0;i<v_num;i++) { if(mark[i]==0) { s.push(i); while(!s.empty()) { int pc=s.top(); s.pop(); if(mark[pc]==0) visit(pc); mark[pc]=1; for(int j=v_num-1;j>0;j--) //for(int j=0;j<v_num;j++) //??? 為何順序顛倒??? { if(matrix[pc][j]>0&&matrix[pc][j]<WEIGHTMAX) if(mark[j]==0) s.push(j); } } } } } void bfs() //廣度遍歷(用佇列實現) { resetMark(); queue<int> q; for(int i=0;i<v_num;i++) { if(mark[i]==0) { q.push(i); while(!q.empty()) { int pc=q.front(); q.pop(); if(mark[pc]==0) visit(pc); mark[pc]=1; for(int j=0;j<v_num;j++) //for(int j=v_num;j>=0;j--) //????? { if(matrix[pc][j]>0&&matrix[pc][j]<WEIGHTMAX) if(mark[j]==0) q.push(j); } } } } } void prim() //prim { resetMark(); int x=0,y=0; //下標 edge *e=new edge[v_num-1]; //構建的最小生成樹的邊組成的陣列 int *ver=new int[v_num]; //結點的陣列,用於統計哪些結點已被構建,當陣列滿時說明構建完成 {//初始化markedge for(int i=0;i<v_num;i++) ver[i]=-1; } ver[0]=0; //放入首個結點 mark[0]=1; y++; while(y<v_num) //如果結點沒有全部訪問完則迴圈 { int minWeight=WEIGHTMAX,sta,en; for(int i=0;ver[i]!=-1;i++) //遍歷尋找權重最小的邊 { for(int j=0;j<v_num;j++) { //如果邊滿足:權重最小、邊的尾結點未被訪問,則加入邊的尾結點 if(matrix[ver[i]][j]!=0&&minWeight>matrix[ver[i]][j] &&mark[j]==0) { minWeight=matrix[ver[i]][j]; sta=ver[i]; en=j; } } } edge temp(sta,en,minWeight); e[x++]=temp; ver[y++]=en; mark[en]=1; } {//展示結果: cout<<"插入邊順序: "<<endl; for(int i=0;i<v_num-1;i++) cout<<e[i].start<<"---"<<e[i].weight<<"--->"<<e[i].end<<endl; cout<<"插入結點順序: "; for(int i=0;i<v_num;i++) cout<<ver[i]<<" "; cout<<endl; } delete [] ver; delete [] e; } void kruskal() //kruskal { int n=v_num,union_num=0; queue<edge> q; ufset ufs(n); {//遍歷使所有邊按權重從小到大的順序排成陣列,進隊 edge eq[e_num]; int x=0; int **edgew=new int*[n]; edgew=matrix; while(x<+e_num) { for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(edgew[i][j]!=0) { edge e(i,j,edgew[i][j]); eq[x++]=e; edgew[i][j]=edgew[j][i]=0; } } } } for(int i=0;i<e_num;i++) { int minweight=eq[i].weight; for(int j=0;j<e_num;j++) { if(eq[j].weight>minweight) { minweight=eq[j].weight; edge temp; temp=eq[j]; eq[j]=eq[i]; eq[i]=temp; } } } for(int i=0;i<e_num;i++) q.push(eq[i]); delete edgew; } cout<<"邊插入順序:"<<endl; while(!q.empty()) { edge e=q.front(); q.pop(); if(!ufs.unionOK(e.start,e.end)) { cout<<e.start<<"---"<<e.weight<<"--->"<<e.end<<endl; ufs.Union(e.start,e.end); } } cout<<"結點插入順序:"; for(int i=0;i<n;i++) { cout<<ufs.next[i]<<" "; } cout<<endl; } }; int main() { graph a(8); {//set edge(初始化圖) a.setEdge(0,1,1); a.setEdge(0,2,2); a.setEdge(1,3,3); a.setEdge(1,4,5); a.setEdge(3,7,4); a.setEdge(4,7,4); a.setEdge(2,6,1); a.setEdge(2,5,3); a.setEdge(5,6,2); } cout<<"帶權無向圖:(P160 4-12)"<<endl; a.showEdge(); cout<<" node1 first edge's weight: "<<a.firstEdge(1).weight<<endl; cout<<"node2 first edge's next edge's weight: "<<a.nextEdge(2,a.firstEdge(2)).weight<<endl; cout<<"遞迴深度遍歷: "; a.dfs_traverse(a,0); cout<<endl; cout<<"非遞迴深度遍歷: "; a.dfs_notraverse(); cout<<endl; cout<<" 廣度遍歷: "; a.bfs(); cout<<endl; cout<<"prim:"<<endl; a.prim(); cout<<"kruskal:"<<endl; a.kruskal(); cout << "Hello world!" << endl; return 0; }