stl中的list 是雙向鏈表結構,最近用到其中的sort方法,文檔中有這麼兩段:
Sorts *this according to operator<. The sort is stable, that is, the relative order of equivalent elements is preserved. All iterators remain valid and continue to point to the same elements. [6] The number of comparisons is approximately N log N, where N is the list's size.
-》[6] The sort algorithm works only for random access iterators. In principle, however, it would be possible to write a sort algorithm that also accepted bidirectional iterators. Even if there were such a version of sort, it would still be useful for list to have a sort member function. That is, sort is provided as a member function not only for the sake of efficiency, but also because of the property that it preserves the values that list iterators point to.
可以看出 stl中的sort算法一般只支持 隨機訪問的結構,對於list來說,一般使用它自己的sort成員函數,並且時間複雜度在nlogn。
由於對鏈表結構的排序比較感興趣,回頭在網上搜索了一下list內部的sort算法分析,由源碼分析可以看出list內部的sort函數,實際上是通過鏈表方式實現的非遞歸的mergesort,時間複雜度在nlogn,並且空間複雜度爲O(1),下面貼兩篇分析的文章:
---------------------------------------
stl中的list被實現爲環狀的雙向鏈表,設置一個“哨”node作爲end( )。list沒有使用標準sort算法,而是實現自身的sort,本質上是mergesort(侯捷解釋的是錯的),但是採用了一個特殊的形式:
普通的mergesort直接將待排序的序列一分爲二,然後各自遞歸調用mergesort,再使用Merge算法用O(n)的時間將已排完序的兩個子序列歸併,從而總時間效率爲n*lg(n)。(mergesort是很好的排序算法,絕對時間很小,n*lg(n)之前的係數也很小,但是在內存中的排序算法中並不常見,我想可能主要還是因爲耗空間太多,也是O(n))
list_sort所使用的mergesort形式上大不一樣:將前兩個元素歸併,再將後兩個元素歸併,歸併這兩個小子序列成爲4個元素的有序子序列;重複這一過程,得到8個元素的有序子序列,16個的,32個的。。。,直到全部處理完。主要調用了swap和merge函數,而這些又依賴於內部實現的transfer函數(其時間代價爲O(1))。該mergesort算法時間代價亦爲n*lg(n),計算起來比較複雜。list_sort中預留了64個temp_list,所以最多可以處理2^64-1個元素的序列,這應該足夠了:)
爲何list不使用普通的mergesort呢?這比較好理解,因爲每次找到中間元素再一分爲二的代價實在太大了,不適合list這種非RandomAccess的容器。
爲何list不使用標準sort算法呢(標準sort要求RandomAccessIterator)?至少普通的quicksort我覺得應該是可以的,具體原因等查查標準算法實現再來說了。
下面把gcc4.02中list_sort的實現貼上:
template<typename _Tp, typename _Alloc>
void
list<_Tp, _Alloc>::
sort()
{
// Do nothing if the list has length 0 or 1.
if (this->_M_impl._M_node._M_next != &this->_M_impl._M_node
&& this->_M_impl._M_node._M_next->_M_next != &this->_M_impl._M_node)
{
list __carry;
list __tmp[64];
list * __fill = &__tmp[0];
list * __counter;
do
{
__carry.splice(__carry.begin(), *this, begin());
for(__counter = &__tmp[0];
__counter != __fill && !__counter->empty();
++__counter)
{
__counter->merge(__carry);
__carry.swap(*__counter);
}
__carry.swap(*__counter);
if (__counter == __fill)
++__fill;
}
while ( !empty() );
for (__counter = &__tmp[1]; __counter != __fill; ++__counter)
__counter->merge(*(__counter - 1));
swap( *(__fill - 1) );
}
}
--------------------------------------------------------
list::sort() 這個函數使用了非常巧妙的算法,來對list中的元素進行排序,在某些書上看到,指出該算法是快速排序,個人認爲應該是歸併排序更爲確切。。所以提供了以下測試代碼以觀察整個排序過程。
#include <iostream>
#include <list>
#include <iomanip>
using namespace std;
//the max value is 64
const int SCALE=10;
template <typename T>
void print_dbg(list<T>& iList, list<T>& carry, list<T>* counter)
{
typename list<T>::iterator it2;
cout<<"list: ";
it2=iList.begin();
while(it2!=iList.end())
{
cout<<setw(3)<<*it2++;
}
cout<<endl;
cout<<"carry: ";
it2=carry.begin();
while(it2!=carry.end())
{
cout<<setw(3)<<*it2++;
}
cout<<endl;
for(int i=0; i<SCALE; ++i)
{
if(!counter[i].empty())
{
cout<<"counter["<<i<<"]: ";
it2=counter[i].begin();
while(it2!=counter[i].end())
{
cout<<setw(3)<<*it2++;
}
cout<<endl;
}
}
cout<<endl<<endl;
}
template <typename T>
void LSort(list<T> &iList)
{
if(iList.size()<= 1)
{
return;
}
list<T> carry;
list<T> counter[64];
int fill = 0;
typename list<T>::iterator it;
while (!iList.empty())
{
carry.splice(carry.begin(), iList, iList.begin());
print_dbg(iList, carry, counter);
int i = 0;
while(i < fill && !counter[i].empty())
{
counter[i].merge(carry);
carry.swap(counter[i++]);
}
carry.swap(counter[i]);
print_dbg(iList, carry, counter);
if (i == fill)
{
++fill;
}
cout<<endl<<endl<<endl;
}
for (int i = 1; i < fill; ++i)
{
counter[i].merge(counter[i-1]);
}
print_dbg(iList, carry, counter);
iList.swap(counter[fill-1]);
}
int main()
{
int arr[]={22,43,1,32,43,3,65,8,56,98,4,23,87,94,37,77,35,36,0};
list<int> iList(arr,arr+sizeof(arr)/sizeof(int));
list<int>::iterator it;
LSort(iList);
cout<<"Complete! After sort: "<<endl;
it=iList.begin();
while(it!=iList.end())
{
cout<<setw(3)<<*it++;
}
cout<<endl<<endl;
system("pause");
return 0;
}
通過函數print_dbg()打印所有中間鏈表的內容,在以上數組的輸入時,可以得到以下輸出:
list: 43 1 32 43 3 65 8 56 98 4 23 87 94 37 77 35 36
carry: 22
list: 43 1 32 43 3 65 8 56 98 4 23 87 94 37 77 35 36
carry:
counter[0]: 22
list: 1 32 43 3 65 8 56 98 4 23 87 94 37 77 35 36 0
carry: 43
counter[0]: 22
list: 1 32 43 3 65 8 56 98 4 23 87 94 37 77 35 36 0
carry:
counter[1]: 22 43
list: 32 43 3 65 8 56 98 4 23 87 94 37 77 35 36 0
carry: 1
counter[1]: 22 43
list: 32 43 3 65 8 56 98 4 23 87 94 37 77 35 36 0
carry:
counter[0]: 1
counter[1]: 22 43
list: 43 3 65 8 56 98 4 23 87 94 37 77 35 36 0
carry: 32
counter[0]: 1
counter[1]: 22 43
list: 43 3 65 8 56 98 4 23 87 94 37 77 35 36 0
carry:
counter[2]: 1 22 32 43
list: 3 65 8 56 98 4 23 87 94 37 77 35 36 0
carry: 43
counter[2]: 1 22 32 43
list: 3 65 8 56 98 4 23 87 94 37 77 35 36 0
carry:
counter[0]: 43
counter[2]: 1 22 32 43
list: 65 8 56 98 4 23 87 94 37 77 35 36 0
carry: 3
counter[0]: 43
counter[2]: 1 22 32 43
list: 65 8 56 98 4 23 87 94 37 77 35 36 0
carry:
counter[1]: 3 43
counter[2]: 1 22 32 43
list: 8 56 98 4 23 87 94 37 77 35 36 0
carry: 65
counter[1]: 3 43
counter[2]: 1 22 32 43
list: 8 56 98 4 23 87 94 37 77 35 36 0
carry:
counter[0]: 65
counter[1]: 3 43
counter[2]: 1 22 32 43
list: 56 98 4 23 87 94 37 77 35 36 0
carry: 8
counter[0]: 65
counter[1]: 3 43
counter[2]: 1 22 32 43
list: 56 98 4 23 87 94 37 77 35 36 0
carry:
counter[3]: 1 3 8 22 32 43 43 65
list: 98 4 23 87 94 37 77 35 36 0
carry: 56
counter[3]: 1 3 8 22 32 43 43 65
list: 98 4 23 87 94 37 77 35 36 0
carry:
counter[0]: 56
counter[3]: 1 3 8 22 32 43 43 65
list: 4 23 87 94 37 77 35 36 0
carry: 98
counter[0]: 56
counter[3]: 1 3 8 22 32 43 43 6
list: 4 23 87 94 37 77 35 36 0
carry:
counter[1]: 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 23 87 94 37 77 35 36 0
carry: 4
counter[1]: 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 23 87 94 37 77 35 36 0
carry:
counter[0]: 4
counter[1]: 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 87 94 37 77 35 36 0
carry: 23
counter[0]: 4
counter[1]: 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 87 94 37 77 35 36 0
carry:
counter[2]: 4 23 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 94 37 77 35 36 0
carry: 87
counter[2]: 4 23 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 94 37 77 35 36 0
carry:
counter[0]: 87
counter[2]: 4 23 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 37 77 35 36 0
carry: 94
counter[0]: 87
counter[2]: 4 23 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 37 77 35 36 0
carry:
counter[1]: 87 94
counter[2]: 4 23 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 77 35 36 0
carry: 37
counter[1]: 87 94
counter[2]: 4 23 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 77 35 36 0
carry:
counter[0]: 37
counter[1]: 87 94
counter[2]: 4 23 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 35 36 0
carry: 77
counter[0]: 37
counter[1]: 87 94
counter[2]: 4 23 56 98
counter[3]: 1 3 8 22 32 43 43 65
list: 35 36 0
carry:
counter[4]: 1 3 4 8 22 23 32 37 43 43 56 65 77 87 94
list: 36 0
carry: 35
counter[4]: 1 3 4 8 22 23 32 37 43 43 56 65 77 87 94
list: 36 0
carry:
counter[0]: 35
counter[4]: 1 3 4 8 22 23 32 37 43 43 56 65 77 87 94
list: 0
carry: 36
counter[0]: 35
counter[4]: 1 3 4 8 22 23 32 37 43 43 56 65 77 87 94
list: 0
carry:
counter[1]: 35 36
counter[4]: 1 3 4 8 22 23 32 37 43 43 56 65 77 87 94
list:
carry: 0
counter[1]: 35 36
counter[4]: 1 3 4 8 22 23 32 37 43 43 56 65 77 87 94
list:
carry:
counter[0]: 0
counter[1]: 35 36
counter[4]: 1 3 4 8 22 23 32 37 43 43 56 65 77 87 94
list:
carry:
counter[4]: 0 1 3 4 8 22 23 32 35 36 37 43 43 56 65
Complete! After sort:
0 1 3 4 8 22 23 32 35 36 37 43 43 56 65 77 87 94 98
所以個人認爲應該算是歸併排序。
完