1. 程式人生 > >stl中list的sort演算法實現

stl中list的sort演算法實現

STL中有一個std::sort演算法,但它是不支援std::list的,因為list不提供RandomIterator的支援,但list自己提供了sort演算法,把list的元素按從小到大的方式來排序,程式碼長度到不長,但真是難以讀懂,後來扣持了一下午終於搞明白了,貼個總結上來。

list::sort的程式碼如下(sgi stl):

行數的確不多,但還真麻煩,我先說一下他是怎麼實現的,但具體為什麼這麼做,我不知道。

比如我們的list裡有如下幾個需要排序的元素:21,45,1,30,52,3,58,47,22,59,0,58。

排序的時候怎麼做,我們先定義若干中轉list在上述程式碼中定義了64個元素的陣列

list<_Tp, _Alloc> __counter[64]; 其中裡邊存什麼呢?他們都是用來中轉用的

__counter[0]裡存放2(0+1)次方個元素
__counter[1]裡存放2(1+1)次方個元素
__counter[2]裡存放2(2+1)次方個元素
__counter[3]裡存放2(3+1)次方個元素,依次類推

那又是怎麼個存放方法呢?一個指導原則就是當第i個元素即__counter[i]的內容個數等於2(i+1)次方時,就要把__counter[i]的資料轉移給__count[i+1]。

具體過程如下:

取出第1個數21,放到__counter[0]裡,這時__counter[0]裡有一個元素,小於2,繼續

__counter[0]: 21

__counter[1]: NULL

取出第2個數45,放到__counter[0]裡(不是簡單的放,而是排序放,類似兩個list做merge),這時__counter[0]裡有2個元素了,需要把這兩個元素轉移到__counter[1].

__counter[0]: NULL

__counter[1]: 21,45

取出第3個數1,放到__counter[0]裡,__count[0]與__count[1]都小於規定個數

__counter[0]: 1

__counter[1]: 21,45

取出第4個數30,放到__counter[0]裡,這時__counter[0]的個數等於2了,需要轉移到__counter[1]裡

__counter[0]: NULL

__counter[1]: 1,21,30,45

但這時__counter[1]裡的個數又等於4了,所有需要把__counter[1]的值轉移到__counter[2]裡,

__counter[0]: NULL

__counter[1]: NULL

__counter[2]: 1,21,30,45

然後取出52,放入__counter[0]

__counter[0]: 52

__counter[1]: NULL

__counter[2]: 1,21,30,45

然後取出3,放入__counter[0]

__counter[0]: 3,52

__counter[1]: NULL

__counter[2]: 1,21,30,45

這時候需要轉移

__counter[0]: NULL

__counter[1]: 3,52

__counter[2]: 1,21,30,45

然後取58

__counter[0]: 58

__counter[1]: 3,52

__counter[2]: 1,21,30,45

然後取47

__counter[0]: 47,58

__counter[1]: 3,52

__counter[2]: 1,21,30,45

需要轉移

__counter[0]: NULL

__counter[1]: 3,47,52,58

__counter[2]: 1,21,30,45

還需要轉移

__counter[0]: NULL

__counter[1]: NULL

__counter[2]: 1,3,21,30,47,45,52,58

還需要轉移

__counter[0]: NULL

__counter[1]: NULL

__counter[2]: NULL

__counter[3]: 1,3,21,30,47,45,52,58

然後再取59

__counter[0]: 59

__counter[1]: NULL

__counter[2]: NULL

__counter[3]: 1,3,21,30,47,45,52,58

然後取0

__counter[0]: 0,59

__counter[1]: NULL

__counter[2]: NULL

__counter[3]: 1,3,21,30,47,45,52,58

需要轉移

__counter[0]: NULL

__counter[1]: 0,59

__counter[2]: NULL

__counter[3]: 1,3,21,30,47,45,52,58

最後取58

__counter[0]: 58

__counter[1]: 0,59

__counter[2]: NULL

__counter[3]: 1,3,21,30,47,45,52,58

 腦算流程總算完了,但程式碼還是很難理解,先看一個幾個相關的函式吧

1.splice:把當前列表的__i位置元素刪除,儲存在__position裡

[cpp] void list::splice(iterator __position, list&, iterator __i)  

2.merge:把引數list的元素合併到當前list,引數list的內容會清空的

[c-sharp] void list<_Tp, _Alloc>::merge(list<_Tp, _Alloc>& __x)

/* Written     By     MaiK */

    STL中的list被實現為環狀的雙向連結串列,設定一個“哨兵”node作為end( )。鑑於list的記憶體分配模型,list不能使用通用的標準sort演算法,而是實現自身的sort,但是list有自己的成員函式sort()可供其自身呼叫,其實際模型是基於合併排序的。普通的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個元素的序列,這應該足夠了。

/* Written     By    Lamar */

    類似2進位制,每一次進位都是相鄰高位數值的一半,所以是類2進位制地。例如8,低位4滿之後會進4個到8的。

相關推薦

使用C++STL的deque實現作業系統FIFO、LRU頁面置換演算法

#include <iostream> #include <deque>//雙端佇列所在的標頭檔案 #include <algorithm>//find()函式所在的標頭檔案 using namespace std; cons

stlpartition演算法的解釋

Partition:分塊,將滿足條件的元素向前移動.(初始的相對位置將發生改變) 一個簡單的例子,把大於8的數分塊; bool isok(int num) {     return (num > 8); } void main() {     vector<

STL 容器 演算法 迭代器 之間的關係

https://blog.csdn.net/adobeadge/article/details/6750831 最近一直在看侯捷寫的《STL原始碼剖析》小有想法。故此一記 1,三者之間聯絡:         

《雙向迴圈連結串列STL的iterator實現

雙向迴圈連結串列,STL中的iterator實現 帶頭節點的連結串列 在列表頭部引入一個偽首節點來實現,這個節點被稱為頭節點。這個頭節點的資料部分不存放列表元素;它作為存放第一個元素的節點的前驅,其鏈域指向“真正的”首節點。頭節點的作用其實就是在迴圈連結串列中告訴你連結串列

MySQLJoin演算法實現原理通俗易懂

注意:MySQL 5.1.18之後的版本中才會體現出來 一:原理: 在MySQL 中,只有一種 Join 演算法,就是大名鼎鼎的 Nested Loop Join,他沒有其他很多資料庫所提供的 Hash Join,也沒有 Sort Merge Join。 1.Nested Loop

STLvector的實現及面試問題

class Vector { public: typedef T* Iterator; typedef const T* ConstIterator; Vector(size_t n = 3) :_start(new T[n]) , _finish(_s

lwipNagle 演算法實現

何謂愚笨視窗綜合症: 愚笨視窗綜合症有2種變現形式:接收方愚笨視窗綜合症和傳送方愚笨視窗綜合症。 考慮以下情形。當接收方的接收快取滿時,它會通知對方它的接收允許視窗為0,使傳送方不要再繼續傳送資料。這時接收應用程式從接收快取中讀入一個位元組,那麼就空出了一個位元組的空間。接

stllist的sort演算法實現

STL中有一個std::sort演算法,但它是不支援std::list的,因為list不提供RandomIterator的支援,但list自己提供了sort演算法,把list的元素按從小到大的方式來排序,程式碼長度到不長,但真是難以讀懂,後來扣持了一下午終於搞明白了,貼個總

STL×××源碼下載實現 iterator trail 的編程技巧

想是 rim void 指針類型 constant 偏特化 empty 思考 infer 《泛型編程和 STL》筆記及思考。 這篇文章主要記錄在 STL 中叠代器設計過程中出現的編程技巧,圍繞的 STL 主題為 (叠代器特征) Iterator traits 和 相關類型

多媒體技術 || 用位切割演算法實現影象減色

實現環境:python 處理一張紅蘋果圖: 先描述一下中位切割演算法吧: 將圖片內的所有畫素加入到同一個區域 對於所有的區域做以下的事: 計算此區域內所有畫素的 RGB 三元素最大值與最小值的差。 選出相差最大的那個顏色(R 或 G 或 B)

決策樹之ID3演算法實現(python) [置頂] 怒寫一個digit classification(不斷更新)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

推薦系統協同過濾演算法實現分析(重要兩個圖!!)

“協”,指許多人協力合作。 “協同”,就是指協調兩個或者兩個以上的不同資源或者個體,協同一致地完成某一目標的過程。 “協同過濾”,簡單來說,就是利用興趣相投或擁有共同經驗的群體的喜好來給使用者推薦感興趣的資訊,記錄下來個人對於資訊相當程度的迴應(如評分),以達到過濾的目的,進而幫助別人篩

圖解STL演算法的分類、簡介及其Demo

STL中包含演算法標頭檔案<algorithm>就可以使用其中的演算法了,使用這些通用的演算法可以使得程式碼更加簡單、易讀、通用。但是這些演算法有哪些呢?以及這些演算法的職能又是什麼?其實這些東西,候捷大師在他的《STL原始碼剖析》中都有列舉,且FluentCPP有一篇文章1

計算機圖形學實驗(三)——點畫圓演算法實現及其原始碼

1.中點畫圓演算法簡介:(以第一象限內靠近Y軸的1/8圓為例) 由於圓的對稱性,只需要考慮的圓上的點。舉例: 引入建構函式:。 分別表示點在圓外,圓上,圓內。 如圖3-8所示:.M是P1和P2中點。 當F(M)<0時,說明M在圓內,進而得知P1離圓弧更近;否則P

計算機圖形常用演算法實現1 DDA,點畫線法,bresenham演算法

打算手動實現圖形學中的絕大部分演算法。 執行環境winform+c# (程式碼是通用的,如果在其他地方畫圖,只需要替換掉畫點的函式即可) 我們的函式預設是按x座標順序遞增傳入的,因此在呼叫下面函式之前,需要保證p1.x<p2.x(可以減少討論數量) Point pp =

【JTR&hashcat&】JTR和hashcat具體演算法部分實現的資訊獲取

一. JTR 1. JTR中演算法部分的各大函式 get_salt():從密文輸出中還原計算時用的salt,比較多的密文輸出時候都是對真實的密文值,還有salt值進行16進位制化輸出; get_binary():從密文輸出中還原計算出的真實密文結果; set_key():對明文進行的,參與計算之前的轉

CC++實現區塊鏈()之演算法實現

1、矩陣類實現 class Martix { public: static const int circle_s = 1; //假定向量環路為1; static const int KEY =Martix::circle_s * 8; private: unsigned long long

Python實現演算法導論 第三版》演算法 第2章 演算法基礎

第2章 演算法基礎 1. 插入排序 P17。插入排序比較簡單。 class InsertionSort: def sort(self, A): for i in range(

二叉樹序遍歷(非遞迴)演算法實現--C語言

今天繼續二叉樹的學習。 昨天寫了一遍二叉樹的先序遍歷(非遞迴)演算法,今天寫一下二叉樹的二叉樹的中序遍歷(非遞迴)演算法。中序遍歷的非遞迴演算法有兩種,但是個人覺得只要掌握一種就可以了,只要自己的邏輯清晰,會哪一種又有什麼關係呢~ 首先給出今天的二叉樹的示例圖: 程式碼如下:

Python實現演算法導論 第三版》演算法 第6章 堆排序

第6章 堆排序 1. 堆 堆是一個數組,它可以被看成一個近似的完全二叉樹。樹上的每一個結點對應陣列中的一個元素。除最底層外,該樹是完全充滿的,而且是從左向右填充。表示堆的陣列包括兩個屬性:A.le