精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

一種高效的順序劃分算法——循環(huán)劃分算法

譯文 精選
開發(fā) 前端
本文將詳細介紹一種新穎高效的順序劃分算法——循環(huán)劃分算法,它能夠?qū)ζ胀愋椭禂?shù)據(jù)進行最小次數(shù)的重新排列。

譯者 | 朱先忠

審校 | 重樓

摘要:本文將詳細介紹一種新穎高效的順序劃分算法——循環(huán)劃分算法,它能夠?qū)ζ胀愋椭禂?shù)據(jù)進行最小次數(shù)的重新排列。

1.導(dǎo)言

順序劃分是計算機編程中一種基本且常用的算法。給定一個數(shù)字序列“A”和一個稱為基準(zhǔn)值的值“p”,劃分算法的目的是以這種方式重新排列“A”中的數(shù)字,使所有小于“p”的數(shù)字排在第一位,然后是其余的數(shù)字。

按基準(zhǔn)值“p=20”劃分前后的序列示例。應(yīng)用算法后,所有小于20的值(淺綠色)顯示在其他值之前(黃色)。

劃分算法有不同的應(yīng)用,但最受歡迎的應(yīng)用包括:

  • 快速排序(QuickSort)——一種劃分算法,在給定數(shù)組的不同子數(shù)組上通過遞歸多次調(diào)用,直到最終完成排序。
  • 找到給定序列的中值——利用劃分來有效地縮小搜索范圍,并最終在預(yù)期的線性時間內(nèi)找到中值。

對序列進行排序是在大量數(shù)據(jù)上實現(xiàn)更快導(dǎo)航的重要步驟。在兩種常見的搜索算法中——線性搜索和二分查找——后者只有在數(shù)組中的數(shù)據(jù)被排序時才能使用。找到中位數(shù)或k階統(tǒng)計量對于理解給定未排序數(shù)據(jù)中的值分布至關(guān)重要。

目前已經(jīng)存在不同的劃分算法(也稱為劃分方案),但最著名的要算是“Lomuto方案”和“Hoare方案”。Lomuto方案通常直觀上更容易理解,而Hoare方案在給定數(shù)組內(nèi)的重排次數(shù)較少,這就是它在實踐中通常更受歡迎的原因。

在本文中,我要推薦的是一種新的劃分方案,稱為“循環(huán)劃分”,它類似于Hoare方案,但數(shù)組內(nèi)的重新排列(值賦值)要少1.5倍。因此,正如稍后將顯示的那樣,值賦值的數(shù)量幾乎等于最初“不在原位”的值的數(shù)量,并且應(yīng)該以某種方式移動。這一事實讓我認為這個新的劃分方案幾乎是最優(yōu)的。

接下來的內(nèi)容按以下方式組織:

  • 在第2節(jié)中,我們將回顧什么是就地劃分(一種屬性,它使得劃分操作不那么繁雜)
  • 在第3節(jié)中,我們將回顧廣泛使用的Hoare劃分方案
  • 在第4節(jié)中,我將介紹“循環(huán)賦值”,我們將了解為什么序列的某些重排可能需要比同一序列的其他重排更多的值賦值
  • 第5節(jié)將利用“賦值循環(huán)”的一些性質(zhì),推導(dǎo)出新的“循環(huán)劃分”方案,作為Hoare方案的優(yōu)化變體
  • 最后,第6節(jié)將對小數(shù)據(jù)類型和大數(shù)據(jù)類型的數(shù)組進行Hoare方案和循環(huán)劃分的實驗比較。

請注意,GitHub上已經(jīng)提供了基于C++語言的循環(huán)劃分的實現(xiàn),以及它與當(dāng)前標(biāo)準(zhǔn)Hoare方案的基準(zhǔn)測試,詳見本文末尾的引用文獻。

2.原地順序劃分回顧

如果輸入和輸出序列位于計算機內(nèi)存中的2個不同數(shù)組中,則對序列進行劃分將不是一項艱巨的任務(wù)。如果情況是這樣的話,那么其中一種方法可能是:

  • 計算“A”中有多少值小于“p”(這將給出輸出序列左半部分的最終長度)
  • 從左到右掃描輸入數(shù)組“A”,并將每個當(dāng)前值“A[i]”附加到左側(cè)或右側(cè),具體取決于它是否小于“p”。

以下是運行此類算法的幾個狀態(tài):

在第一階段,我們計算出只有7個值小于“p=20”(淺綠色的值),因此我們準(zhǔn)備從索引7開始將較大的值寫入輸出序列。

在第二階段掃描輸入序列的5個值之后,我們將其中的3個附加到輸出序列的左側(cè)部分,另兩個在其右側(cè)。

繼續(xù)第二階段,我們現(xiàn)在從輸入序列中掃描了9個值,將其中5個放置在輸出序列的左側(cè),將另外4個放置在其右側(cè)。

算法完成(現(xiàn)在,輸出序列的兩個部分都已正確填充到末尾)

注意,這里保留了左邊部分或右邊部分中數(shù)值的相對順序(根據(jù)它們最初在輸入數(shù)組中的寫入方式)。

當(dāng)然,還有其他更簡短的解決方案,比如代碼中只有一個循環(huán)的解決方案。

現(xiàn)在,當(dāng)我們不想使用任何額外的內(nèi)存時,困難就來了。因此,只需在唯一的數(shù)組中移動值,輸入序列就會被轉(zhuǎn)換為劃分后的輸出序列。順便說一句,這種不使用額外內(nèi)存的算法稱為就地算法。

用相同的基準(zhǔn)值“p=20”對相同的輸入序列“A”進行劃分

這里顯示的值順序?qū)?yīng)于序列的輸入狀態(tài),每個值都顯示箭頭——如果應(yīng)該將該值移動到某處,以便對整個序列進行劃分。

在介紹我的劃分方案之前,讓我們首先來回顧一下現(xiàn)有的和常用的就地劃分解決方案。

3.目前使用的劃分方案

在觀察了各種編程語言的標(biāo)準(zhǔn)庫中排序的一些實現(xiàn)后,看起來使用最廣泛的劃分算法是Hoare方案。我發(fā)現(xiàn)它被用于例如:

  • C++STL中的“std::sort()”實現(xiàn)
  • JDK for Java中用于原始數(shù)據(jù)類型的“Arrays.sort()”實現(xiàn)

在基于Hoare方案的劃分中,我們從兩端向彼此同時掃描序列,在左側(cè)部分搜索大于或等于'p'的a[i]值,在右側(cè)部分搜索小于'p'的a[j]值。一旦找到,我們就知道這兩個值A(chǔ)[i]和A[j]都屬于“不在它們的正確位置”(記住,劃分序列應(yīng)該先有小于'p'的值,然后才有大于或等于'p'所有其他值),所以我們只需要交換A[i]與A[j]。交換后,我們繼續(xù)以同樣的方式,同時掃描索引為i和j的數(shù)組“A”,直到它們相等。一旦完成,劃分就完成了。

讓我們在另一個例子中觀察Hoare方案:

長度為'N'的輸入序列“A”,應(yīng)按基準(zhǔn)值“p=20”進行劃分

索引i從0開始向上掃描,索引j從“N-1”開始向下掃描。

當(dāng)增加索引i時,我們會遇到值“A[2]=31”,它大于“p”。然后,在減小索引j之后,我們遇到另一個值“A[10]=16”,它小于'p'。這兩個將被交換。

在交換“A[2]”和“A[10]”之后,我們繼續(xù)從2增加i,從10減少j。索引i將在大于'p'的值“A[4]=28”時停止,索引j將在小于'p]的值“A[9]=5”時停止。這兩個也將被交換。

算法以同樣的方式繼續(xù),數(shù)字“A[5]=48”和“A[7]=3”也將被交換。

之后,索引“i”和“j”將彼此相等。至此,劃分算法完成。

如果用Hoare方案編寫劃分的偽代碼,我們將得到以下內(nèi)容:

// 對序列A[0..N)進行劃分,使用基準(zhǔn)值 'p' 
// 根據(jù)Hoare方案,并返回結(jié)果右邊部分第一個值的索引。
function partition_hoare( A[0..N) : Array of Integers, p: Integer ) : Integer
 i := 0
 j := N-1
 while true
 // 根據(jù)需要向左移動索引“i”
 while i < j and A[i] < p
 i := i+1
 // 根據(jù)需要向右移動索引“j”
 while i < j and A[j] >= p
 j := j-1
 // Check for completion
 if i >= j
 if i == j and A[i] < p
 return i+1 // "A[i]" 指向左邊部分
 else
 return i // "A[i]"指向右邊部分 
//交換"A[i]"和"A[j]"
 tmp := A[i]
 A[i] := A[j]
 A[j] := tmp
 //'i'和'j'各自加1
 i := i+1
 j := j-1

在第5行和第6行中,我們?yōu)?次掃描設(shè)置了開始索引。

第8-10行從左側(cè)搜索這樣一個值,該值在劃分后應(yīng)屬于右側(cè)。

同樣,第11-13行從右側(cè)搜索這樣一個值,它應(yīng)該屬于左側(cè)。

第15-19行檢查掃描是否完成。一旦索引'i'和'j'相遇,就有兩種情況:“A[i]”屬于左部分或右部分。根據(jù)這一點,我們返回“i”或“i+1”,因為函數(shù)的返回值應(yīng)該是右側(cè)部分的開始索引。

接下來,如果掃描尚未完成,第20-23行會交換那些不在正確位置的2個值。

最后,第24-26行各自把這兩個索引加1,以便不重新檢查已經(jīng)交換的值。

該算法的時間復(fù)雜度為O(N),無論兩次掃描在哪里相遇,因為它們總是一起掃描N個值。

這里有一個重要的注意事項,如果數(shù)組“A”的'L'值“不在它們的位置”,并且應(yīng)該被交換,那么按照Hoare方案,我們將進行“3*L/2”賦值,因為交換2個值需要3個賦值:

交換2個變量“a”和“b”的值,需要在“tmp”變量的幫助下進行3次賦值。

這些任務(wù)是:

tmp := a

a := b

b := tmp

需要強調(diào)一下,“L”總是偶數(shù)。這是因為對于最初位于左側(cè)區(qū)域的每個值“A[i]>=p”,都有另一個值“A[j]<p”最初位于右側(cè)區(qū)域,這些值正在被交換。因此,每次交換都會重新排列2個這樣的值,Hoare方案中的所有重新排列都是通過交換完成的。這就是為什么“L”——要重新排列的值的總數(shù)——總是偶數(shù)。

4.循環(huán)賦值

本節(jié)內(nèi)容可能看起來與本文主題有所偏離,但實際上并非如此,因為在優(yōu)化Hoare劃分方案時,我們需要在下一節(jié)中了解循環(huán)賦值的知識。

假設(shè)我們想以某種方式重新排列給定序列“A”中的值的順序。這不一定是劃分,而是任何形式的重新排列。讓我來證明一下,一些重排列需要比其他一些排列更多的賦值操作。

情形1:序列的循環(huán)左移

如果我們想將序列“A”循環(huán)左移1個位置,應(yīng)該完成多少個賦值操作?

長度為N=12的序列“A”的循環(huán)左移示例

我們看到所需的賦值操作數(shù)量為N+1=13,因為我們需要:

1)將“A[0]”存儲在臨時變量“tmp”中,然后

2)“N-1”次將右相鄰值賦值給當(dāng)前值,最后

3)將“tmp”賦值給序列“A[N-1]”的最后一個值。

要做到這一點,所需的操作是:

tmp := A[0]
A[0] := A[1]
A[1] := A[2]
...
A[9] := A[10]
A[10] := A[11]
A[11] := tmp

……這導(dǎo)致了13次賦值操作。

情形2:循環(huán)左移3個位置

在下一個例子中,我們?nèi)匀幌雽ν恍蛄羞M行循環(huán)左移,但現(xiàn)在向左移動3個位置:

序列“A”的循環(huán)左移3的示例,長度N=12序列“A”的循環(huán)左移3的示例,長度N=12

我們看到值A(chǔ)[0]、A[3]、A[6]和A[9]正在相互交換(藍色箭頭)

以及值A(chǔ)[1]、A[4]、A[7]和A[10](粉紅色箭頭)

并且由于值A(chǔ)[2]、A[5]、A[8]和A[11]僅在彼此之間交換(黃色箭頭)。

“tmp”變量被賦值和讀取了3次。

這里我們有3個獨立的賦值鏈/循環(huán),每個長度為4。

為了在A[0]、A[3]、A[6]和A[9]之間正確交換值,需要采取以下行動:

tmp := A[0]
A[0] := A[3]
A[3] := A[6]
A[6] := A[9]
A[9] := tmp

……這里進行了5次賦值。同樣,在組(A[1],A[4],A[7],A[10])和(A[2],A[5],A[8],A[11])內(nèi)交換值將需要分別進行5次賦值。將所有這些加在一起,得到了將序列“A”循環(huán)左移3所需的5*3=15個賦值,其中N=12個值。

情形3:顛倒順序

當(dāng)反轉(zhuǎn)長度為“N”的序列“A”時,執(zhí)行的操作是:

  • 將其第一個值與最后一個值交換,然后
  • 將第二個值與右側(cè)的第二個進行交換,
  • 將第三個值與右側(cè)的第三個進行交換,
  • ……等等。

反轉(zhuǎn)數(shù)組“A”的示例,其中N=12個值反轉(zhuǎn)數(shù)組“A”的示例,其中N=12個值

我們看到成對的值(A[0],A[11]),(A[1],A[10]),(A[2],A[9])等正在相互獨立地交換。變量“tmp”被賦值和讀取6次。

由于每個交換都需要3次賦值,而對于反轉(zhuǎn)整個序列“A”,我們需要進行N/2交換,因此賦值的總數(shù)為:

3*N/2=3*12/2=3*6=18

與“A”相反的賦值的確切順序是:

tmp := A[0] // 循環(huán)1
A[0] := A[11]
A[11] := tmp
tmp := A[1] // 循環(huán)2
A[1] := A[10]
A[10] := tmp

...

tmp := A[5] // 循環(huán)6
A[5] := A[6]
A[6] := tmp

小結(jié)

我們已經(jīng)看到,重新排列相同序列“A”的值可能需要不同數(shù)量的賦值,具體取決于重新排列值的確切方式。

在所提供的3個示例中,序列的長度始終為N=12,但所需分配的數(shù)量不同:

更確切地說,賦值次數(shù)等于N+C,其中“C”是重排過程中產(chǎn)生的循環(huán)次數(shù)。在這里,我所說的“循環(huán)”是指“a”的變量子集,其值在彼此之間旋轉(zhuǎn)。

在我們的例子1(左移1)中,我們只有C=1個賦值循環(huán),“A”的所有變量都參與了這個周期。這就是為什么賦值總數(shù)是:

N+C=12+1=13。

在情形2(左移3)中,我們有C=3個賦值循環(huán),其中:

變量內(nèi)的第一個循環(huán)(A[0]、A[3]、A[6]、A[9])

第二個循環(huán)應(yīng)用于變量(A[1]、A[4]、A[7]、A[10])

第三個循環(huán)應(yīng)用于變量(A[2],A[5],A[8],A[11])。

這就是為什么賦值總數(shù)是:

N+C=12+3=15。

在我們的情形3(反轉(zhuǎn))中,我們有?N/2?=12/2=6個周期。這些都是最短的可能循環(huán),并應(yīng)用于配對(A[0],A[11]),(A[1],A[10]),…等等。這就是為什么賦值的總數(shù)是:

N+C=12+6=18。

當(dāng)然,在所提供的示例中,賦值數(shù)量的絕對差異非常小,在編寫高性能代碼時不會起任何作用。但這是因為我們考慮了一個長度為“N=12”的非常短的數(shù)組。對于較長的數(shù)組,賦值數(shù)量的差異將與N成比例增長。

在結(jié)束本節(jié)時,讓我們記住,重新排列序列所需的賦值數(shù)量會隨著這種重新排列所引入的循環(huán)數(shù)量而增長。如果我們想更快地重新排列,我們應(yīng)該嘗試通過這樣一個方案來實現(xiàn),該方案具有盡可能少的賦值循環(huán)。

5.優(yōu)化Hoare劃分方案

現(xiàn)在,讓我們再次觀察Hoare劃分方案,這次要注意它引入了多少個賦值循環(huán)。

假設(shè)我們有一個長度為N的相同數(shù)組“A”,以及一個必須根據(jù)其進行劃分的基準(zhǔn)值“p”。另外,讓我們假設(shè)數(shù)組中有'L'值,應(yīng)該以某種方式重新排列,以便將“A”帶入劃分狀態(tài)。事實證明,Hoare劃分方案以最慢的方式重新排列這些“L”值,因為它引入了最大可能的賦值循環(huán)數(shù),每個循環(huán)僅由2個值組成。

給定基準(zhǔn)值“p=20”,應(yīng)重新排列的“L=8”值是朝箭頭方向(或離開箭頭方向)。

Hoare劃分方案引入了“L/2=4”個賦值循環(huán),每個循環(huán)只作用于2個值。

在長度為2的循環(huán)中移動2個值,本質(zhì)上就是交換它們,需要3次賦值。因此,Hoare劃分方案的值賦值總數(shù)為“3*L/2”。

我將要描述的優(yōu)化背后的想法來自這樣一個事實,即在對序列進行劃分后,我們通常對值“a[I]<p”的相對順序不感興趣,這些值應(yīng)該在劃分序列的左側(cè)結(jié)束,我們也不關(guān)心值的相對順序,這些值應(yīng)在右側(cè)結(jié)束。我們唯一感興趣的是,所有小于“p”的值都排在其他值之前。這一事實允許我們改變Hoare方案中的賦值循環(huán),并只產(chǎn)生一個賦值循環(huán),其中包含所有的“L”值,這些值應(yīng)該以某種方式重新排列。

讓我先借助下圖描述一下更改后的劃分方案:

更改后的劃分方案,應(yīng)用于相同的序列“A”更改后的劃分方案,應(yīng)用于相同的序列“A”

由于基準(zhǔn)值“p=20”沒有改變,因此應(yīng)重新排列的“L=8”值也相同。

所有箭頭代表新方案中唯一的賦值循環(huán)。

在將所有“L”值移動到它上面之后,我們將得到一個替代的劃分序列。

那么,我們在這里干什么呢?

  • 與原始Hoare方案一樣,首先我們從左側(cè)掃描并找到這樣的值“A[i]>=p”,它應(yīng)該位于右側(cè)。但是,我們沒有用其他值交換它,而是記住它:“tmp:=A[i]”。
  • 接下來,我們從右側(cè)掃描,找到這樣的值“A[j]<p”,它應(yīng)該位于左側(cè)。我們只需執(zhí)行賦值“A[i]:=A[j]”,而不會丟失“A[i]”的值,因為它已經(jīng)存儲在“tmp”中。
  • 接下來,我們從左側(cè)繼續(xù)掃描,找到這樣的值“A[i]>=p”,它也應(yīng)該轉(zhuǎn)到右側(cè)。因此,我們進行賦值“A[j]:=A[i]”,而不會丟失值“A[j]”,因為它已經(jīng)被賦值給了'i'的前一個位置。
  • 這種模式繼續(xù)下去,一旦索引i和j相遇,仍然需要將大于'p'的值放置在“A[j]”中,我們只需執(zhí)行“A[j]:=tmp”,因為最初變量“tmp”保存了從左起的第一個值,大于'p。劃分完成。

正如我們所看到的,這里我們只有一個遍歷所有“L”值的賦值循環(huán),為了正確地重新排列它們,與Hoare方案的“3*L/2”賦值相比,只需要“L+1”值賦值。

我更喜歡將這種新的劃分方案稱為“循環(huán)劃分”,因為所有應(yīng)該以某種方式重新排列的“L”值現(xiàn)在都位于一個賦值循環(huán)中。

下面給出的是循環(huán)劃分算法的偽代碼。與Hoare方案的偽代碼相比,這些變化微不足道,但現(xiàn)在我們將少做1.5倍的任務(wù)。

// 通過“循環(huán)劃分”方案將序列A[0..N)與樞軸值'p'進行劃分,
//并返回結(jié)果右側(cè)部分的第一個值的索引。
function partition_cyclic( A[0..N) : Array of Integers, p: Integer ) : Integer
 i := 0
 j := N-1
 // 找到左邊第一個不在其位置的值
 while i < N and A[i] < p
 i := i+1
 if i == N
 return N // 所有N值都移到左側(cè)
 //下面開始循環(huán)賦值
 tmp := A[i] // 唯一一次寫向變量'tmp'
 while true
 // 根據(jù)需要向右移動索引“j”
 while i < j and A[j] >= p
 j := j-1
 if i == j // 檢查掃描是否完成
 break
 //循環(huán)中的下一個賦值
 A[i] := A[j]
 i := i+1
 //根據(jù)需要向左移動索引“i”
 while i < j and A[i] < p
 i := i+1
 if i == j // 檢查掃描是否完成
 break
 // 循環(huán)中的下一個賦值
 A[j] := A[i]
 j := j-1
 // 掃描已經(jīng)完成
 A[j] := tmp // 唯一一次讀變量'tmp'
 return j

上面代碼中,第5行和第6行設(shè)置了兩次掃描的開始索引('i'從左到右,'j'從右到左)。

第7-9行從左側(cè)搜索這樣的值“a[i]”,該值應(yīng)位于右側(cè)。如果事實證明沒有這樣的值,并且所有N個項目都屬于左側(cè)部分,則第10行和第11行會報告這一點并完成算法。

否則,如果找到了這樣的值,在第13行,我們會將其記在“tmp”變量中,從而在索引“i”處打開一個空位,用于在那里放置另一個值。

第15-19行從右側(cè)搜索這樣的值“a[j]”,該值應(yīng)移動到左側(cè)。一旦找到,第20-22行將其放入索引“i”處的空位中,之后索引“j”處的位置變?yōu)榭眨⒌却硪粋€值。

同樣,第23-27行從左側(cè)搜索這樣的值“a[i]”,該值應(yīng)移動到右側(cè)。一旦找到,第28-30行將其放入索引“j”處的空位中,之后索引“i”處的位置再次變空,并等待另一個值。

這種模式在算法的主循環(huán)中繼續(xù),在第14-30行。

一旦索引'i'和'j'相遇,我們就會在那里有一個空位,第31行和第32行將'tmp'變量中最初記憶的值賦值給那里,因此索引'j'成為第一個保存屬于右側(cè)部分的值的索引。

最后一行返回該索引。

這樣我們就可以在循環(huán)體中一起編寫循環(huán)的2個賦值,因為正如第3節(jié)所證明的那樣,“L”總是偶數(shù)。

該算法的時間復(fù)雜度也是O(N),因為我們?nèi)匀粡膬啥藪呙栊蛄小K粫p少1.5倍的值賦值,因此加速僅反映在常數(shù)因子中。

注意:GitHub網(wǎng)站上提供了C++語言中循環(huán)劃分的實現(xiàn),且在本文末尾引文中也有提供。

我還想證明,無論我們使用什么劃分方案,Hoare方案中的值“L”都不能降低。假設(shè)劃分后,左部分的長度為“l(fā)eft _n”,右部分的長度也為“right _n”。現(xiàn)在,如果查看原始未劃分?jǐn)?shù)組的左對齊“l(fā)eft_n”長區(qū)域,我們會在那里找到一些“t1”值,這些值不在它們的最終位置。因此,這些值大于或等于“p”,無論如何都應(yīng)該移動到右側(cè)。

劃分前后順序的圖示劃分前后順序的圖示

左側(cè)部分的長度為“l(fā)eft_n=7”,右側(cè)部分的長度是“right_n=5”。

在未劃分序列的前7個值中,有“t1=3”

它們大于“p=20”(黃色),應(yīng)該以某種方式移動到右側(cè)。

在未劃分序列的最后5個值中,有“t2=3”

它們小于“p”(淺綠色的),應(yīng)該以某種方式移動到左側(cè)。

同樣,如果查看原始未劃分?jǐn)?shù)組的右側(cè)的“right_n”長度范圍,我們會在那里找到一些't2'值,這些值也不在它們的最終位置。這些值小于'p',應(yīng)該移到左邊。我們不能從左向右移動小于“t1”的值,也不能從右向左移動小于“t2”的值。

在Hoare劃分方案中,“t1”和“t2”值是相互交換的值。所以我們有:

t1 = t2 = L/2,

或者:

t1 + t2 = L.

這意味著,“L”實際上是應(yīng)該以某種方式重新排列的最小數(shù)量的值,以便對序列進行劃分。循環(huán)劃分算法僅通過“L+1”賦值重新排列它們。這就是我允許自己將這種新的劃分方案稱為“近乎最優(yōu)”的原因。

6.實驗結(jié)果

已經(jīng)證明,新的劃分方案執(zhí)行的值賦值更少,因此我們可以預(yù)期它運行得更快。然而,在發(fā)布算法之前,我也想以實驗的方式收集結(jié)果。

我比較了使用Hoare方案和循環(huán)劃分進行劃分時的運行時間。所有實驗都是在隨機亂序的數(shù)組中進行的。

實驗中,使用的不同的參數(shù)有:

  • N——數(shù)組的長度,
  • “l(fā)eft_part_percent”——劃分后左部分長度的百分比(N時)
  • 在原始數(shù)據(jù)類型變量(32位整數(shù))的數(shù)組上運行,與在某種大型對象的數(shù)組(256個16位整數(shù)的長靜態(tài)數(shù)組)上運行相比。我想澄清為什么我發(fā)現(xiàn)有必要在原始數(shù)據(jù)類型的數(shù)組和大型對象的數(shù)組上運行劃分。在這里,我所說的“大對象”是指與原始數(shù)據(jù)類型相比占用更多內(nèi)存的值。在對原始數(shù)據(jù)類型進行劃分時,將一個變量分配給另一個變量的速度將與這兩種算法中使用的幾乎所有其他指令一樣快(例如遞增索引或檢查循環(huán)條件)。同時,在對大型對象進行劃分時,與其他使用的指令相比,將一個這樣的對象分配給另一個對象將花費更多的時間,而此時我們有興趣盡可能減少值賦值的總數(shù)。
    我將在本節(jié)稍后解釋為什么我決定用不同的“l(fā)eft_part_percent”值進行不同的實驗。
    實驗是在以下系統(tǒng)下使用Google Benchmark性能測試工具進行的:
  • CPU:英特爾酷睿i7–11800H@2.30GHz
  • 內(nèi)存:16.0 GB
  • 操作系統(tǒng):Windows 11家庭版,64位
  • 編譯器:MSVC 2022(/O2/Ob2/MD/GR/Gd)

對原始數(shù)據(jù)類型的數(shù)組進行劃分

以下是對原始數(shù)據(jù)類型(32位整數(shù))的數(shù)組運行劃分算法的結(jié)果:

在長度為N=10000的32位整數(shù)數(shù)組上劃分算法的運行時間在長度為N=10000的32位整數(shù)數(shù)組上劃分算法的運行時間

藍色條對應(yīng)于Hoare方案的劃分,而紅色條對應(yīng)于循環(huán)劃分算法。

劃分算法針對5種不同的情況運行,基于“l(fā)eft_part_percent”——劃分后出現(xiàn)的數(shù)組左半部分的百分比(N)。時間以納秒為單位。

我們觀察到,“l(fā)eft_part_percent”的值與兩種算法運行時間的相對差異之間沒有明顯的相關(guān)性。這種行為是意料之中的。

對“大型對象”數(shù)組進行劃分

以下是在所謂的“大對象”數(shù)組上運行2個劃分算法的結(jié)果,每個對象都是一個256長度的16位隨機整數(shù)靜態(tài)數(shù)組。

大對象數(shù)組上劃分算法的運行時間(256個隨機16位整數(shù)的長靜態(tài)數(shù)組),長度N=10000

其中,藍色條對應(yīng)于Hoare方案的劃分,而紅色條對應(yīng)于循環(huán)劃分算法。

劃分算法針對5種不同的情況運行,基于“l(fā)eft_part_percent”——劃分后出現(xiàn)的數(shù)組左半部分的百分比(N)。時間以納秒為單位。

現(xiàn)在,我們看到了一個明顯的相關(guān)性:循環(huán)劃分比Hoare方案表現(xiàn)得更好,因為“l(fā)eft_part_percent”接近50%。換句話說,當(dāng)劃分后數(shù)組的左右部分看起來長度更近時,循環(huán)劃分的工作速度相對更快。這也是一種預(yù)期的行為。

實驗結(jié)果說明

第一個問題:為什么當(dāng)“l(fā)eft_part_percent”接近50%時,劃分通常需要更長的時間呢?

讓我們想象一下一個極端情況——劃分后幾乎所有值都出現(xiàn)在左(或右)部分。這意味著,數(shù)組的幾乎所有值都小于(或大于)基準(zhǔn)值。這意味著,在掃描過程中,所有這些值都被認為已經(jīng)處于最終位置,并且執(zhí)行的值賦值很少。如果試著想象另一種情況——當(dāng)劃分后左右部分的長度幾乎相等時,這意味著執(zhí)行了大量的值賦值(因為最初所有值在數(shù)組中都是隨機混洗的)。

第二個問題:在查看“大型對象”的劃分時,為什么當(dāng)“l(fā)eft_part_percent”接近50%時,兩種算法的運行時間差異會變得更大?

前面的解釋表明,當(dāng)“l(fā)eft_part_percent”接近50%時,需要在數(shù)組中進行更多的值賦值。在前面的幾節(jié)中,我們還表明,與Hoare方案相比,循環(huán)劃分總是使值賦值減少1.5倍。因此,當(dāng)我們通常需要對數(shù)組中的值進行更多重新排列時,1.5倍的差異對整體運行時間的影響更大。

第三個問題:為什么對“大對象”進行劃分時的絕對時間(以納秒為單位)比對32位整數(shù)進行劃分時大?

這個方法很簡單——因為將一個“大對象”分配給另一個對象比將一個原始數(shù)據(jù)類型分配給其他類型需要更多的時間。

此外,我還對不同長度的數(shù)組進行了所有實驗,但總體情況沒有改變。

7.結(jié)論

在本文中,我介紹了一種經(jīng)過修改的劃分方案,稱為“循環(huán)劃分”。與目前使用的Hoare劃分方案相比,它總是能夠減少1.5倍的值賦值。

當(dāng)然,在對序列進行劃分時,值賦值并不是唯一執(zhí)行的操作類型。除此之外,劃分算法檢查輸入序列“A”的值是否小于或大于基準(zhǔn)值“p”,以及它們對“A”上的索引進行遞增和遞減。比較、增量和減量的數(shù)量不會受到引入“循環(huán)劃分”的影響,因此我們不能指望它的運行速度快1.5倍。然而,當(dāng)對復(fù)雜數(shù)據(jù)類型的數(shù)組進行劃分時,其中值賦值比簡單地遞增或遞減索引要耗時得多,整個算法的運行速度實際上可以快1.5倍。

劃分過程是快速排序算法的主要程序,也是查找未排序數(shù)組中值或查找其k階統(tǒng)計量的算法的主要例程。因此,在處理復(fù)雜數(shù)據(jù)類型時,我們還可以預(yù)期這些算法的性能提高1.5倍。

除非另有說明,本文中所有使用的圖像均按作者本人要求而設(shè)計。

參考文獻

【1】——C++中循環(huán)劃分的實現(xiàn):https://github.com/tigranh/cyclic_partition。

譯者介紹

朱先忠,51CTO社區(qū)編輯,51CTO專家博客、講師,濰坊一所高校計算機教師,自由編程界老兵一枚。

原文標(biāo)題:Cyclic Partition: An Up to 1.5x Faster Partitioning Algorithm,作者:Tigran Hayrapetyan


責(zé)任編輯:華軒 來源: 51CTO
相關(guān)推薦

2015-12-10 11:15:02

2015-11-20 08:36:43

2018-05-07 09:48:49

AccordionHBase內(nèi)存

2022-08-08 08:22:22

量子計算

2022-07-17 06:57:02

時間戳唯一標(biāo)識符

2021-03-02 09:06:20

安全API授權(quán)

2022-11-09 08:24:39

2022-06-15 15:56:22

壓縮算法神經(jīng)網(wǎng)絡(luò)

2023-03-07 15:08:57

2015-06-02 10:15:08

2009-04-16 18:52:43

Vmware虛擬化虛擬機

2024-01-18 15:38:17

語言模型大型語言模型

2021-02-24 09:30:44

人工智能PULSE超分辨率算法

2024-03-08 09:29:42

車道檢測AI

2022-07-07 10:33:27

Python姿勢代碼

2022-06-22 09:44:41

Python文件代碼

2020-12-23 10:10:23

Pythonweb代碼

2020-12-09 10:15:34

Pythonweb代碼

2021-04-05 14:44:20

JavaScript循環(huán)代碼

2021-03-23 12:25:40

區(qū)塊鏈穩(wěn)定幣以太坊
點贊
收藏

51CTO技術(shù)棧公眾號

91精品观看| 国产系列在线观看| 亚洲成人原创| 亚洲美女又黄又爽在线观看| 午夜在线观看av| 最爽无遮挡行房视频在线| 北岛玲一区二区三区四区| 国产97色在线| 日韩av不卡播放| 日韩中文字幕电影| 欧美亚洲黄色| 天天综合天天做天天综合| 青青成人在线| 亚洲精品一区二区三区蜜桃| 97在线精品视频| 国产香蕉一区二区三区| 天堂av资源网| 激情综合五月婷婷| 91精品国产91| 日韩影院一区二区| 沈樵精品国产成av片| 日韩欧美的一区| 午夜dv内射一区二区| 欧美另类tv| 中文av一区二区| 久久riav二区三区| 国产wwwxxx| 日av在线不卡| 7777kkkk成人观看| 免费一级片在线观看| jvid福利在线一区二区| 亚洲国产欧美一区二区三区久久| 一本一道久久a久久综合蜜桃| 中文在线а√天堂| 亚洲成人免费电影| 大片在线观看网站免费收看| 97欧美成人| 国产伦精品一区二区三区千人斩 | 日韩一区二区三区高清免费看看| www.亚洲天堂网| hd国产人妖ts另类视频| 亚洲色图另类专区| 亚洲精品中文字幕乱码三区不卡| 91久久在线播放| 国产视频精品视频| 日韩最新av| 91精品国产色综合久久不卡蜜臀| 亚洲国产成人va在线观看麻豆| 成人影院网站| 色综合一个色综合亚洲| 日本少妇高潮喷水视频| av中文字幕在线看| 亚洲一区二区三区国产| 欧美视频在线第一页| av电影免费在线观看| 亚洲欧美乱综合| 可以在线看黄的网站| 免费观看在线黄色网| 国产精品国产三级国产普通话三级| 欧美日韩国产高清视频| 免费在线国产| 久久久久国产精品免费免费搜索| 美女三级99| 伦理片一区二区三区| 久久亚洲综合色一区二区三区| 久久久精品有限公司| 深夜影院在线观看| 久久久久88色偷偷免费| 日韩激情视频| 色网站免费在线观看| 亚洲欧洲无码一区二区三区| 精品久久久久香蕉网| 成人性生交大片免费看小说 | 欧美在线综合| 国产97色在线|日韩| 懂色av蜜臀av粉嫩av分享吧最新章节| 久久一二三区| 国产精品日日做人人爱| 91丨porny丨在线中文| 国产乱码精品一区二区三区av | 精品国产a一区二区三区v免费| 国产亚洲一区精品| 国产中文字幕久久| 亚洲电影在线| 日产精品99久久久久久| 中文字幕久久网| 极品美女销魂一区二区三区| 国产精品久久久久久久久婷婷| 无码国产伦一区二区三区视频 | 精品亚洲成a人| 成人av免费在线看| 日本一级在线观看| 中文字幕色av一区二区三区| 男女日批视频在线观看| 二吊插入一穴一区二区| 7878成人国产在线观看| 手机在线成人av| 清纯唯美亚洲综合一区| 久久久久久久久久久91| 精品一区二区无码| 国产一区二区三区av电影| 精品国产乱码久久久久软件| 波多野结衣在线网站| 亚洲综合一区二区精品导航| 国产av无码专区亚洲精品| 亚洲一区导航| 亚洲欧美另类在线观看| 国产a免费视频| 久久久久久9| 99精品在线直播| 国产三区四区在线观看| 亚洲成人av电影| 天天综合网久久| 亚洲盗摄视频| 欧美日韩ab片| 亚洲手机在线观看| 国产又粗又猛又爽| 激情都市一区二区| 美女三级99| 日本乱理伦在线| 欧美日韩免费视频| 人妻熟女aⅴ一区二区三区汇编| 亚洲精品国产首次亮相| 国产精品69av| 五月婷婷在线播放| 亚洲乱码国产乱码精品精的特点| 黄色手机在线视频| 国产亚洲一区二区三区啪| 久久99精品国产99久久6尤物| av首页在线观看| 91蝌蚪porny九色| 免费在线看黄色片| 精品午夜av| www.亚洲男人天堂| 无码久久精品国产亚洲av影片| av不卡在线观看| 亚洲熟妇无码av在线播放| 豆花视频一区| 日韩在线高清视频| 在线免费看91| 亚洲国产精品99久久久久久久久| 高清在线观看免费| 久久精品凹凸全集| 久99九色视频在线观看| 99er热精品视频| 最新热久久免费视频| 日本黄色福利视频| 日韩在线观看一区| 国产精品三级美女白浆呻吟| 国产精品99999| 欧洲激情一区二区| 中国女人特级毛片| 日本中文字幕不卡| 亚洲精品高清视频| 精品176极品一区| 色香阁99久久精品久久久| 中文字幕永久在线视频| 欧美国产亚洲另类动漫| 天堂av在线网站| 欧美hd在线| 亚洲www在线观看| 亚洲无线看天堂av| 精品噜噜噜噜久久久久久久久试看 | 人人妻人人爽人人澡人人精品| 国产亚洲美州欧州综合国| 麻豆av免费在线| 欧美xxav| 亚洲自拍另类欧美丝袜| av丝袜在线| 亚洲精品少妇网址| 中文字幕91爱爱| 亚洲欧美日韩在线播放| 黑森林av导航| 午夜亚洲视频| 一区二区三区四区欧美日韩| 国产亚洲观看| 7777kkkk成人观看| 亚乱亚乱亚洲乱妇| 欧美一区二区三区在线看| 久久网一区二区| 95精品视频在线| 亚洲成人av免费看| 中文字幕午夜精品一区二区三区 | 亚洲精品国产精品国| 婷婷国产在线综合| 91在线播放国产| 亚洲 日本 欧美 中文幕| 久久久国产精品午夜一区ai换脸| 久久婷婷国产91天堂综合精品| 特级毛片在线免费观看| 青青草在线视频免费观看| 色屁屁一区二区| 91亚洲精品丁香在线观看| 欧美69xxx| 精品国产亚洲在线| 99re这里只有精品在线| 亚洲欧美在线视频观看| 可以看的av网址| 久久亚洲国产精品一区二区| 亚洲一区二区三区精品视频| 综合激情久久| 国产日韩在线看片| www成人免费观看| 日韩在线观看免费高清完整版| 国产综合视频在线| 欧美特级限制片免费在线观看| 免费在线观看日韩| 国产精品无码永久免费888| 日本美女久久久| 久久三级视频| 成人免费看片'免费看| 成人久久电影| 精品国产中文字幕| 人人爱人人干婷婷丁香亚洲| 国产成人小视频在线观看| 黑人精品视频| 精品国模在线视频| 玖玖综合伊人| 亚洲韩国日本中文字幕| 99久久久国产精品无码免费| 欧美最猛黑人xxxxx猛交| 国产无遮挡裸体免费视频| 中文字幕一区在线观看视频| 偷拍夫妻性生活| 成人精品国产一区二区4080| 国产永久免费网站| 日韩av中文字幕一区二区三区 | 一本到12不卡视频在线dvd| 欧洲精品码一区二区三区免费看| 国产精品17p| 91入口在线观看| 4438五月综合| 国产精品久久久久久亚洲影视| 蜜桃视频在线观看免费视频| 欧美激情videos| а√中文在线8| www日韩欧美| 尤物在线视频| 中文字幕日韩欧美| 国产毛片在线看| 亚洲片在线资源| 男女网站在线观看| 亚洲欧美日韩直播| 欧美人体大胆444www| 日韩精品一区二区视频| 午夜视频免费看| 亚洲第一页自拍| 天天插天天干天天操| 欧美精品一区二区高清在线观看| 亚洲经典一区二区三区| 日韩精品一区二区三区四区| 亚洲高清视频网站| 欧美精品一区二区三区视频| 高潮一区二区三区乱码| 亚洲福利小视频| 亚洲欧美日韩动漫| 亚洲欧美在线一区二区| 黄色在线网站| 国产一区二区三区在线视频| 阿v免费在线观看| 中文字幕在线亚洲| caopo在线| 性日韩欧美在线视频| caoporn视频在线观看| 97视频在线播放| 偷拍视频一区二区三区| 国产精品美女www爽爽爽视频| 成人国产精品一区二区免费麻豆| 国产精品一区二区久久| 成人51免费| 岛国视频一区免费观看| 色爱av综合网| 亚洲欧美日韩不卡一区二区三区| 999成人网| 日本黄色片一级片| 久久亚洲色图| 51自拍视频在线观看| 97久久超碰国产精品| 真实乱视频国产免费观看| 国产精品欧美久久久久一区二区| 91高清免费看| 精品久久久在线观看| 国产精品成人无码| 日韩丝袜美女视频| 四虎影视精品成人| 色琪琪综合男人的天堂aⅴ视频| 成人短视频在线观看| 欧亚精品中文字幕| 国产精品777777在线播放| 精品国产aⅴ麻豆| 大片网站久久| 精品少妇在线视频| 日本91福利区| 性久久久久久久久久久| 国产精品国模大尺度视频| 日韩网红少妇无码视频香港| 欧美在线免费播放| 亚洲第一大网站| 一道本无吗dⅴd在线播放一区| 国产精品蜜臀| 国产精品亚洲自拍| 色婷婷综合久久久久久| 99亚洲精品视频| 亚洲专区欧美专区| 伦伦影院午夜理论片| 国产欧美一区二区精品仙草咪| 久久久久久久久久久网| 欧美日韩国产一级片| 欧美一区二区黄片| 久久成人一区二区| 97成人超碰| 欧美高清性xxxxhd| 在线免费观看欧美| 手机看片国产精品| 欧美国产国产综合| 国产免费av一区| 亚洲大尺度美女在线| 成年人网站在线| 国产精品成人aaaaa网站| 国产乱人伦精品一区| 在线免费观看一区二区三区| 亚洲成人激情社区| 亚洲午夜久久久| 又污又黄的网站| 日韩精品极品在线观看| 男女在线观看视频| 成人黄色生活片| 日本道不卡免费一区| 亚洲熟妇av一区二区三区| 成人福利电影精品一区二区在线观看| 日韩av毛片在线观看| 欧美性一区二区| 国内精品在线视频| 全球成人中文在线| 香蕉视频一区| 日本一区二区黄色| 91香蕉视频在线| 97超碰人人干| 亚洲精品wwww| 成av人片在线观看www| 国产精品区免费视频| 韩日视频一区| 国产精品偷伦视频免费观看了 | 亚洲日本精品国产第一区| 视频在线观看国产精品| 久久久久久久久久久久| 一本到不卡精品视频在线观看 | eeuss国产一区二区三区四区| 成人国产一区二区三区| 韩国毛片一区二区三区| 黄色香蕉视频在线观看| 777a∨成人精品桃花网| 日本高清中文字幕在线| 91色在线视频| 欧美精品日本| 亚洲午夜久久久久久久久| 亚洲国产毛片aaaaa无费看| 少妇人妻精品一区二区三区| 91国语精品自产拍在线观看性色 | 日韩亚洲欧美中文在线| 91精品福利观看| 国产精品av免费观看| 国产69精品久久777的优势| 日操夜操天天操| 亚洲视频视频在线| 青青热久免费精品视频在线18| 亚洲午夜精品一区二区三区| 国产一区二区三区免费观看| 久久久久久久久久一区二区三区| 亚洲国产欧美一区二区三区同亚洲| 亚洲插插视频| 亚洲一卡二卡区| 国产成人在线视频网站| 国产成人免费观看视频| 一区二区三区日韩在线| 美女精品视频在线| 老太脱裤子让老头玩xxxxx| 久久久不卡影院| 91久久久久久久久久久久| 欧美极品美女电影一区| 国产99久久久国产精品成人免费 | 日本久久二区| 97中文字幕在线| 国产午夜一区二区三区| 国产精品国产av| 5278欧美一区二区三区| 欧美国产美女| 国产二级一片内射视频播放| 日韩午夜电影网| 久久久久久久久久久久久国产| heyzo一本久久综合| 在线免费观看一级片| 久久久中精品2020中文| 欧美日韩国产一区二区三区不卡 | 国产无一区二区| 国产精品毛片久久久久久久久久99999999| 欧美在线视频a| 色狮一区二区三区四区视频| 中文字幕在线观看91| 色悠久久久久综合欧美99|