STL的算法中,提供了sort()算法,算法接收兩個RandomAccessIterator。所有關係型容器底層使用紅黑樹的,有自動排序功能。序列容器中的stack,queue使用priority-queue。而優先隊列使用堆實現,它們都有特定的出入口,不允許排序。剩下的vector,list,deque中,list無法使用,因爲list的迭代器屬於BidirectionIterators。list是雙向鏈表。
List的sort()排序代碼很短,但是不太好懂,這裏從<STL源碼剖析>摘錄,下劃線部分被刪掉,方便閱讀。書上說這是快速排序,但是怎麼看都是歸併......
template<class T,class Alloc>
void list<T,Alloc>::sort(){
//以下判斷,如果是空鏈,或者只有一個元素,不進行操作
if(node->next==node||link_type(node->next)->next==node)
return;
list<T,Alloc> carry;
list<T,Alloc> counter[64];
int fill=0;
while(!empty()){
carry.splice(carry.begin(),*this,begin());
int i=0;
while(i<fill&&!counter[i].empty()){
counter[i].merge(carry);
carry.swap(counter[i++]);
}
carry.swap(counter[i);
if(i==fill) ++fill;
}
for(int i=0=1;i<fill;++i)
counter[i].merge(counter[i-1]);
swap(counter[fill-1]);
}
首先這裏使用到兩個list的函數。
void splice(iterator position,list &,iterator i)
函數將i所指的元素結合於position所指的位置之前。
template<class T,class Alloc>
void list<T,Alloc>::merge(list<T,Alloc>&x )
函數將x合併到*this身上,兩個lists的內容都必須先經過遞增排序。
參數list的內容會清空,合併過程有排序!!!
下面看一下整個代碼的具體實現。
代碼開頭先進行了一下校驗。
然後聲明瞭兩個變量,carry和counter[64]都是拿來作爲中間變量進行中轉的。
counter[0]存放2^1次方個元素
counter[1]存放2^2次方個元素
依次類推
怎樣存放呢,原則是當第i個counter[i]中存放的內容個數等於2^(i+1)時,就把counter[i]裏的內容轉移到counter[i+1]
假設我們有個list:7,9,8,6,11。
第一輪:
開始時:
carry:NULL
fill:0
counter[0]:NULL
counter[1]:NULL
1.carry.splice取出第一個元素
carry=7
2.現在i==fill跳過while循環
3.carry.swap之後,carry和counter[0]交換
carry:NULL
counter[0]:7
counter[1]:NULL
4.現在執行if(i==fill) ++fill;
fill=1;
結束時:
carry:NULL
fill:1
counter[0]:7
counter[1]:NULL
第二輪:
1.carry.splice取出第二個元素
carry=9
2.現在i<fill且counter[0]非空,執行while循序內部內容
couter[i].merge[carry]
carry:NULL
counter[0]:7,9
counter[1]:NULL
注意這裏是的放置已經經過了排序,在merge裏實現
carry.swap[counter[i++]
carry:7,9
counter[0]:NULL
counter[1]:NULL
3.i=1,fill=1退出while循環
4.carry.swap之後,carry和counter[1]交換
carry:NULL
counter[0]:NULL
counter[1]:7,9
5.現在執行if(i==fill) ++fill;
fill=2;
結束時:
carry:NULL
fill:2
counter[0]:NULL
counter[1]:7,9
這樣就把兩個元素歸併到了counter[1]中,下面不再繁瑣的分析
取出第三個數字8,放到counter[0]中,現在counter[0],counter[1]中的數字個數都小於規定數字:
counter[0]:8
counter[1]:7,9
取出第四個數字6,放到counter[1]中,這是counter[0]中個數定爲2,需要轉移到counter[1]中:
counter[0]:NULL
counter[1]:6,7,8,9
這時候counter[1]的個數等於4了,需要把所有的數字轉移到counter[2]中
counter[0]:NULL
counter[1]:NULL
counter[2]:6,7,8,9
然後取出11放到counter[0]中,鏈表所有元素取完了。結束while循環。
把所有結果歸併。
這裏fill其實表示了一個2^(i+1)次方的判定!!
整個過程總結如下:
將前兩個元素歸併,再將後兩個元素歸併,歸併這兩個小子序列成爲4個元素的有序子序列;重複這一過程,得到8個元素的有序子序列,16個的,32個的。。。,直到全部處理完。主要調用了swap和merge函數,而這些又依賴於內部實現的transfer函數(其時間代價爲O(1))。該mergesort算法時間代價亦爲n*lg(n),計算起來比較複雜。list_sort中預留了 64個temp_list,所以最多可以處理2^64-1個元素的序列,這應該足夠了。