array和list的排序演算法對比(一) 快速排序

2021-07-10 09:09:12 字數 2870 閱讀 5251

一般來說,我們討論排序都是針對陣列結構。陣列的特點是:可以很方便地進行隨機訪問,但是增刪元素比較耗時。因此,針對陣列的排序,通常會避免元素的增刪操作,改為元素交換。同時,常採用二分的方法實現高效排序演算法。

鍊錶與陣列相反,隨機訪問非常耗時,但增刪元素很簡單。因此鍊錶的排序和陣列也會有所不同。

這篇部落格針對陣列和鍊錶的不同,分析了常用排序演算法——快速排序在陣列和鍊錶中的實現。

注:我們規定排序的語義如下:

sort(begin, end)表示對[begin, end)之間的元素排序,包含begin,但不包含end

int num[n];

quick_sort(int *begin, int *end); //begin和end為指向陣列元素的指標

快速排序的思路是:以某個元素為切分點,把小於它的元素全部交換到前面,大於它的元素交換到後面,使切分點成為已排序元素,再對切分點前後進一步排序。

以首元素為切分點,**如下:

void quick_sort(int *begin, int *end)else

}partition--;

swap(*partition, *begin); //begin放在切分點位置

quick_sort(begin, partition);

quick_sort(partition + 1, end);

}

快速排序的關鍵在於切分陣列。上述**中把陣列分成4個部分:

1. begin元素

2. (begin, partition)為小於begin的元素

3. [partition, tmp)為大於等於begin的元素,

4. [tmp, end)為未排序元素

while迴圈用於處理tmp處元素,擴充套件第1和第2部分,縮減第3部分。處理方法是:若tmp小於begin元素,則tmp與partition處元素交換,再各自加1;若tmp大於等於begin元素,直接將tmp自加即可。

當tmp移動到end的時候,陣列就只剩下前3個部分。然後,partition自減1,即為小於切分元素的最後乙個元素。將partition元素和begin處元素交換,則陣列的3部分如下:

1. [begin, partition)小於切分元素

2. partition處為切分元素

3. (partition, end)大於等於切分元素

至此切分陣列工作完成,即可進行下一步的遞迴。

這裡以乙個簡單的雙向鍊錶作為示例:

class

node;

此外,設煉表的首節點為head,尾節點為tail,均不儲存實際資料,即,如果乙個鍊錶有三個元素1,2,3,則鍊錶的結構應為:

head node(1) node(2) node(3) tail

此處headtail不儲存資料,是為了在對鍊錶進行操作時無需考慮邊界情形。

對照陣列排序的思路,可以寫出鍊錶的快速排序:

void quick_sort(node *begin, node *end)else

}quick_sort(tmp_head->next, begin);

quick_sort(begin->next, end);

}

鍊錶的快速排序從總體上和陣列的排序比較接近,也需要切分鍊錶,但切分的方式則略有不同。

鍊錶被分為以下4部分:

1. [tmp_head->next, begin)小於切分元素

2. begin處為切分元素

3. [begin->next, tmp)大於等於切分元素

4. [tmp, end)尚未處理

與陣列快速排序相同,鍊錶排序也需要借助while迴圈後移tmp節點,並擴充套件1和3部分。

通過對比可以發現,鍊錶快速排序與陣列快速排序的不同點為:

1. 陣列排序中,需要不斷修正partition的位置,而鍊錶排序中,切分點始終在begin處。

2. 陣列排序中,為避免增刪元素,需通過交換將小於切分元素的節點向前移動。而鍊錶排序中,只需要將小於begin的節點從原位置刪除,再插入到begin正前方即可。

3. 由於沒有交換操作,鍊錶的快速排序結構更加清晰。同時,鍊錶的快速排序也是穩定排序

在陣列和鍊錶的排序中,需要充分考慮到陣列和鍊錶在隨機訪問和增刪方面的複雜度,合理編寫**。

以上陣列快速排序演算法是不穩定的,而鍊錶快速排序演算法是穩定的。但一般來說鍊錶快速排序的效率低於陣列,這是因為鍊錶的結構更為複雜,且無法有效利用程式區域性性。

陣列和鍊錶的快速排序平均時間複雜度均為o(

nlog

n),平均空間複雜度為o(

logn

) 。

以上程式以首節點為切分點,在已排序陣列或鍊錶中會遇到最壞複雜度,最壞時間複雜度為o(

n2) ,最壞空間複雜度為o(n)。

值得注意的是,陣列可以採用隨機選擇切分節點的方式使最壞情況隨機化,但鍊錶沒有隨機訪問特性,因此無法高效地隨機選擇切分節點。也就是說,鍊錶的快速排序演算法是有漏洞的。

Array和List的區別

array和list都屬於順序表。因為list是乙個鍊錶,所以我需要從第乙個元素開始逐個next到所需索引的元素。這是乙個耗時的過程。陣列必須要在初始化時分配固定的大小,比如說int a new int 3 如果我們僅僅寫int a new int 編譯器就會無情地給我們報錯。但是list由於空間不...

Array和List的異同

array和list的異同 array的建立格式是 型別 eg string array new string 5 可以在建立時限定長度,但在後面使用中不可以更改。直接賦值 不適用於二維陣列 引用賦值。只能選其一,且不能重複賦值。可以放基本型別資料和物件。list建立格式是 型別 泛型 eg lis...

Array和List的轉換

呼叫list的toarray 方法,可以直接規定引數陣列大小為1,如果不夠,方法將自動建立合適大小的陣列 listlist new arraylist list.add aaa list.add bbb string s list.toarray new string 1 for string ss...