在兩位亦師亦友的朋友的幫助下,準(zhǔn)備從零開始學(xué)習(xí)算法,第一課是從最簡單的排序算法
開始學(xué)習(xí)九妈。
本篇文章中的內(nèi)容是看了別人的文章和書籍的總結(jié)丽蝎,再加上兩位朋友的細心教導(dǎo)猎拨,最后加上自己的理解膀藐。
1.排序介紹
在本文中,我們會依次來介紹10中排序方法分別是:冒泡排序
红省、選擇排序
额各、插入排序
、快速排序
吧恃、希爾排序
虾啦、歸并排序
、桶排序
痕寓、計數(shù)排序
傲醉、基數(shù)排序
、堆排序
呻率。
在排序的過程中我們會分析算法中幾個基本的特點:
-
時間復(fù)雜度
:算法執(zhí)行需要的時間硬毕。 -
空間復(fù)雜度
:算法執(zhí)行需要的額外的空間(內(nèi)存)。 -
穩(wěn)定性
:算法執(zhí)行過程中相同的數(shù)字相對位置是否交換礼仗。
在文章提到的所有的排序的數(shù)據(jù)都默認是正整數(shù)
吐咳,排序的順序是遞增
。
2.排序詳解
2.1.冒泡排序(Bubble Sort)
冒泡排序
是一種較簡單的排序方法元践,基本的流程就是:
- 遍歷所有的數(shù)據(jù)韭脊,比較相鄰的兩個數(shù)字,如果左邊的大于右邊的數(shù)字单旁,就交換沪羔。經(jīng)過一次遍歷之后,數(shù)組中最大的數(shù)字就會在數(shù)組的末尾了象浑。
- 重復(fù)1步驟蔫饰,直到數(shù)組中所有的數(shù)字右邊的都比左邊的大,這樣就完成了一個有序的數(shù)組融柬,就像水中的氣泡一樣死嗦,慢慢浮上了水面。
vector<int> bubbleSort1(vector<int> arr) {
int count = arr.size();
for (int i = 1; i < count; i++) {
for (int j = 1; j < count - i; j++) {
if (arr[j] < arr[j - 1]) {
// 交換
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
return arr;
}
從上述代碼中可以看出粒氧,冒泡排序的需要兩層循環(huán)越除,所以時間復(fù)雜度為,排序過程中只用到了常數(shù)級的額外空間外盯,所以空間復(fù)雜度為
摘盆,算法中只有在左邊大于右邊的時候才交換,相同數(shù)字的相對位置沒有改變饱苟,所以是一種穩(wěn)定的排序算法孩擂。
優(yōu)化
但是如果數(shù)據(jù)已經(jīng)是有序的呢?上面的算法的時間復(fù)雜度還是箱熬,所以我們需要對算法改進一下类垦,讓它在有序的情況下只遍歷一次就夠了狈邑,下面的算法就是使用一個標(biāo)記來記錄數(shù)組是否被交換過,如果交換過蚤认,說明數(shù)組是無序的米苹,如果沒有交換過,說明數(shù)組已經(jīng)是有序的了砰琢。這樣在已經(jīng)有序的情況下時間復(fù)雜度為
蘸嘶。
vector<int> bubbleSort2(vector<int> arr) {
// 記錄是否交換
bool flag = true;
while (flag) {
flag = false;
for (int i = 1; i < arr.size(); i++) {
if (arr[i] < arr[i - 1]) {
// 交換
int temp = arr[i];
arr[i] = arr[i - 1];
arr[i - 1] = temp;
flag = true;
}
}
}
return arr;
}
2.2.選擇排序(Selection Sort)
選擇排序
是一種簡單直觀的排序方法,基本的流程就是:
1.從待排序的數(shù)組中選出一個最小的數(shù)據(jù)陪汽,放在起始位置训唱。
2.從剩余待排序的數(shù)組中選出一個最小的數(shù)據(jù),放到已排序數(shù)組的末尾位置挚冤。
3.重復(fù)2步驟况增,直到所有的數(shù)組都變成已排序。
vector<int> selectionSort(vector<int> arr) {
int minIndex;
for (int i = 0; i < arr.size() - 1; i++) {
minIndex = i;
for (int j = i + 1; j < arr.size(); j++) {
// 先找出一個最小的數(shù)
minIndex = arr[j] < arr[minIndex] ? j : minIndex;
}
// 和第i位交換
int temp = arr[minIndex];
arr[minIndex] = arr[i];
arr[i] = temp;
}
return arr;
}
從上述代碼中可以看出你辣,選擇排序需要兩層循環(huán)巡通,所以時間復(fù)雜度為尘执,排序過程中只用到了常數(shù)級的額外空間舍哄,所以空間復(fù)雜度為
,選擇排序雖然和冒泡排序雖然類似誊锭,但是卻是一種不穩(wěn)定的排序算法表悬。
舉個??:假如有數(shù)組[4, 5, 4, 3, 6],當(dāng)?shù)谝淮窝h(huán)的時候丧靡,3是最小的數(shù)據(jù)蟆沫,所以3和第一個4交換,如此以來兩個4的相對位置就已經(jīng)發(fā)生了變化温治,所以是不穩(wěn)定的排序算法饭庞。
2.3.插入排序(Insertion Sort)
插入排序
是一種簡單直觀的排序方法,基本的流程就是:
1.先將數(shù)組分成兩部分:已排序和待排序熬荆,已排序的數(shù)組默認放一個舟山。
2.從剩余待排序的數(shù)組起始位置取一個,插入到已排序數(shù)組的相應(yīng)位置卤恳。
3.重復(fù)2步驟累盗,直到所有的數(shù)組都變成已排序。
vector<int> insertionSort(vector<int> arr) {
// 已經(jīng)排好序的位置
int sortedIndex = 0;
int current;
// 遍歷未排序的數(shù)組
for (int i = 1; i < arr.size(); i++) {
current = arr[i];
// 把取出來的數(shù)據(jù)插入到已排序的數(shù)組中
for (int j = sortedIndex; j >= 0; j--) {
if (current > arr[j]) {
arr[j + 1] = current;
sortedIndex++;
break;
} else if (current < arr[j]) {
arr[j + 1] = arr[j];
if (j == 0) {
arr[0] = current;
sortedIndex++;
break;
}
}
}
}
return arr;
}
從上述代碼中可以看出突琳,插入排序需要兩層循環(huán)若债,所以時間復(fù)雜度為,排序過程中只使用了常數(shù)級的額外空間拆融,所以空間復(fù)雜度為
蠢琳,插入排序是一種穩(wěn)定的排序算法啊终,插入過程中相同元素的相對位置不會變化。
2.4.快速排序(Quick Sort)
快速排序
的基本思想是:通過一趟排序?qū)⒁判虻臄?shù)據(jù)分割成獨立的兩部分傲须,其中一部分的所有數(shù)據(jù)都比另外一部分的所有數(shù)據(jù)都要小孕索,然后再按此方法對這兩部分?jǐn)?shù)據(jù)分別進行快速排序,整個排序過程可以遞歸進行躏碳,以此達到整個數(shù)據(jù)變成有序序列搞旭。
1.先確定一個關(guān)鍵值,重新排列數(shù)組菇绵,把比關(guān)鍵值小的放在關(guān)鍵值的左邊肄渗,把比關(guān)鍵值大的放在關(guān)鍵值的右邊。
2.把數(shù)組從關(guān)鍵值分割成兩個數(shù)組咬最,分別把兩個新的數(shù)組執(zhí)行步驟1翎嫡。
3.重復(fù)2步驟,直到最小的數(shù)組不能分割永乌,現(xiàn)在數(shù)組就已經(jīng)是一個有序的數(shù)組了惑申。
void quickSorting(vector<int> &arr, int low, int high) {
if (low >= high) {
return;
}
// 先保存左右點
int left = low;
int right = high;
// 默認關(guān)鍵值為數(shù)組的最左邊的點
int key = arr[left];
while (left < right) {
while (left < right && arr[right] >= key) {
right--;
}
arr[left] = arr[right];
while (left < right && arr[left] <= key) {
left++;
}
arr[right] = arr[left];
}
arr[left] = key;
quickSorting(arr, low, left - 1);
quickSorting(arr, left + 1, high);
}
vector<int> quickSort(vector<int> arr) {
quickSorting(arr, 0, arr.size() - 1);
return arr;
}
從上述代碼中可以看出,快速排序是遞歸調(diào)用函數(shù)翅雏,所以時間復(fù)雜度為圈驼,空間復(fù)雜度也為為
(作為算法新手的我其實并不會推導(dǎo),我也是死記的)望几,快速排序涉及到多次交換绩脆,是一種不穩(wěn)定的排序算法(這里不好舉??,等我想到合適的再加上)橄抹。
2.5.希爾排序(Shell Sort)
希爾排序
是插入排序的一種靴迫,又稱“縮小增量排序”,是插入排序的改進版楼誓,基本的流程就是:
1.先設(shè)定一個步長玉锌,數(shù)組中距離為步長的數(shù)據(jù)都被編成一組,統(tǒng)一我們都取數(shù)組長度的二分之一疟羹,特別說明一下這里主守,如果步長是數(shù)組長度的二分之一,那么就是兩個數(shù)據(jù)一組阁猜,首先我們會先對這兩個數(shù)據(jù)進行排序丸逸。
2.完成所有組排序之后,把步長除2剃袍,那數(shù)組中的數(shù)據(jù)就變成了4個一組黄刚,繼續(xù)對數(shù)組中的數(shù)據(jù)排序。
3.完成所有組排序之后民效,把步長除2憔维,繼續(xù)對數(shù)組中的數(shù)據(jù)排序涛救。
4.重復(fù)步驟3,直到步長為1业扒,這時候數(shù)組就剩下一個了检吆,就是我們最終需要的已經(jīng)排序的數(shù)組。
vector<int> shellSort(vector<int> arr) {
int step = arr.size() / 2;
while(step >= 1) {
// 把距離為step的元素編為一組 掃描所有組
for (int i = step; i < arr.size(); i++) {
int j = 0;
int temp = arr[i];
// 對距離為gap的元素組進行排序
for (j = i - step; j >= 0 && temp < arr[j]; j = j - step) {
arr[j + step] = arr[j];
}
arr[j + step] = temp;
}
// 減小步長
step /= 2;
}
return arr;
}
從上述代碼中可以看出程储,希爾排序雖然是兩層循環(huán)蹭沛,但是時間復(fù)雜度并不是,因為兩層循環(huán)的此次都是遠遠小于n的章鲤,所以平均時間復(fù)雜度為
(弱雞的我還是不知道是怎么推導(dǎo)出來的)摊灭,只使用了常數(shù)單位的額外空間,空間復(fù)雜度為
败徊,是一種不穩(wěn)定的排序算法帚呼。
2.6.歸并排序(Merge Sort)
歸并排序
是建立在歸并操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應(yīng)用。將已有序的子序列合并皱蹦,得到完全有序的序列煤杀;即先使每個子序列有序,再讓子序列段合并成有序的序列沪哺,基本的流程就是:
1.先把現(xiàn)有的數(shù)組分成兩個數(shù)組沈自。
2.再分別對兩個數(shù)組進行歸并排序。
3.把已經(jīng)排序好的兩個數(shù)組合并成一個新的有序數(shù)組凤粗。
vector<int> merge(vector<int> left, vector<int> right) {
vector<int> res;
// 兩個數(shù)組歸并為一個數(shù)組
int one = 0;
int two = 0;
while (one < left.size() && two < right.size()) {
if (left[one] < right[two]) {
res.push_back(left[one++]);
} else {
res.push_back(right[two++]);
}
}
while (one < left.size()) {
res.push_back(left[one++]);
}
while (two < right.size()) {
res.push_back(right[two++]);
}
return res;
}
vector<int> mergeSort(vector<int> arr) {
if (arr.size() < 2) {
return arr;
}
// 先將數(shù)組分為兩個
int mid = arr.size() / 2;
vector<int> left, right;
copy(arr.begin(), arr.begin() + mid, back_inserter(left));
copy(arr.begin() + mid, arr.end(), back_inserter(right));
return merge(mergeSort(left), mergeSort(right));
}
從上述代碼中可以看出酥泛,歸并排序是遞歸調(diào)用函數(shù),所以時間復(fù)雜度為嫌拣,歸并排序的遞歸是在排序的過程中,但是內(nèi)存的消耗卻是在合并的過程中呆躲,所以空間復(fù)雜度為
异逐,是一種穩(wěn)定的排序算法。
2.7.桶排序(Bucket Sort)
桶排序
又稱箱排序
插掂,工作的原理是將數(shù)組分到有限數(shù)量的桶子里灰瞻。每個桶子再個別排序(有可能再使用別的排序算法或是以遞歸方式繼續(xù)使用桶排序進行排序)。
后面的幾種排序主要是偏理解辅甥,所以我都先舉個??來說明一下:
假如酝润,現(xiàn)在有1w個年齡不等的人(最大年齡為110, 最小年齡為1歲)璃弄,需要按照年齡的升序來排列要销。
那我們就可以創(chuàng)建11個桶,編號為1的桶都放1-10歲的人夏块,編號為2的桶都放11-20歲的人疏咐,把所有的人都依次放到桶中纤掸,分別排序每個桶中的數(shù)據(jù),最后按順序合并稱一個大數(shù)組浑塞,就是最后需要的已排序的數(shù)組了借跪。
基本的流程就是:
1.先計算需要的桶的數(shù)量。
2.分別把所有數(shù)組存放到相應(yīng)的桶中酌壕。
3.把每個桶中的數(shù)據(jù)使用快速排序進行排序掏愁。
4.把所有桶中的數(shù)據(jù)依次合并成一個大數(shù)組,就是最后需要的已排序的數(shù)組了卵牍。
vector<int> bucketSort(vector<int> arr) {
if (arr.size() < 2) {
return arr;
}
// 先找出排序數(shù)組中的最大和最小的元素
int maxInt = arr.front();
int minInt = arr.front();
for (int i = 0; i < arr.size(); i++) {
maxInt = max(arr[i], maxInt);
minInt = min(arr[i], minInt);
}
// 初始化桶
// 桶大小
int bucketSize = 5;
// 桶個數(shù) 向上取整
int bucketCount = ceil((maxInt - minInt + 1) / 5.0);
vector<vector<int>> bucket(bucketCount);
for (int i = 0; i < arr.size(); i++) {
// 判斷放到哪一個桶中
int index = (arr[i] - minInt) / bucketSize;
bucket[index].push_back(arr[i]);
}
// 分別對每個桶中的數(shù)據(jù)快速排序
arr.resize(0);
for (int i = 0; i < bucket.size(); i++) {
if (bucket[i].size() > 0) {
quickSort(bucket[i]);
arr.insert(arr.end(), bucket[i].begin(), bucket[i].end());
}
}
return arr;
}
從上述代碼中可以看出托猩,桶排序是兩個并列的循環(huán),如果數(shù)據(jù)的個數(shù)為n辽慕,桶的數(shù)量為m京腥,個人理解是因為已經(jīng)分成了m個桶了,快速排序的時間可以忽略不計溅蛉,所以時間復(fù)雜度為公浪,空間復(fù)雜度為
(但是具體的公式還是需要通過推導(dǎo)出來),是一種穩(wěn)定的排序算法船侧。
2.8.計數(shù)排序(Counting Sort)
計數(shù)排序
是一個非基于比較的排序算法欠气。它的優(yōu)勢在于在對一定范圍內(nèi)的整數(shù)排序時,它的復(fù)雜度為Ο(n+k)(其中k是整數(shù)的范圍)镜撩,快于任何比較排序算法预柒。
其實計數(shù)排序是桶排序的一種情況,舉個??來說明一下(還是上面的例子):
假如袁梗,現(xiàn)在有1w個年齡不等的人(最大年齡為110宜鸯, 最小年齡為1歲),需要按照年齡的升序來排列遮怜。
那我們就可以創(chuàng)建110個桶淋袖,編號為1的桶都放1歲的人,編號為2的桶都放2歲的人锯梁,把所有的人都依次放到桶中即碗,(這里并不需要再次排序,因為每一個桶中的人年齡都是相同的)陌凳,最后按順序合并稱一個大數(shù)組剥懒,就是最后需要的已排序的數(shù)組了。
基本的流程就是:
1.先計算需要的桶的數(shù)量合敦。
2.分別把各個數(shù)據(jù)的個數(shù)存放到相應(yīng)的桶中初橘。
3.根據(jù)數(shù)據(jù)的數(shù)量,依次合并成一個大數(shù)組,就是需要的已排序的數(shù)組了壁却。
vector<int> countingSort(vector<int> arr) {
if (arr.size() < 2) {
return arr;
}
// 先找出排序數(shù)組中的最大和最小的元素
int maxInt = arr.front();
int minInt = arr.front();
for (int i = 0; i < arr.size(); i++) {
maxInt = max(arr[i], maxInt);
minInt = min(arr[i], minInt);
}
// 創(chuàng)建一個數(shù)組可以承載最小到最大值中的所有的元素批狱。
vector<int> bucket(maxInt - minInt + 1);
for (int i = 0; i < arr.size(); i++) {
bucket[arr[i] - minInt]++;
}
int index = 0;
for (int i = 0; i < bucket.size(); i++) {
while (bucket[i] > 0) {
arr[index++] = i;
bucket[i]--;
}
}
return arr;
}
從上述代碼中可以看出,計數(shù)排序和桶排序一樣展东,所以時間復(fù)雜度為赔硫,空間復(fù)雜度為
(但是具體的公式還是需要通過推導(dǎo)出來),是一種穩(wěn)定的排序算法盐肃。
但是一般都會有一個問題爪膊,既然和桶排序這么像,那為什么還叫計數(shù)排序砸王,直接叫桶排序好了推盛,原因是我們在存數(shù)據(jù)的時候并沒有存具體的數(shù)據(jù),而是存的數(shù)據(jù)的數(shù)量谦铃,所以叫計數(shù)排序耘成。
2.9.基數(shù)排序(Radix Sort)
基數(shù)排序
屬于“分配式排序”,又稱“桶子法”驹闰,顧名思義瘪菌,它是透過鍵值的部份資訊,將要排序的元素分配至某些“桶”中嘹朗,藉以達到排序的作用师妙。
舉個??來說明一下:
假如,現(xiàn)在有1w個11位的手機號碼屹培,需要按照升序來排列默穴。
那我們就可以創(chuàng)建10個桶(分別編號為0-10),把倒數(shù)第一個數(shù)字和桶編號相同的數(shù)據(jù)放在一個桶中褪秀。
已經(jīng)排序好的數(shù)據(jù)蓄诽,繼續(xù)把倒數(shù)第二個數(shù)字和桶編號相同的數(shù)據(jù)放在一個桶中,一直重復(fù)溜歪,直到把第一個數(shù)字和桶編號相同的數(shù)據(jù)放在一個桶中若专。
最后按順序合并稱一個大數(shù)組,就是最后需要的已排序的數(shù)組了蝴猪。
基本的流程就是:
1.先計算需要的桶的數(shù)量,如果是正整數(shù)膊爪,我們的桶數(shù)量一般都是10自阱。
2.把倒數(shù)第一個數(shù)字和桶編號相同的數(shù)據(jù)放在一個桶中。
3.重復(fù)步驟2米酬,直到把第一個數(shù)字和桶編號相同的數(shù)據(jù)放在一個桶中
4.把桶中的數(shù)據(jù)取出沛豌,依次合并成一個大數(shù)組,就是需要的已排序的數(shù)組了。
vector<int> radixSort(vector<int> arr) {
if (arr.size() < 2) {
return arr;
}
// 先找出排序數(shù)組中的最大和最小的元素
int maxInt = arr.front();
for (int i = 0; i < arr.size(); i++) {
maxInt = max(arr[i], maxInt);
}
// 求出最大的位數(shù)
int maxDigit = 1;
while (maxInt / 10 > 0) {
maxInt = maxInt / 10;
maxDigit++;
}
for (int i = 0; i < maxDigit; i++) {
// 創(chuàng)建一個數(shù)組為10的數(shù)組
vector<vector<int>> bucket(10);
// 分別放到不同的桶中
for (int j = 0; j < arr.size(); j++) {
// 計算i個位置的數(shù)
int num = (arr[j] % (int)pow(10, i + 1)) / (int)pow(10, i);
bucket[num].push_back(arr[j]);
}
// 把桶中的數(shù)據(jù)重新取出
arr.resize(0);
for (int j = 0; j < bucket.size(); j++) {
if (bucket[j].size() > 0) {
for (int k = 0; k < bucket[j].size(); k++) {
arr.push_back(bucket[j][k]);
}
}
}
}
return arr;
}
從上述代碼中可以看出加派,基數(shù)排序是兩層循環(huán)叫确,如果數(shù)據(jù)的個數(shù)為n,桶的數(shù)量為m(桶的數(shù)量是根據(jù)數(shù)據(jù)的最大位數(shù)決定的)芍锦,所以時間復(fù)雜度為竹勉,空間復(fù)雜度為
(但是具體的公式還是需要通過推導(dǎo)出來),是一種穩(wěn)定的排序算法娄琉。
2.10.堆排序(Heap Sort)
堆排序
是指利用堆
這種數(shù)據(jù)結(jié)構(gòu)所設(shè)計的一種排序算法次乓。堆
是一個近似完全二叉樹
的結(jié)構(gòu),并同時滿足堆積的性質(zhì):即子結(jié)點的鍵值或索引總是小于(或者大于)它的父節(jié)點孽水。
最后一個堆排序
可能相對于其他的排序比較難理解一點票腰,需要一定的二叉樹的知識,才可以理解堆的結(jié)構(gòu)女气,其實就是一個父節(jié)點比子節(jié)點大(或者子節(jié)點比父節(jié)點大)的完全二叉樹杏慰。
基本的流程就是:
1.先創(chuàng)建一個大頂堆,就是父節(jié)點比子節(jié)點大的堆炼鞠。
2.把大頂堆最頂部的一個數(shù)據(jù)缘滥,和最末尾的一個數(shù)據(jù)交換,這樣最大的數(shù)據(jù)就到了最后面了簇搅。
3.重新把剩余的數(shù)據(jù)完域,重新變成一個大頂堆,然后在把大頂堆最頂部的一個數(shù)據(jù)瘩将,和未排序最末尾的一個數(shù)據(jù)交換吟税。
4.重復(fù)3步驟,最后就得到了一個有序的數(shù)組姿现。
int len;
// 堆化
void adjustHeap(vector<int> &arr, int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int top = i;
if (left < len && arr[left] > arr[top]) {
top = left;
}
if (right < len && arr[right] > arr[top]) {
top = right;
}
if (top != i) {
int temp = arr[i];
arr[i] = arr[top];
arr[top] = temp;
adjustHeap(arr, top);
}
}
// 創(chuàng)建大頂堆
void buildHeap(vector<int> &arr) {
// 現(xiàn)在是一個無序的普通的堆
for (int i = arr.size() / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i);
}
}
vector<int> heapSort(vector<int> arr) {
if (arr.size() < 2) {
return arr;
}
len = arr.size();
buildHeap(arr);
for (int i = arr.size() - 1; i > 0; i--) {
// 交換
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
// 需要實時記錄一個len
len--;
// 重新排列成為大頂堆 從上到下
adjustHeap(arr, 0);
}
return arr;
}
從上述代碼中可以看出肠仪,堆排序主要時間消耗是在堆化的過程,是一個遞歸的過程备典,所以時間復(fù)雜度為异旧,(但是具體的公式還是需要通過推導(dǎo)出來),堆是原地排序提佣,所以空間復(fù)雜度為
吮蛹,是一種不穩(wěn)定的排序算法。
結(jié)束語
- 以上算法還沒有經(jīng)過大數(shù)據(jù)的測試拌屏,所以在有些情況下也許沒有達到排序的效果潮针,發(fā)現(xiàn)有問題的同學(xué)可以幫忙指出不足。
- 后面的三種排序算法:桶排序倚喂、基數(shù)排序每篷、計數(shù)排序,雖然效率更快,但是有一定的場景的限制焦读,所以平時使用的并不是很多子库。
- 看時間復(fù)雜度和空間復(fù)雜度,堆排序比快速排序感覺還更好一點矗晃,但是在實際的運用中快速排序的運用更加的廣泛仑嗅,因為堆排序的操作比較繁瑣,建堆和堆化喧兄,而且堆是基于二叉樹的无畔,所以一般都是使用指針來存儲,創(chuàng)建堆的時候內(nèi)存就有一定的消耗吠冤,還有對計算機的內(nèi)存是不友好的浑彰,是碎片存儲的。
- 快速排序也不是萬能的排序拯辙,也有自己的不足之處郭变,比如日常運用中數(shù)據(jù)量比較大的情況下,需要防止堆棧溢出涯保,解決方法是:我們可以模擬遞歸的出棧入棧诉濒,達到遞歸相同的效果。
- 如果是已經(jīng)有序的數(shù)組夕春,快速排序的時間復(fù)雜度為
未荒,但是怎么才可以較好的優(yōu)化這個算法呢?希望知道的朋友可以教我一下及志,謝謝了片排。
參考資料
《編程珠璣》,《算法第四版》速侈,王爭的《數(shù)據(jù)結(jié)構(gòu)與算法之美》