list::sort源碼分析

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個的。。。,直到全部處理完。主要調用了swapmerge函數,而這些又依賴於內部實現的transfer函數(其時間代價爲O(1))。該mergesort算法時間代價亦爲n*lg(n),計算起來比較複雜。list_sort中預留了 64temp_list,所以最多可以處理2^64-1個元素的序列,這應該足夠了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章