日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

排序中减治法算法伪代码_算法浅谈——分治算法与归并、快速排序(附代码和动图演示)...

發(fā)布時間:2023/12/19 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 排序中减治法算法伪代码_算法浅谈——分治算法与归并、快速排序(附代码和动图演示)... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在之前的文章當(dāng)中,我們通過海盜分金幣問題詳細講解了遞歸方法。

我們可以認為在遞歸的過程當(dāng)中,我們通過函數(shù)自己調(diào)用自己,將大問題轉(zhuǎn)化成了小問題,因此簡化了編碼以及建模。今天這篇文章呢,就正式和大家聊一聊將大問題簡化成小問題的分治算法的經(jīng)典使用場景——排序

排序算法

排序算法有很多,很多博文都有總結(jié),號稱有十大經(jīng)典的排序算法。我們信手拈來就可以說上來很多,比如插入排序、選擇排序、桶排序、希爾排序、快速排序、歸并排序等等。老實講這么多排序算法,但我們實際工作中并不會用到那么多,凡是高級語言都有自帶的排序工具,我們直接調(diào)用就好。為了應(yīng)付面試以及提升自己算法能力呢,用到的也就那么幾種。今天我們來介紹一下利用分治思想實現(xiàn)的兩種經(jīng)典排序算法——歸并排序與快速排序

歸并排序

我們先來講歸并排序,歸并排序的思路其實很簡單,說白了只有一句話:兩個有序數(shù)組歸并的復(fù)雜度是 O(n)

我們舉個例子:

a = [1, 4, 6]b = [2, 4, 5]c = []

我們用i和j分別表示a和b兩個數(shù)組的下標(biāo),c表示歸并之后的數(shù)組,顯然一開始的時候i, j = 0, 0。我們不停地比較a和b數(shù)組i和j位置大小關(guān)系,將小的那個數(shù)填入c。

填入一個數(shù)之后:

i = 1j = 0a = [1, 4, 6]b = [2, 4, 5]c = [1]

填入兩個數(shù)之后:

i = 1j = 1a = [1, 4, 6]b = [2, 4, 5]c = [1, 2]

我們重復(fù)以上步驟,直到a和b數(shù)組當(dāng)中所有的數(shù)都填入c數(shù)組為止,我們可以很方便地寫出以上操作的代碼:

從上面的代碼我們也能看出來,這個過程雖然簡單,但是寫成代碼非常麻煩,因為我們需要判斷數(shù)組是否已經(jīng)全部填入的情況。這里有一個簡化代碼的優(yōu)化,就是在a和b兩個數(shù)組當(dāng)中插入一個”標(biāo)兵“,這個標(biāo)兵設(shè)置成正無窮大的數(shù),這樣當(dāng)a數(shù)組當(dāng)中其他元素都彈出之后。由于標(biāo)兵大于b數(shù)組當(dāng)中除了標(biāo)兵之外其他所有的數(shù),就可以保證a數(shù)組永遠不會越界,如此就可以簡化很多代碼了(前提,a和b數(shù)組當(dāng)中不存在和標(biāo)兵一樣大的數(shù))。

我們來看代碼:

這里應(yīng)該都沒有問題,接下來的問題是我們怎么利用歸并數(shù)組的操作來排序呢?

其實很簡單,這也是歸并排序的精髓

我們每次將一個數(shù)組一分為二,顯然,這個劃分出來的數(shù)組不一定是有序的。但如果我們繼續(xù)切分呢?直到數(shù)組當(dāng)中只有一個元素的時候,是不是就天然有序了呢?

我們舉個例子:

[4, 1, 3, 2] / [4, 1] [3, 2] / / [4] [1] [3] [2] / / [1, 4] [2, 3] / [1, 2, 3, 4]

通過上面的這個過程我們可以發(fā)現(xiàn),在歸并排序的時候,我們先一直往下遞歸切分數(shù)組,直到所有的切片當(dāng)中只有一個元素天然有序。接著一層一層地歸并回來,當(dāng)所有元素歸并結(jié)束的時候,數(shù)組就完成了排序。這也就是歸并排序的全部過程。

如果還不理解,還可以參考一下下面的動圖。

我們來試著用代碼來實現(xiàn)。之前我曾經(jīng)在面試的時候被要求在白板上寫過歸并排序,當(dāng)時我用的C++覺得編碼還有一定的難度。現(xiàn)在,當(dāng)我用習(xí)慣了Python之后,我感覺編碼難度降低了很多。因為Python支持許多數(shù)組相關(guān)的高級操作,比如切片,變長等等。整個歸并排序的代碼不超過20行,我們一起來看下代碼:

你看,無論是思想還是代碼實現(xiàn),歸并排序并不難,就算一開始不熟悉,寫個兩遍也一定沒問題了。

理解了歸并排序之后,再來學(xué)快速排序就不難了,我們一起來看快速排序的算法原理。

快速排序

快速排序同樣利用了分治的思想,我們每次做一個小的操作,讓數(shù)組的一部分變得有序,之后我們通過遞歸,將這些有序的部分組合在一起,達到整體有序

在歸并排序當(dāng)中,我們劃分問題的方法是橫向切分,我們直接將數(shù)組一分為二,針對這兩個部分分別排序。快排稍稍不同,它并不是針對數(shù)組的橫向切分,而是從問題本身出發(fā)的”縱向“切分。在快速排序當(dāng)中,我們解決的子問題不是對數(shù)組的一部分排序,而是提升數(shù)組的有序程度。怎么提升呢?

我們在數(shù)組當(dāng)中尋找一個數(shù),作為標(biāo)桿,我們利用這個標(biāo)桿調(diào)整數(shù)組當(dāng)中元素的順序。將小于它的放到它的左側(cè),大于它的放到它的右側(cè)。這么一個操作結(jié)束之后,可以肯定的是,這個標(biāo)桿所在的位置就是排序完成之后,它應(yīng)該在的位置

我們來看個例子:

a = [8, 4, 3, 9, 10, 2, 7]

我們選擇7作為標(biāo)桿,一輪操作之后可以得到:

a = [2, 4, 3, 7, 9, 10, 8]

接著我們怎么做呢?很簡單,我們只需要對標(biāo)桿前面以及標(biāo)桿后面的部分遞歸調(diào)用重復(fù)上述操作即可。如果還不明白的同學(xué)可以看一下下面這張動圖:

如果用C++寫過快排的同學(xué)肯定對于快排的代碼印象深刻,它是屬于典型的原理不難,但是寫起來很麻煩的算法。因為快速排序需要用到兩個下標(biāo),寫的時候一不小心很容易寫出bug。同樣,由于Python當(dāng)中動態(tài)數(shù)組的支持非常好,我們可以避免使用下標(biāo)來實現(xiàn)快排,這樣代碼的可讀性以及編碼難度都要降低很多。

多說無益,我們來看代碼:

整個代碼除去注釋,不到15行,我想大家應(yīng)該都非常容易理解。

最后,我們來分析一下這兩個算法的復(fù)雜度,為什么說這兩個算法都是 O(nlogn) 的算法呢?(不考慮快速排序最差情況)這個證明非常簡單,我們放一張圖大家一看就明白了:

我們在遞歸的過程當(dāng)中,我們只遍歷了一遍數(shù)組,雖然我們每一層都會講數(shù)組拆分。但是在遞歸樹上同一層的遞歸函數(shù)遍歷的總數(shù)加起來應(yīng)該是等于數(shù)組的總長也就是n的。

而且遞歸的層數(shù)是有限制的,因為我們每次都將數(shù)組一分為二。而一個數(shù)組的最小長度是1,也就是說極端情況下我們一共能有 log2n 層,每一層的復(fù)雜度總和是n,所以整體的復(fù)雜度是 nlogn。

當(dāng)然對于快速排序算法來說,如果數(shù)組是倒序的,我們默認取最后一個元素作為標(biāo)桿的話,我們是無法切分數(shù)組的,因為除它之外所有的元素都比它大。在這種情況下算法的復(fù)雜度會退化到 n^2 。所以我們說快速排序算法最差復(fù)雜度是 n^2 。

到這里,關(guān)于歸并排序與快速排序的算法就講完了。這兩個算法并不難,我想學(xué)過算法和數(shù)據(jù)結(jié)構(gòu)的同學(xué)應(yīng)該都有印象,但是在實際面試當(dāng)中,真正能把代碼寫出來并且沒有明顯bug的實在是不多。我想,不論之前是否已經(jīng)學(xué)會了,回顧一下都是很有必要的吧。

今天的文章就到這里,希望大家有所收獲。如果喜歡本文,請順手點個關(guān)注吧。

總結(jié)

以上是生活随笔為你收集整理的排序中减治法算法伪代码_算法浅谈——分治算法与归并、快速排序(附代码和动图演示)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。