STL源码系列--List::sort算法解析

296人阅读 评论(0)

一.解析一

http://blog.csdn.net/yihucha166/article/details/6544039

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中的list被实现为环状的双向链表，设置一个“哨”node作为end( )。list没有使用标准sort算法，而是实现自身的sort，本质上是mergesort（侯捷解释的是错的），但是采用了一个特殊的形式：

list_sort所使用的mergesort形式上大不一样：将前两个元素归并，再将后两个元素归并，归并这两个小子序列成为4个元素的有序子序列；重复这一过程，得到8个元素的有序子序列，16个的，32个的。。。，直到全部处理完。主要调用了swap和merge函数，而这些又依赖于内部实现的transfer函数(其时间代价为O(1))。该mergesort算法时间代价亦为n*lg(n)，计算起来比较复杂。list_sort中预留了64个temp_list，所以最多可以处理2^64-1个元素的序列，这应该足够了：）

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;

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

二.解析二

http://jiguiyuan.blog.163.com/blog/static/4336137820122133373886/

template <class T, class Alloc>
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 = 1; i < fill; ++i)
counter[i].merge(counter[i - 1]);

swap(counter[fill - 1]);
}

typedef list<int> IList;

void print(const IList& list)
{

IList::const_iterator ite = list.begin();
for (; ite != list.end(); ++ite)
{
cout << *ite << "  ";
}
cout << endl;

}

int main()
{
IList s;

s.push_back(7);
s.push_back(6);
s.push_back(5);
s.push_back(4);
s.push_back(3);
s.push_back(2);
s.push_back(1);
s.push_back(0);

IList carry;
IList counter[64];
int fill = 0;
int num = 0;
while (!s.empty())
{
cout << "取第" << num << "个数据: fill = " << fill << endl;
carry.splice(carry.begin(), s, s.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;
//我自己加的计数
num++;

//打印每次完的结果
for (int i = 0; i < fill; ++i)
{
cout << i << "==";
print(counter[i]);
}
}

for (int i = 1; i < fill; ++i)
counter[i].merge(counter[i - 1]);
s.swap(counter[fill - 1]);

getchar();
return 0;
}

i次方个有序元素.其实这应该是一个归并排序，而不是注释所说的快速排序。

0
0

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：68672次
• 积分：1756
• 等级：
• 排名：千里之外
• 原创：107篇
• 转载：15篇
• 译文：0篇
• 评论：24条
阅读排行
最新评论