標籤:style blog color 使用 資料 io
優先隊列(priority queue)
對於一般的隊列是在隊列的尾部添加資料,在頭部刪除,以便先進先出。
而優先隊列中的每個元素都有一個優先順序,每次將一個元素放入隊列中,而每次出隊時都是將優先順序最大的那個元素出隊,稱為高進先出(largest-in,first-out)。
優先隊列必須實現以下幾個操作
1.入隊(push):將一個元素放入隊列中。
2.出隊(pop):將優先順序最高的元素從隊列中刪除。
要實現上面的操作可以維護一個有序的鏈表。每次插入資料時維護整個鏈表有序,即使用插入法,每次出隊的操作只需要刪除鏈表最前面的元素。
這麼做的話入隊操作的複雜度是O(n),出隊是O(1),綜合複雜度為O(n)。
接下來要介紹的是O(logn) 的資料結構——二元堆積。
給定一棵完全二叉樹,該樹的每個節點的優先順序大於該節點的所有孩子節點的優先順序。易知,根節點將是優先順序最高的節點。
要用二元堆積來實現優先隊列,必須完成的兩個操作:
1.入隊(push):對於一棵空的二元堆積,只需要將入堆的元素加入根節點即可。對於一般情況,我們將該元素直接加入完全二叉樹的一個位置,該位置是指將這個位置加入該完全二叉樹,這個樹仍然是完全二叉樹的那個點。之後將這個元素和他的父節點比較,若優先順序大於該父節點,則與父節點交換位置,再將新插入的這個元素再和它的新父節點比較,直到它沒有父節點或有一個父節點優先順序大於它為止。
2.出隊(pop):要拿出該完全二叉樹的根節點,之後要維護剩下的節點滿足二元堆積的性質。
在講這個操作之前,我們先定義一個新的操作——假設某節點的左右兩棵子樹都滿足堆的性質,要將整個樹也變成一個堆。我們把該操作稱為篩選(sift)。對於篩選演算法我們需要將根節點和兩個子節點比較,若根節點的優先順序最大,則已經調整完成,否則將兩個子節點中較大的那個和根節點進行交換,此時根節點將是最大的元素了,然後跟蹤被交換的那個孩子節點的位置,繼續做如上的調整,直到調整結束。
對於出隊操作,刪除根節點的元素,並將該二元堆積的最後一個元素(所謂最後一個元素是指將該元素從完全二叉樹刪除,該二叉樹仍然是完全二叉樹的那個元素)放到根節點的位置,然後對該樹進行篩選操作。
一般的來講,堆可以輕易地用數組實現,假設數組編號為1的元素是根節點,那麼2和3分別是它的左右節點。對於一個數組編號為i(i>=1)的節點,他的左右節點分別為i*2和i*2+1。
要將一個數組中的n個元素(編號從1到n)直接變成堆,可以用以下操作:for(i=n/2;i>=1;i--) sift(以編號為i的節點為根節點)。這是因為超過n/2的那些節點都是葉子節點,滿足堆的性質,其他節點從下往上依次進行sift操作就完成的堆的建立。
1 #include<stdio.h> 2 /*r[0].fix為堆的長度*/ 3 typedef int elemtype; 4 typedef struct node 5 { 6 elemtype data; 7 int fix; 8 }HeapNode; 9 HeapNode out(HeapNode r[],int s)/*r[s]出堆*/10 {11 int i,j;12 HeapNode item;13 item=r[s];/*資料暫存*/14 r[s]=r[r[0].fix];/*最後一個資料放入要出堆的元素的位置上*/15 r[0].fix--;/*長度減一*/16 sift(r,s,r[0]);17 return item;18 }19 void in(HeapNode r[],HeapNode item)/*入堆*/20 {21 int i;22 for(i=r[0].fix+1;i>1;i/=2)23 {24 if(item.fix</*>*/r[i/2].fix) r[i]=r[i/2];25 else break;26 }27 r[i]=item;28 r[0].fix++;29 }30 void sift(HeapNode r[],int s,int t)/*篩選成小頂堆演算法*/31 {/*r[s...t]中的記錄除r[s]外均滿足堆的特性*/32 int i,j;33 HeapNode item;34 item=r[s];35 i=s;36 j=2*i;37 while(j<=r[0].fix)38 {39 if(j+1<=r[0].fix&&r[j+1].fix</*>*/r[j].fix) j++;40 if(item.fix>/*<*/r[j].fix){r[i]=r[j];i=j;j=2*i;}41 else break;42 }43 r[i]=item;44 }45 /*46 初始堆的建立:47 for(i=n/2;i>=1;--) sift(r,i,n);48 */49 /*堆排序*/50 /*大頂堆完成升序,小頂堆完成降序*/51 void Heat_sort(long r[],int n)52 {53 int i;54 long item;55 for(i=n/2;i>=1;i--) sift(r,i,n);/*初始堆的建立*/56 for(i=n;i>=2;i--)57 {58 item=r[i];59 r[i]=r[1];60 r[1]=item;61 sift(r,1,i-1); /*大頂堆完成升序,小頂堆完成降序*/62 }63 }