被忽視的 partition 演算法

2021-07-22 06:32:47 字數 2356 閱讀 9892

如果你學習過演算法,那麼肯定聽說過快速排序的大名,但是對於快速排序中用到的 partition 演算法,你了解的夠多嗎?或許是快速排序太過於光芒四射,使得我們往往會忽視掉同樣重要的 partition 演算法。

partition 可不只用在快速排序中,還可以用於 selection algorithm (在無序陣列中尋找第k大的值)中。甚至有可能正是這種通過一趟掃瞄來進行分類的思想激發 edsger dijkstra 想出了 three-way partitioning,高效地解決了 dutch national flag problem問題。接下來我們一起來探索 partition 演算法。

快速排序中用到的 partition 演算法思想很簡單,首先從無序陣列中選出樞軸點 pivot,然後通過一趟掃瞄,以 pivot 為分界線將陣列中其他元素分為兩部分,使得左邊部分的數小於等於樞軸,右邊部分的數大於等於樞軸(左部分或者右部分都可能為空),最後返回樞軸在新的陣列中的位置。

partition 的乙個直觀簡單實現如下(這裡取陣列的第乙個元素為pivot):

// do partition in arr[begin, end), with the first element as the pivot.

intpartition(vector

&arr,intbegin,intend)

} }swap(arr[begin], arr[pos]);

returnpos;

}

如果原始陣列為[5,9,2,1,4,7,5,8,3,6],那麼整個處理的過程如下圖所示:

這種實現思路比較直觀,但是其實並不高效。從直觀上來分析一下,每個小於pivot的值基本上(除非到現在為止還沒有遇見大於pivot的值)都需要一次交換,大於pivot的值(例如上圖中的數字9)有可能需要被交換多次才能到達最終的位置。

如果我們考慮用 two pointers 的思想,保持頭尾兩個指標向中間掃瞄,每次在頭部找到大於pivot的值,同時在尾部找到小於pivot的值,然後將它們做乙個交換,就可以一次把這兩個數字放到最終的位置。一種比較明智的寫法如下:

intpartition(vector&arr,intbegin,intend)

arr[begin] = pivot;

returnbegin;

}

如果是第一次看到上面的**,那麼停下來,好好品味一下。這裡沒有用到 swap 函式,但其實也相當於做了 swap 操作。以前面的陣列為例,看看以這種方法來做的話,整個處理的流程。

直觀上來看,賦值操作的次數不多,比前面單向掃瞄的swap次數都少,效率應該會更高。 這裡 從理論上對這兩種方法進行了分析,有興趣可以看看。

我們都知道經典的快速排序就是首先用 partition 將陣列分為兩部分,然後分別對左右兩部分遞迴進行快速排序,過程如下:

voidquick_sort(vector

&arr,intbegin,intend)

intpos = partition(arr, begin, end);

quick_sort(arr, begin, pos);

quick_sort(arr, pos+1, end);

}

雖然快排用到了經典的分而治之的思想,但是快排實現的前提還是在於 partition 函式。正是有了 partition 的存在,才使得可以將整個大問題進行劃分,進而分別進行處理。

除了用來進行快速排序,partition 還可以用 o(n) 的平均時間複雜度 從無序陣列中尋找第k大的值 。和快排一樣,這裡也用到了分而治之的思想。首先用 partition 將陣列分為兩部分,得到分界點下標 pos,然後分三種情況:

下面給出基於迭代的實現:

intfind_kth_number(vector

&arr,intk)

elseif(pos > k-1)

else

}returntarget_num;

}

該演算法的時間複雜度是多少呢?考慮最壞情況下,每次 partition 將陣列分為長度為 n-1 和 1 的兩部分,然後在長的一邊繼續尋找第 k 大,此時時間複雜度為 o(n^2 )。不過如果在開始之前將陣列進行隨機打亂,那麼可以盡量避免最壞情況的出現。而在最好情況下,每次將陣列均分為長度相同的兩半,執行時間 t(n) = n + t(n/2),時間複雜度是 o(n)。

被忽視的 partition 演算法

如果你學習過演算法,那麼肯定聽說過快速排序的大名,但是對於快速排序中用到的 partition 演算法,你了解的夠多嗎?或許是快速排序太過於光芒四射,使得我們往往會忽視掉同樣重要的 partition 演算法。partition 可不只用在快速排序中,還可以用於 selection algorith...

快排光芒下被忽視的Partition函式

看到這篇標題,沒有學過快排的人自然是不知道partition函式的意思和作用,這裡附上學習的連線 lantian的快排總結 我們現在都是被快排蒙蔽了雙眼,沒有意識到快最核心的劃分函式partition,當然partition函式也就不止於快排這裡,本文就從多方面來為展示partition函式的本質和...

被忽視的IT金飯碗

談高校學子對軟體測試認識的三大誤區 軟體測試是保障軟體質量的重要環節,企業對於軟體質量意識的逐步增強,促使國內軟體測試人員的地位不斷提公升。但中國高等教育往往落後企業實際發展3 5年,所以在高校學子心中,重開發 輕測試的思想依然嚴重。許多優秀的畢業生甚至對測試工作存在偏見,致使軟體測試人才缺口進一步...