• 【STL***list容器三】


    目录

    transfer

    merge

    reverse

    sort


    list是一个循环双向链表, 不是一个连续地址空间, 所以sort功能需要特殊的算法单独实现, 而不能用算法中的sort. 当然还可以将list的元素插入到vector中最后将vector排序好的数据拷贝回来, 不过这种做法很费时, 费效率

    先分析几个会被调用的函数

    transfer

    功能:将一段链表添加到指定位置之前

    1. last的前一个节点叫last_but_one
    2. first的前一个节点叫zero

    现在分析transfer的每一步

    1. template <class T, class Alloc = alloc>
    2. class list
    3. {
    4. ...
    5. protected:
    6. void transfer(iterator position, iterator first, iterator last)
    7. {
    8. if (position != last)
    9. {
    10. (*(link_type((*last.node).prev))).next = position.node;
    11. (*position.node).prev = (*last.node).prev;
    12. link_type tmp = link_type((*position.node).prev);
    13. (*first.node).prev = tmp;
    14. (*(link_type((*position.node).prev))).next = first.node;
    15. (*(link_type((*first.node).prev))).next = last.node;
    16. (*last.node).prev = (*first.node).prev;
    17. }
    18. }
    19. /*
    20. void transfer(iterator position, iterator first, iterator last)
    21. {
    22. if (position != last)
    23. {
    24. (*(link_type((*last.node).prev))).next = position.node;
    25. (*(link_type((*first.node).prev))).next = last.node;
    26. (*(link_type((*position.node).prev))).next = first.node;
    27. link_type tmp = link_type((*position.node).prev);
    28. (*position.node).prev = (*last.node).prev;
    29. (*last.node).prev = (*first.node).prev;
    30. (*first.node).prev = tmp;
    31. }
    32. }
    33. */
    34. ...
    35. };

    splice 将两个链表进行合并(调用了transfer)

    1. template <class T, class Alloc = alloc>
    2. class list
    3. {
    4. ...
    5. public:
    6. void splice(iterator position, list& x) {
    7. if (!x.empty())
    8. transfer(position, x.begin(), x.end());
    9. }
    10. void splice(iterator position, list&, iterator i) {
    11. iterator j = i;
    12. ++j;
    13. if (position == i || position == j) return;
    14. transfer(position, i, j);
    15. }
    16. void splice(iterator position, list&, iterator first, iterator last) {
    17. if (first != last)
    18. transfer(position, first, last);
    19. }
    20. ...
    21. };

    merge

    将list与x从小到大合并到原链表中(核心还是transfer)

    1. template <class T, class Alloc>
    2. void list::merge(list& x) {
    3. iterator first1 = begin();
    4. iterator last1 = end();
    5. iterator first2 = x.begin();
    6. iterator last2 = x.end();
    7. while (first1 != last1 && first2 != last2)
    8. if (*first2 < *first1) {
    9. iterator next = first2;
    10. // 将first2到first+1的左闭右开区间插入到first1的前面
    11. // 这就是将first2合并到first1链表中
    12. transfer(first1, first2, ++next);
    13. first2 = next;
    14. }
    15. else
    16. ++first1;
    17. // 如果链表x还有元素则全部插入到first1链表的尾部
    18. if (first2 != last2) transfer(last1, first2, last2);
    19. }

    reverse

    功能:翻转链表

    list的迭代器不会改变

    将每个元素一个一个插入到begin之前(list不会变但begin()会变,它始终指向第一个元素的地址)

    1. template <class T, class Alloc>
    2. void list::reverse()
    3. {
    4. if (node->next == node || link_type(node->next)->next == node)
    5. return;
    6. iterator first = begin();
    7. ++first;
    8. while (first != end()) {
    9. iterator old = first;
    10. ++first;
    11. // 将元素插入到begin()之前
    12. transfer(begin(), old, first);
    13. }
    14. }

    sort

    几个重要参数分析

    1. fill : 当前可以处理的元素个数为2^fill个

    2. counter[fill] : 可以容纳2^(fill+1)个元素

    3. carry : 一个临时中转站, 每次将一元素插入到counter[i]链表中.

    在处理的元素个数不足2^fill个时,在counter[i](0之前转移元素

    步骤:

    每次读一个数据到carry中,并将carry的数据转移到counter[0]中
    当counter[0]中的数据个数少于2时,持续转移数据到counter[0]中
    当counter[0]的数据个数等于2时,将counter[0]中的数据转移到counter[1]…从counter[i]转移到counter[i+1],直到counter[fill]中数据个数达到2^(fill+1)个。
    ++fill, 重复步骤1
    sort用了一个数组链表用来存储2^i个元素, 当上一个元素存储满了之后继续往下一个链表存储, 最后将所有的链表进行merge归并(合并), 从而实现了链表的排序!

    1. //list 不能使用sort函数,因为list的迭代器是bidirectional_iterator, 而sort
    2. //sort函数要求random_access_iterator
    3. template<class T,class Alloc>
    4. void list::sort()
    5. {
    6. //如果元素个数小于等于1,直接返回
    7. if(node->next==node||node->next->next==node)
    8. return ;
    9. list carry; //中转站
    10. list counter[64];
    11. int fill=0;
    12. while(!empty())
    13. {
    14. carry.splice(carry.begin(),*this,begin()); //每次取出一个元素
    15. int i=0;
    16. while(iempty())
    17. {
    18. counter[i].merge(carry); //将carry中的元素合并到counter[i]中
    19. carry.swap(counter[i++]); //交换之后counter[i-1]为空
    20. }
    21. carry.swap(counter[i]);
    22. if(i==fill)
    23. ++fill;
    24. }
    25. // 将counter数组链表的所有节点按从小到大的顺序排列存储在counter[fill-1]的链表中
    26. for(int i=1;i
    27. {
    28. counter[i].merge(counter[i-1]);
    29. }
    30. // 最后将couter与carry交换, 实现排序
    31. swap(counter[fill-1]);
    32. }

    本篇文章有图解:(36条消息) stl中list的sort()函数解析_骑猪去兜风..的博客-CSDN博客_list sort stl 

    总结:

  • 相关阅读:
    PCB设计时如何选择合适的叠层方案
    想进入社交电商,但却害怕投入回本无望?来试一试这样做
    PHP自增构造_GET
    小白也能看懂的 ROC 曲线详解
    Vue生命周期
    智能运维和数字孪生赋能智慧城市管理服务平台
    NIO file 读取为字节数组
    简单博客网页
    QT事件及处理
    『现学现忘』Docker相关概念 — 8、虚拟化技术和容器技术的关系
  • 原文地址:https://blog.csdn.net/weixin_53459056/article/details/126968223