一:用法示例

函数原型:

有两个重载。

(1)void sort();

(2)template <class Compare>
              void sort (Compare comp);

实现功能:对链表进行排序,默认是升序,如自定义是降序,需使用重载类型第二个,具体操作看下面的示例。


示例:

// list::sort
#include <iostream>
#include <list>
#include <string>
#include <cctype>

// comparison, not case sensitive.
bool compare_nocase(const std::string& first, const std::string& second)
{
unsigned int i = 0;
while ((i < first.length()) && (i < second.length()))
{
if (tolower(first[i]) < tolower(second[i])) return true;
else if (tolower(first[i]) > tolower(second[i])) return false;
++i;
}
return (first.length() < second.length());
}

int main()
{
std::list<std::string> mylist;
std::list<std::string>::iterator it;
mylist.push_back("one");
mylist.push_back("two");
mylist.push_back("Three");

mylist.sort();

std::cout << "mylist contains:";
for (it = mylist.begin(); it != mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';

mylist.sort(compare_nocase);

std::cout << "mylist contains:";
for (it = mylist.begin(); it != mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';

return 0;
}

Output:


mylist contains: Three one two mylist contains: one Three two



二:源码

template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::sort()
{
if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node)
{
list<_Tp, _Alloc> __carry;
list<_Tp, _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]);
}
}


三:源码剖析

template <class _Tp, class _Alloc>
void list<_Tp, _Alloc>::sort()
{
//链表长度如果是0或者1,直接结束。这里没有使用size()是因为速度相对源码的这样设计会慢。
if (_M_node->_M_next != _M_node && _M_node->_M_next->_M_next != _M_node)
{
list<_Tp, _Alloc> __carry;
list<_Tp, _Alloc> __counter[64];
int __fill = 0;
/*
定义了一个类似于搬运作用的链表carry和具有中转站作用的链表counter,这里首先对counter[i]里面
存储数据的规则进行分析;counter[i]里面最多存储数据个数为2^(i+1),若存储数据超过该数字,则向相邻高位
进位,即把counter[i]链表里的内容都合并到counter[i+1]链表。carry负责取出原始链表的头一个数据
节点和交换数据中转站作用;源码中的fill表示当前可处理数据的个数为2^fill.那么counter数组长度64,
也就是排序元素个数最多可到2^64-1,这数据量已经足够。
*/

while (!empty())
{
__carry.splice(__carry.begin(), *this, begin());//把当前链表的第一个节点放在carry链表头
int __i = 0;
while (__i < __fill && !__counter[__i].empty())
{
__counter[__i].merge(__carry);//把链表carry合并到counter[i]
__carry.swap(__counter[__i++]);//交换链表carry和counter[i]内容
}
__carry.swap(__counter[__i]);//交换链表carry和counter[i]内容
if (__i == __fill) ++__fill;
}
for (int __i = 1; __i < __fill; ++__i)
__counter[__i].merge(__counter[__i - 1]);//把低位不满足进位的剩余数据全部有序的合并到上一位
swap(__counter[__fill - 1]);//最后把已排序好的链表内容交换到当前链表
}
}


建议读者在阅读一些算法代码,尤其是经典的源代码时,如果在理解上有困难,一定要自己设计测试数据,然后再纸上模拟算法流程,由此加深理解。