Prim演算法實現最小生成樹(圖模型+小根堆)
阿新 • • 發佈:2019-02-05
Prim演算法實現最小生成樹的思想是:在圖中取一個頂點為起始點,找出其鄰接的所有頂點,將該點和鄰接的頂點和邊的權值一一壓入小根堆中,接著從小根堆中退出小根堆的根,將沒訪問過的兩個頂點及其關聯邊的權值插入到最小生成樹中,以此類推,總共需要迴圈n-1次。
小根堆模組:
int heapNum=0; //記錄堆的結點個數 //堆的結點結構 struct Heap { int sta,en; int weight; } heap[100]; //下滑操作 void siftDown(int start,int end) { //將start號結點向下調整直到end int i=start,j=2*i; heap[0]=heap[i]; //用heap[0]來臨時儲存i結點的值 while(j<=end) { //有右孩子並且右孩子比左孩子小時,將j儲存右孩子 if(j<end&&heap[j].weight>heap[j+1].weight) ++j; //比j號結點小時,不需調整 if(heap[0].weight<=heap[j].weight) break; else { //向下調整 heap[i]=heap[j]; i=j; j=2*j; } } heap[i]=heap[0]; } void siftUp(int start) { int j=start,i=j/2; heap[0]=heap[j]; while(j>0) { if(heap[i].weight<=heap[0].weight) break; else { //向上調整工作 heap[j]=heap[i]; j=i; i=i/2; } } heap[j]=heap[0]; } //插入操作的實現 bool insert(Heap temp) { ++heapNum; heap[heapNum]=temp; siftUp(heapNum); return true; } //刪除操作 bool removeMin(Heap& temp) { //保留下根結點 temp=heap[1]; heap[1]=heap[heapNum]; //填補樹根 --heapNum; siftDown(1,heapNum); //將根結點下滑到尾部 return true; }
圖模組:
struct LinkNode { int vex; //鄰接的結點在陣列中的編號 LinkNode* next; int weig; //結點的權值 }; //定義圖結點的最大個數 const int MaxSize=10; bool visited[10]={false}; struct Node { int data; LinkNode* head; //將結點鄰接的連結串列頭置為空 Node(){ head=0;} } Adj[MaxSize],miniTree[MaxSize]; //Adj陣列表示原來的圖 //miniTree表示最小生成樹 //建立圖的演算法 void createLink(int& numNode) { int numLink=0; LinkNode* ptr; cin>>numNode; for(int i=1;i<=numNode;++i) { cin>>Adj[i].data; cin>>numLink; //頭插入建表 for(int j=0;j<numLink;++j) { ptr=new LinkNode; cin>>ptr->vex; cin>>ptr->weig; ptr->next=Adj[i].head; Adj[i].head=ptr; } } }
Prim演算法模組:
//將圖中v所關聯的邊存入堆中 void inHeap(int v) { LinkNode* ptr=0; ptr=Adj[v].head; //每個鄰接點都有機會訪問 while(ptr!=0) { if(!visited[ptr->vex]) { Heap temp; temp.sta=v; temp.en=ptr->vex; temp.weight=ptr->weig; //將圖中的邊和所關聯的兩個結點壓入堆中 insert(temp); } ptr=ptr->next; //到下個鄰接點 } } //將兩個結點及其對應關係插入最小生成樹中 void insertTree(int st,int en,int weig) { LinkNode* ptr=new LinkNode; ptr->vex=en; ptr->weig=weig; ptr->next=miniTree[st].head; miniTree[st].head=ptr; } //求從u結點開始遍歷生成的最小生成樹的演算法 void prim(int u) { int nodeNum=0; createLink(nodeNum); visited[u]=true; int cntNum=1; while(cntNum<nodeNum) { //將u所關聯的邊存入堆中 inHeap(u); while(heapNum!=0) { Heap temp; //取堆中權值最小的結點 removeMin(temp); if(!visited[temp.en]) { //將兩個頂點及其關聯邊插入最小生成樹中 miniTree[temp.sta].data=Adj[temp.sta].data; miniTree[temp.en].data=Adj[temp.en].data; insertTree(temp.sta,temp.en,temp.weight); insertTree(temp.en,temp.sta,temp.weight); u=temp.en; visited[u]=true; ++cntNum; break; } } } }