STL中關於list容器的sort函式詳解

2021-08-29 12:25:16 字數 2989 閱讀 3239

因為在stl中stl_algo中提供有sort函式,他的函式原型:

template inline void sort(randomaccessiterator first, randomaccessiterator last);

template inline void sort(randomaccessiterator first, randomaccessiterator last,

compare comp);

我們看到關於迭代器都是 randomaccessiterator型別的,就是最高層次的指標,但是我們list中迭代器型別為:

typedef bidirectional_iterator_tag iterator_category;
由於bidirectional_iterator_tag是random_access_iterator_tag的子類,不會傳遞呼叫random_access_iterator_tag版本的排序函式,那麼關於list中的sort函式的實現就放在了stl_list中來進行實現了

struct random_access_iterator_tag : public bidirectional_iterator_tag {};
splice函式:在sort函式中使用到了這種過載型別

//將list &中i位置上的節點,插入到this的position位置之前,list &中i位置上的節點消失

void splice(iterator position, list&, iterator i)

swap函式,我們這裡使用乙個栗子來看一下swap函式,因為我最後沒有找到swap的原函式在**,函式可以實現將兩個list容器裡的所有內容互換(感覺只交換一下最後尾部的節點就好)

#include #include using namespace std;

int main()

merge函式:

//將list x的內容全部新增到當前操作的list中,並且按照順序進行插入

//前提是兩個list都是遞增排序的

template void list::merge(list& x)

else

++first1;

if (first2 != last2) transfer(last1, first2, last2);

}

這裡要著重說一下,因為在list中進行轉移操作,都是指標的移動,而不知重新建造空間,使用建構函式,所以在merge函式執行完之後,list x中的內容全都會消失,只剩最後的指向自身的節點。

這裡實現的sort函式有點類似於歸併排序,但是很神奇的是,表面上看不出什麼限制,但是他的list陣列counter,每個裡面的元素最多都是2^i個,這裡我覺得也是理解的難點。

template void list::sort() 

carry.swap(counter[i]); //carry不為空的話,那麼就將所有內容放到後面乙個counter中

if (i == fill) ++fill; //說明前面的所有counter都進行了更新,那麼之前第fill中存在的元素個數為2^(fill+1),所以上面一句話中開乙個新的counter來儲存,這裡來更新迴圈次數

} for (int i = 1; i < fill; ++i) counter[i].merge(counter[i-1]); //最後合併所有的counter

swap(counter[fill-1]);

}

為什麼counter[i]最多儲存2^i個內容?

我認為這裡關鍵的位置就是!counter[i].empty()以及if(i==fill) ++fill,這裡因為每次carry都是攜帶乙個節點來,第一次迴圈不再陳述,假設為第二次迴圈,首先和counter[0]合併,然後counter[0]中內容為2個,執行一次swap,那麼carry中內容為2個,counter[0]為空,但是上次counter[0]的大小為1,那麼第一次迴圈的時候會滿足i==fill條件,fill會變為1,但是counter[1] 為空,所以後面會將carry中的兩個元素放入counter[1]中,依次這樣向上推進,向counter[2]中存放資料的時候一定是counter[0]含有乙個元素,counter[1]中含有兩個元素,當carry再次攜帶乙個元素來的時候,會將所有元素放入counter[2]中,counter[2]中含有4個元素

因為函式merge執行完後,元素都是有序的,那麼在最後進行合併的時候會非常省時,基本上就是歸併排序的思想。

我們可以來模擬一下這個過程,使用鍊錶:8 ,2 ,5, 1, 9,  7

第一次:carry = 8,但是counter[0]為空,那麼直接將carry放入到counter[0]中,i == fill,此時fill++

第二次:carry = 2,首先與counter[0]合併,counter[0] = ,carry = null,此時counter[1] = fill,直接將所有元素放入counter[1]中,counter[0] = null,counter[1] =

第三次:carry = 5,直接將5放入counter[0]中,因為counter[0],為空

第四次:carry = 1,與counter[0]合併,生成序列,再與counter[1]合併,生成序列,將序列放入counter[2]中,前面全部為空

第五次:carry = 9,直接放入到counter[0]中

第六次:carry = 7,與counter[0]合併,且因為counter[1] = null,所以將合併的序列放入counter[1]中,形成

最後將counter[0]-counter[3]合併到counter[3]中,得到正確的序列

使用陣列簡化的歸併排序

《stl原始碼分析》侯捷著

STL中的 list 容器詳解

list是一種序列式容器。list容器完成的功能實際上和資料結構中的雙向鍊錶是極其相似的,list中的資料元素是通過鍊錶指標串連成邏輯意義上的線性表,也就是list也具有鍊錶的主要優點,即 在鍊錶的任一位置進行元素的插入 刪除操作都是快速的。list的實現大概是這樣的 list的每個節點有三個域 前...

STL順序容器 list

list是乙個線性鍊錶結構,它的資料由若干個節點構成,每乙個節點都包括乙個 息塊 即實際儲存的資料 乙個前驅指標和乙個後驅指標。它無需分配指定 記憶體大小且可以任意伸縮,這是因為它儲存在非連續的記憶體空間中,並且由指 針將有序的元素鏈結起來。由於其結構的原因,list 隨機檢索的效能非常的不好,因為...

STL通用容器之 list 容器

list容器 相對於vector的連續線性空間,list是乙個雙向鍊錶,它有乙個重要性質 插入操作和刪除操作都不會造成原有的list迭 器失效,每次插入或刪除乙個元素,就配置或釋放乙個元素空間。也就是說,對於任何位置的元素插入或刪除,list 遠是常數時間。1 建構函式 listc 建立乙個空的li...