日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STL 中的链表排序

發布時間:2023/12/13 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STL 中的链表排序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一直以來學習排序算法, 都沒有在鏈表排序上下太多功夫,因為用得不多。最近看STL源碼,才發現,原來即使是鏈表,也能有時間復雜度為O(nlogn)的算法,

大大出乎我的意料之外,一般就能想到個插入排序。

下面的代碼就是按照源碼寫出的(去掉了模板增加可讀性),注意forward_list是C++11新加的單向鏈表,這里選這個是因為它更接近我們自己實現鏈表時的做法。

void sort_list(forward_list<int>& l){auto it = l.begin();if (l.empty() || ++it == l.end())return;forward_list<int> carry;forward_list<int> counter[64];//總共只設立了64個桶,因為第i個桶被填充的時候,里面至多2^i個元素,2^64,遠超一般元素數目int fill = 0; //fill記錄的是當前填到哪個桶了while (!l.empty()){carry.splice_after(carry.cbefore_begin(), l, l.cbefore_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]);l.swap(counter[fill - 1]); }

  關于此算法的分析:網上很多爭論這個到底是快速排序還是歸并排序的(侯捷的書上說是快排)。

? ? ? 為了理解這個代碼,可以手動運行一下。

? ? ? fill,記錄用到了幾個桶,最外層循環保證這樣一個事實:從第0個桶到第fill - 1個桶里面,要么為空,要么存儲有2^fill個元素,而且是有序鏈表。

? ? ? 每次與新取下的元素(存儲在carry中)合并的桶都是counter[0]。如果第0個桶里沒有元素,那就直接放進去carry.swap(counter[i])。下一輪循環的

? ? ?時候,因為counter[0]里有元素了,就會進入內層循環,這時候,counter[i].merge(carry)使得第0個桶變為一個含兩個元素的鏈表,然后內層循環第二步,又將這個鏈表

轉移到carry中,下一輪內層循環的時候,帶有兩個元素的carry就會爭取與第1個桶合并(如果第1個桶不空的話),如果第一個桶為空,它將退出內層循環并將元素放進第一個桶,(此時發現i == fill,于是fill變為2)然后下一輪外層循環繼續從鏈表中取下一個元素,(此時counter[0]為空,counter[1]中含有兩個元素),如前面一樣,先是發現counter[0]是空的,進不去內層循環,于是直接把元素填到counter[0]中,下一次外層循環又取一個元素,進入內層循環,與counter[0]合并,交換,然后下一輪內層循環中,帶有兩個元素的carry就會與帶有兩個元素的counter[1]合并,交換, i == fiil == 2退出內層循環,四個元素變到第2個桶中,fill++。

?

?

?

? ? ? ? ? ? ? ? 走完這一遍之后,感覺清晰了,但是除了外層循環的循環不變條件以外,實在是很難從基本的快排或歸并排序的思想中想到這樣去做。

轉載于:https://www.cnblogs.com/hustxujinkang/p/4111510.html

總結

以上是生活随笔為你收集整理的STL 中的链表排序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。