[爆卦]quick sort複雜度是什麼?優點缺點精華區懶人包

為什麼這篇quick sort複雜度鄉民發文收入到精華區:因為在quick sort複雜度這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者j0958322080 (Tidus)看板C_and_CPP標題[問題] quicksort原地...


開發平台(Platform): (Ex: Win10, Linux, ...)
win10

編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
gcc 4.8.1

額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
no

問題(Question):
想要寫一個quicksort不用遞迴且不用另外開矩陣的寫法,
不過選pivot後第一次都拆成兩個小陣列結束後就不知道開如何做了。

餵入的資料(Input):


預期的正確結果(Expected Output):


錯誤結果(Wrong Output):


程式碼(Code):(請善用置底文網頁, 記得排版,禁止使用圖檔)
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}

void quicksort(int a[], int array_length){
int left_bound = 0, right_bound = array_length-1;
int right = right_bound, left = left_bound, pivot = (left+right)/2;
int i, j;
int new_left_bound, new_right_bound;
int pivot_zero, pivot_one;
while(left < right)
{
if(a[right] > a[pivot])
{
if (a[left] < a[pivot])
{
right--;
left++;
}
else right--;
}
else
{
if (a[left] < a[pivot]) left++;
else
{
swap(&a[left],&a[right]);
right--;
left++;
}
}
if(left == right)
{
new_left_bound = right+1;
new_right_bound = left;
left = left_bound;
right = new_right_bound;
pivot = (left+right)/2;
}
if(left == pivot)break;
printf("%d %d %d\n",right,left,pivot);
}
}


補充說明(Supplement):
感覺這種divide and conquer用迴圈做比較難,
網路上找的版本也幾乎都是遞迴的版本,
除了遞迴比較好寫外有其他原因嗎??

--
!!!!!!!!!!!!!簽名檔破740000點擊率啦!!!!!!!!!!!!!!!
Fw: [問卦] 電影:決勝21點的機率問題 https://goo.gl/2BpbB7 #1MfN3FgZ (joke)
yeebon: chx64的1/2悖論真的很經典呢07/22 16:41
!!!!!!!!!!!!!!簽名檔破740000點擊率啦!!!!!!!!!!!!!!

--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 39.9.136.149
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1545392640.A.7A6.html
poyenc: 你要怎麼知道有那些區間是 partition 完但還沒 merge 的? 12/21 20:00
j0958322080: 原地排列應該沒有合併的問題吧 12/21 22:41
poyenc: 簡單說 DaC 還會需要整合結果的步驟, 所以我問 partition 12/21 23:39
poyenc: 完, 你去處理完更小的區間以後, 要怎麼回來處理其他區間? 12/21 23:40
poyenc: 即使是 in-place quicksort 也有回去處理上個 partition 12/21 23:43
poyenc: 剩下來另一半區間的步驟, 也會有整合結果的步驟 (雖然可以 12/21 23:44
poyenc: 不做事), 但就跟遞迴呼叫類似, 你要用同份程式碼執行在不 12/21 23:45
poyenc: 同情境 (context) 下, 先要有辦法把情境資訊給儲存起來 12/21 23:46
j0958322080: 這個問題也是我現在正在想的,目前的code只能一直往 12/21 23:49
j0958322080: 左或是一直往右。中間的小陣列初步的想法是設定兩個 12/21 23:49
j0958322080: 新的變數存新的邊界去跑,不過這邊就是要想想怎麼寫 12/21 23:49
j0958322080: ,寫出來還要在看看是不是O(nlogn) 12/21 23:49
j0958322080: 不過merge sort就比較好找到迭代版本的code 12/21 23:50
poyenc: 用 LIFO stack 去存當前區間、pivot、階段就可以了 12/22 00:04
poyenc: 這邊有兩種實作可以對照看 https://bit.ly/2T2HEOH 12/22 04:25
suhorng: 如果可以接受多 O(log n) 的空間應該還好寫就是了 12/22 09:41
suhorng: 另外其實 divide 有很好懂的寫法, 不一定要左右交換 12/22 09:42
j0958322080: 感謝兩位的分享,不過我看網路上資料in place的快排 12/22 10:40
j0958322080: 才是最快的,其他都比合併排序慢 12/22 10:40
b0920075: stack存還沒排過的區間 12/22 16:19
suhorng: 還會是 in-place 呀, Quicksort 本來就要 O(log n) 的 12/22 23:55
suhorng: 堆疊空間 12/22 23:55
suhorng: 實際用的 sorting algorithm 記得都是好幾種的混合 12/23 00:00
j0958322080: 但我看網路上的資料是說不需要另外開陣列給他,而且i 12/23 22:50
j0958322080: n place應該也只是陣列內的元素交換而已 12/23 22:50
poyenc: 那有個問題: 你定義區域變數要不要算進空間複雜度? 你進行 12/23 23:10
poyenc: 遞迴呼叫算不算配置記憶體? 12/23 23:10
j0958322080: 我找到的資料。 https://reurl.cc/moQQ7 12/23 23:52
j0958322080: 我目前的想法空間複雜度應該只是常數,但我還沒實現 12/23 23:54
poyenc: 再研究一下 in-place algorithm 指的是哪方面的 in-place 12/24 02:32
poyenc: 吧, 如果 quicksort 空間複雜度可以到常數你就可以得獎了 12/24 02:34
j0958322080: 那如果只是單純在原陣列中排序為何還需要其他空間 12/24 09:17
j0958322080: 喔看來是我誤會in-place的意思了 12/24 09:25
suhorng: 那個 O(log n) 是遞迴的堆疊空間, 在原本的 quicksort 12/24 13:40
suhorng: 就有. 手寫堆疊多多少少可以變迴圈的形式, 而且 12/24 13:41
suhorng: quicksort 的遞迴方式很簡單, 寫出來應該也不會太難懂 12/24 13:41
suhorng: 當然我個人是喜歡寫成遞迴的形式. 遞迴跟歸納法一樣, 12/24 13:42
suhorng: 遞迴呼叫想成 "由歸納假設", 就可以把陣列排好了 12/24 13:42
j0958322080: 我看過msort的遞迴確實比迭代簡單,qsort遞迴也蠻好 12/24 14:22
j0958322080: 寫的,但是個人是喜歡迭代 12/24 14:22
poyenc: O(log N) 不是專指遞迴需要的空間, 而是為了 divide & 12/24 15:01
poyenc: conquer 需要記住的資訊量, 你用 iterative 因為也要記錄 12/24 15:02
poyenc: 相同資訊, 所以免不了這部分的空間複雜度. recursive 只是 12/24 15:03
poyenc: 把資訊存在 call stack 上, 這樣的分別而已 12/24 15:03
poyenc: 把遞迴跟 divide & conquer 劃上等號就錯了, 應該從了解演 12/24 15:14
poyenc: 算法本身著手. divide 我也可以開好多條 thread 去作, 討 12/24 15:16
poyenc: 論實作根本無助於理解這個 O(log N) 12/24 15:16
poyenc: hint: O(log N) 跟演算法是 top-down 有關 12/24 15:37
poyenc: 你會覺得 iterative merge sort 實作很好理解的原因在於即 12/24 16:26
poyenc: 使用 bottom-up approach 去實作也很容易, 因為邊界都可以 12/24 16:27
poyenc: 在一開始的時候全算出來, 但對於 top-down 的演算法, 想要 12/24 16:27
poyenc: 把 "分出子問題" 這件事跟 "解決問題本身" 成本相仿, 你如 12/24 16:30
poyenc: 實作出完全迴圈版, 會發現成本都在儲存子問題資訊上面, 12/24 16:31
poyenc: 空間複雜度 O(N log N), 為了蒐集資訊需額外付出時間成本 12/24 16:32
poyenc: O(N log N) 12/24 16:32
suhorng: 你說得對 12/24 23:19

你可能也想看看

搜尋相關網站