成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

又被分治題卡住好幾個小時!用最笨的方法搞懂分治法邊界,告別死循環!

開發 前端
這篇文章寫于我剛學算法時。好家伙,第一道題快排就卡我老半天。但是好消息是,我算是沒有得過且過,花了一晚上和一上午,把所有情況都捋了一遍、把迭代過程考慮清楚了。

[[406991]]

這篇文章寫于我剛學算法時。好家伙,第一道題快排就卡我老半天。但是好消息是,我算是沒有得過且過,花了一晚上和一上午,把所有情況都捋了一遍、把迭代過程考慮清楚了。之后便感覺入了門,有了感覺,后續其他題目都沒有卡我這么久過。

被很簡單的快排 代碼運行狀態:Memory Limit Exceeded 老半天。

最后琢磨半天越界這事兒。總結起來一句話:避免出現 func(l, r) { ... func(l, r) ... } (遞歸時傳遞到下一層的邊界值不縮小)這種情況,因為這是死循環。 如何避免?比如func(l, r) { func(l, j), func(j + 1, r)}中,j至少滿足 j > r (j從r身上離開,防止 func(l, j) 是 func(l, r)),就可用。

  1. #include <iostream> 
  2. using namespace std; const int N = 1e6 + 10; int n; int q[N]; 
  3.  
  4. void quick_sort(int q[], int l, int r) 
  5.     if (l >= r) return
  6.  
  7.     int i = l - 1, j = r + 1, x = q[l + r >> 1]; 
  8.     while (i < j) 
  9.     { 
  10.         do i ++; while (q[i] < x); 
  11.         do j --; while (q[j] > x); 
  12.         if (i < j) swap(q[i], q[j]); 
  13.     } 
  14.     quick_sort(q, l, j), quick_sort(q, j + 1, r); 
  15.  
  16. int main() { scanf("%d", &n); for (int i = 0; i < n; i ++) scanf("%d", &q[i]); quick_sort(q, 0, n-1); for (int i = 0; i < n; i ++) printf("%d ", q[i]); return 0; } 

手賤,非得寫成:

  1. quick_sort(q, l, i - 1), quick_sort(q, i, r); 

好家伙,報錯。半天沒看出來,后來才恍然大悟,你要是用 i 分界,上面得是 x = q[l + r + 1 >> 1]; 。

那我下面這樣不行嗎?

  1. x = q[l+r >> 1]; 
  2. ... 
  3. quick_sort(q, l, j - 1), quick_sort(q, j, r); 
  4.  
  5. // 或者這樣不行嗎? 
  6. x = q[l+r >> 1]; 
  7. ... 
  8. quick_sort(q, l, i - 1), quick_sort(q, i, r); 
  9.  
  10. // 或者這樣不行嗎? 
  11. x = q[l+r >> 1]; 
  12. ... 
  13. quick_sort(q, l, i), quick_sort(q, i + 1, r); 
  14.  
  15. // 或者這樣不行嗎? 
  16. x = q[l+r+1 >> 1]; 
  17. ... 
  18. quick_sort(q, l, j), quick_sort(q, j + 1, r); 
  19.  
  20. // 或者這樣不行嗎? 
  21. x = q[l+r+1 >> 1]; 
  22. ... 
  23. quick_sort(q, l, j - 1), quick_sort(q, j, r); 
  24.  
  25. // 或者這樣不行嗎? 
  26. x = q[l+r+1 >> 1]; 
  27. ... 
  28. quick_sort(q, l, i), quick_sort(q, i + 1, r); 

上述都不行,看我一一舉反例。

我們輸入長度是2的數組,則第一層循環:l = 0, r = 1(即 quick_sort(0, 1)),如果進入第二層循環時,還出現 quick_sort(0, 1)的情況,則陷入死循環。

下表中,“傳到函數的i, j”指調用 quick_sort(q, l, ?i/j), quick_sort(q, ?i/j, r) 中 i, j 的值。

下表中,最后一列標記 x 表示將使程序陷入死循環。

對于 int mid = l+r >> 1;:

可見,在 int mid = l+r >> 1; 時,四種組合中只有 j j+1 經受住了 0 1 和 1 0 的雙重考驗。

對于 int mid = l+r+1 >> 1;:

可見,在 int mid = l+r+1 >> 1; 時,四種組合中只有 i-1 i 經受住了 0 1 和 1 0 的雙重考驗。

這是為什么呢?

  • 這里有相關證明:AcWing 785. 快速排序算法的證明與邊界分析[1]
  • 如果你沒耐心看上述較為嚴謹的證明,可以看文末我寫的

我用比較笨的方法理解是:

  • int mid = l+r >> 1;:則可證明 j 的取值范圍是 [l, r-1] ,因此對于邊界組合 j j+1 有 quick_sort(q, l, j小于r), quick_sort(q, j+1大于l, r) ,永遠都不會有 quick_sort(q, l, r) 出現。
  • int mid = l+r+1 >> 1;:則可證明 i 的取值范圍是 [l+1, r] ,因此對于邊界組合 i-1 i 有 quick_sort(q, l, i-1小于r), quick_sort(q, i大于l, r) ,永遠都不會有 quick_sort(q, l, r) 出現。

OK,那下面就是背誦:

  • 快排中,int mid = l+r >> 1;( mid 向下取整),是 j j+1,因為j 取值范圍是 [l r-1]
  • 我個人是不太喜歡背誦的,還是知道原理,覺得到時候可以快速推導出來靠譜,推導如下。

用較清晰但是笨拙的方法證明一下 mid 向下取整時 j 屬于 [l, r-1]。

向下取整時 j 屬于 [l, r-1] ==等價于== 向下取整時至少有兩次 j-- 被執行

下面分三種特殊情況討論(普通情況不討論),可以看出三種情況中都至少有兩次 j-- 被執行

情況1:j在r處就不再q[j] > x,而i在l處還滿足q[i] < x

  1. q[mid]     x 
  2.            9  8 
  3. begin   i        j 
  4. step1      i     j  do i++; while(q[i] < x); 
  5. step2      i  j     do j--; while(q[j] > x); 
  6. step3      8  9 
  7. step4      i  j     swap(q[i], q[j]); 
  8. step5         ij    do i++; while(q[i] < x); 
  9. step6      j  i     do j--; while(q[j] > x); 
  10. 跳出循環 while(i < j) {} 

j在r處就不再q[j] > x,而i在l處還滿足q[i] < x;因此對于l < r,還要再跳一輪,因為是 do while 而不是 while do ,所以不管 i 或 j 什么條件,都得再至少來一次 i++; j--; 。

情況2:j在r處還滿足q[j] > x,而i在l處就不再q[i] < x

  1. q[mid]     x 
  2.            8  9 
  3. begin   i        j 
  4. step1      i     j  do i++; while(q[i] < x); 
  5. step2      ij       do j--; while(q[j] > x); 
  6. step3      8  9 
  7. 跳出循環 while(i < j) {} 

j在r處還滿足q[j] > x,因此,一定會繼續執行j--,j一定會小于r。

情況3:j在r處就不再q[j] > x,且i在l處就不再q[i] < x

  1. q[mid]     x 
  2.            8  8 
  3. begin   i        j 
  4. step1      i     j  do i++; while(q[i] < x); 
  5. step2      i  j     do j--; while(q[j] > x); 
  6. step3      8  8 
  7. step4      i  j     swap(q[i], q[j]); 
  8. step5         ij    do i++; while(q[i] < x); 
  9. step6      j  i     do j--; while(q[j] > x); 
  10. 跳出循環 while(i < j) {} 

j在r處就不再q[j] > x,且i在l處就不再q[i] < x;此時有 i < j ,因此不跳出循環,執行 swap;對于l < r,還要再跳一輪,因為是 do while 而不是 while do ,所以不管 i 或 j 什么條件,都得再至少來一次 i++; j--; 。

這里的魅力在于 do while :不管咋的,你滿不滿足條件,我先給你移動一下,你再判斷。

對于二分法,核心思想也是避免出現func(l, r) { func(l, r); } ,因此出現 mid = l + r >> 1; 則必有 r = mid; ,因為 mid 是向下取整,l < r 時 mid 肯定碰不到 r 。

 

責任編輯:姜華 來源: Piper蛋窩
相關推薦

2019-03-05 09:32:31

SLA阿里云宕機

2021-10-16 07:31:54

微信深度清理騰訊

2022-11-18 14:15:13

2020-12-02 09:36:20

算法分支思想

2023-01-31 08:24:55

HashMap死循環

2013-06-06 13:34:56

HashMap線程不安全

2020-10-20 08:14:08

算法與數據結構

2020-11-13 09:31:44

分治算法運算

2018-10-10 20:20:14

2023-05-30 14:54:17

Python循環語句工具

2011-08-29 16:23:29

Lua腳本

2020-12-17 07:39:30

HashMap死循環數據

2021-04-16 09:40:52

Java數據結構算法

2021-05-12 09:07:09

Java數據結構算法

2021-12-20 10:39:30

TopK排序代碼

2011-09-07 10:13:04

IPv6IPv4

2024-12-06 16:00:00

C++頭文件

2025-01-21 00:00:00

HashMap死循環數據損壞

2023-10-08 09:42:41

GitHubDataTable?Fill

2010-09-09 16:40:58

SQL循環游標
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品99久久久久久动医院 | 狠狠的干狠狠的操 | 国产成人精品一区二 | 久久久黄色 | 国产日韩一区二区 | 毛片1| 欧美综合久久 | 免费黄色片在线观看 | 成人免费xxxxx在线视频 | 国产精品高潮呻吟久久av黑人 | 91久久视频 | av福利网 | av在线播放网站 | 99pao成人国产永久免费视频 | 18av在线播放 | 国产综合精品一区二区三区 | 五月激情久久 | 亚洲理论在线观看电影 | yeyeav| 欧美日日 | 国产精品3区 | 亚洲精品一区中文字幕 | 伊人超碰在线 | 欧美九九九 | 91视频a | 国产精品久久久久久久久免费相片 | 欧美一区二区三区视频 | 天天狠狠 | 久久国产婷婷国产香蕉 | 国产三级| 午夜成人在线视频 | 夜夜爽99久久国产综合精品女不卡 | aaa在线| 一区在线观看 | 午夜影晥| 人人鲁人人莫人人爱精品 | 一区二区视频在线 | 国产精品一区二区三级 | 久久久久久久国产精品视频 | 国产成人在线视频 | 国产精品久久久久久久久久久久冷 |