精品欧美一区二区三区在线观看 _久久久久国色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ù)棧公眾號

国产精品二区三区四区| 日韩欧美一区二区三区| 99国产在线视频| 国产中文字字幕乱码无限| 亚洲视频国产精品| 欧美日韩激情视频| 亚洲永久激情精品| 风流老熟女一区二区三区| 日韩天堂av| 中文字幕最新精品| 午夜视频在线观| 国产调教在线| 国产日产亚洲精品系列| 成人网欧美在线视频| 日韩天堂在线观看| 欧美日韩国产不卡在线看| 中文有码在线播放| 国产精品黄色| 综合欧美国产视频二区| 久久人妻少妇嫩草av无码专区| www.成人影院| 亚洲午夜av在线| 色一情一乱一伦一区二区三区丨| 99热这里只有精品66| 国产视频欧美| 欧美日本中文字幕| 极品尤物一区二区| 香蕉久久精品| 精品国产乱码久久久久久老虎| 亚洲高清在线免费观看| 高清电影在线免费观看| 国产精品乱人伦一区二区| 国产综合欧美在线看| 国产绿帽刺激高潮对白| 日本美女一区二区三区视频| 97人人模人人爽人人喊中文字 | 色av性av丰满av| 欧美亚洲不卡| 欧美精品中文字幕一区| 国产三级aaa| 狠狠色丁香婷婷综合影院| 亚洲精品电影在线| 国产大学生视频| 视频在线观看免费影院欧美meiju 视频一区中文字幕精品 | 久久精品欧美| 亚洲欧美另类日韩| 国产成人一区二区精品非洲| 成人网址在线观看| 一级黄色片网站| 蜜臀av一区二区| 国产精品高潮呻吟久久av无限| 欧美一二三区视频| 99亚洲伊人久久精品影院红桃| 欧美日韩不卡合集视频| 久草中文在线视频| 激情另类综合| 国内精品中文字幕| 日韩精品一卡二卡| 99精品视频免费观看| 午夜精品在线视频| 中文字幕亚洲高清| 亚洲欧美日韩国产综合精品二区| 欧美亚洲国产另类| 国内精品久久国产| 一区二区三区在线播放视频| 精品国产精品国产偷麻豆| 亚洲一级黄色av| 九一在线免费观看| 99久久99久久精品国产片桃花| 日韩在线视频免费观看高清中文 | 国产熟女精品视频| 国产一区欧美一区| 成人三级在线| 色视频在线看| 久久精品人人做| 一区二区三区不卡在线| 91精品久久| 偷窥国产亚洲免费视频| 国语对白做受xxxxx在线中国| 视频在线日韩| 欧美一卡二卡三卡| 中文视频在线观看| 精品72久久久久中文字幕| 在线午夜精品自拍| 国产又黄又爽又无遮挡| 亚洲人体大胆视频| 国产精品久久77777| 国产老女人乱淫免费| 成人免费黄色大片| 欧美资源一区| 色呦呦在线观看视频| 欧美日韩在线视频观看| 亚洲欧美日韩一区二区在线 | а天堂中文在线资源| 91精品啪在线观看国产18| 国外成人在线播放| 依依成人在线视频| 成人国产精品免费网站| 天天综合狠狠精品| av色在线观看| 欧美日韩国产一级二级| 大尺度做爰床戏呻吟舒畅| 狠狠做深爱婷婷综合一区| 欧美成人免费va影院高清| 国产精品男女视频| 国产一区二三区好的| 欧美久久综合性欧美| 国产在线看片| 在线观看视频一区二区欧美日韩| 欧美国产在线一区| 精品国产aⅴ| 91高清视频在线免费观看| 91精品在线视频观看| 91美女片黄在线观看| 97超碰免费观看| 日日av拍夜夜添久久免费| 精品欧美一区二区在线观看| 波多野结衣欲乱| 久久www成人_看片免费不卡| 97netav| 性开放的欧美大片| 色婷婷久久久亚洲一区二区三区 | 欧美成人精品午夜一区二区| 国产亚洲精品美女久久久| 国产精品16p| 国产乱理伦片在线观看夜一区 | 大乳在线免费观看| 精品美女永久免费视频| 亚洲国产欧美91| 久久精品不卡| 国产精品久久久久福利| 台湾av在线二三区观看| 亚洲图片欧美一区| 四川一级毛毛片| 久久久久国产精品| 国产欧美日韩视频| 国产精品四虎| 色狠狠一区二区| 亚洲一区二区三区无码久久| 欧美激情综合色综合啪啪| 91美女高潮出水| 蜜桃视频在线观看www社区| 日本精品一级二级| 草草影院第一页| 午夜亚洲福利在线老司机| 国产免费高清一区| 波多野结依一区| 日韩视频123| 欧美日韩国产精品综合| 国产精品自在欧美一区| av不卡在线免费观看| 国产香蕉久久| www.久久久久久.com| 中文字幕在线2019| 自拍偷拍国产亚洲| www.偷拍.com| 一区在线视频| 狠狠久久综合婷婷不卡| aaa在线播放视频| 日韩国产精品一区| 无码人妻精品一区二区| 国产亚洲欧美在线| 午夜免费福利在线| 91精品综合久久久久久久久久久| 成人a视频在线观看| 麻豆传媒视频在线观看免费| 欧美一区二区三区四区高清| 久热这里只有精品在线| 91丝袜国产在线播放| 成人免费无码av| 欧美mv日韩| 99热在线国产| 人狥杂交一区欧美二区| 伊是香蕉大人久久| 国产偷拍一区二区| 亚洲不卡在线观看| 级毛片内射视频| 久久国产婷婷国产香蕉| 日本一级黄视频| 欧美日韩导航| 国产精品一区二区三区在线播放| 国产原创在线观看| 亚洲黄色在线观看| 最近中文字幕在线观看| 亚洲美女免费在线| 99久久人妻无码中文字幕系列| 日韩影院在线观看| 欧美a级黄色大片| 色综合久久中文| 91久久国产综合久久91精品网站| 久色国产在线| 伊人久久免费视频| 国精品人妻无码一区二区三区喝尿| 日韩欧美在线视频| 亚洲国产精品免费在线观看| 91一区二区三区在线观看| 久热精品在线播放| 99国产精品| 一级一片免费播放| 色狠狠久久av综合| 亚洲一区亚洲二区| 国产伦精品一区二区三区视频金莲| 久久精品电影网| 欧美色综合一区二区三区| 91麻豆精品国产无毒不卡在线观看 | 亚洲欧美强伦一区二区| 欧美在线免费观看亚洲| 国产无遮挡aaa片爽爽| 国产精品久久久久久久久图文区| 天天躁日日躁狠狠躁av麻豆男男| 免费观看久久久4p| 一女被多男玩喷潮视频| 艳女tv在线观看国产一区| 欧洲一区二区在线观看| 中文一区二区三区四区| 国产九九精品视频| 日韩av福利| 国外成人性视频| 日本一级理论片在线大全| 色悠悠国产精品| 免费在线超碰| 亚洲精品98久久久久久中文字幕| 国产精品无码在线播放| 欧美亚洲动漫精品| 国产精品久免费的黄网站| 亚洲愉拍自拍另类高清精品| 成人涩涩小片视频日本| 国产精品网友自拍| 这里只有久久精品| 91啦中文在线观看| 国产精品成人99一区无码| 国产一区二区女| 欧美成人三级在线播放| 日本在线播放一区二区三区| 日本免费黄视频| 999亚洲国产精| 2018国产在线| 亚洲精选久久| 久久99久久99精品| 影音先锋久久资源网| 特级西西人体www高清大胆| 91麻豆精品国产91久久久平台| 天堂精品视频| 少妇精品久久久一区二区| 欧美深深色噜噜狠狠yyy| 日本三级久久| 久久综合中文色婷婷| 天美av一区二区三区久久| 好吊色欧美一区二区三区视频| 国产欧美一区二区三区米奇| 国产精品二区三区四区| 国内毛片久久| 久久精品综合一区| 竹菊久久久久久久| 日韩精品伦理第一区| 精品不卡一区| 亚洲制服欧美久久| 亚洲老妇激情| 97在线免费视频观看| 国产精品sm| 国产深夜男女无套内射| 香蕉久久国产| 国产真人无码作爱视频免费| 免费黄网站欧美| 91 视频免费观看| 国产91精品免费| 国产精品福利导航| 国产女同性恋一区二区| 天天做夜夜爱爱爱| 一二三区精品福利视频| 日韩欧美a级片| 日本韩国欧美三级| 国产精品久久777777换脸| 日韩三级在线免费观看| 亚洲av成人精品毛片| 亚洲最新中文字幕| 91中文在线| 91超碰中文字幕久久精品| 777午夜精品电影免费看| 91久久久久久久久久| 成功精品影院| 日本一区免费在线观看| 国产精品97| 精品国产一区三区| 免费观看在线综合色| 日本一级大毛片a一| 国产三级精品三级在线专区| 国精品无码一区二区三区| 欧美日韩国产中文精品字幕自在自线 | 国产成人精品一区二区在线小狼| 成年人国产精品| www.99热| 亚欧色一区w666天堂| 少妇又紧又色又爽又刺激视频| 欧美一区二区免费观在线| 午夜影院免费体验区| 久久亚洲综合国产精品99麻豆精品福利 | 国产精品亚洲欧美在线播放| 亚洲精品久久久一区二区三区| shkd中文字幕久久在线观看| 欧美黑人狂野猛交老妇| 亚洲成av在线| 韩国一区二区三区美女美女秀 | 精品国产一区二| 欧美日韩在线一区二区三区| 国产专区一区| 亚洲成人福利在线| 久久综合久久鬼色| 劲爆欧美第一页| 欧美日韩视频在线观看一区二区三区| 人妻一区二区三区免费| 久久久电影免费观看完整版| 成人做爰视频www网站小优视频| 99九九视频| 欧美好骚综合网| 国产成人精品视频ⅴa片软件竹菊| 成人手机电影网| 一区二区三区影视| 在线精品视频免费播放| 无码国产精品一区二区免费16| 麻豆成人在线看| 精品九九久久| 欧美亚洲爱爱另类综合| 精品999网站| 美女被艹视频网站| 成人免费在线播放视频| 波多野结衣视频在线看| 日韩经典第一页| 超碰97免费在线| 99影视tv| 欧美喷水视频| 国产高清av片| 国产精品久久久久国产精品日日| 一级成人黄色片| 亚洲国产精品高清久久久| 欧美日韩经典丝袜| 国产成人av一区二区三区| 亚洲精品一区二区在线看| 亚洲欧美日本一区二区三区| 国产精品你懂的在线| 最好看的日本字幕mv视频大全| 精品亚洲国产成av人片传媒| 狼人综合视频| 久久亚洲国产精品日日av夜夜| 在线亚洲精品| www在线观看免费视频| 精品国产精品自拍| 色网站在线免费观看| 欧洲亚洲女同hd| 久久99蜜桃| 日韩福利视频在线| 欧美高清在线一区二区| 少妇无套内谢久久久久| 在线成人激情视频| 日韩漫画puputoon| 亚洲精品成人a8198a| 麻豆成人91精品二区三区| 污污视频网站在线免费观看| 欧美精品在线观看一区二区| 成人ww免费完整版在线观看| 99r国产精品视频| 亚洲第一精品影视| 国产精品无码永久免费不卡| 色综合久久综合网97色综合| 国产在线一二三区| 国产中文字幕91| 国产在线日韩| 一区二区黄色片| 欧美日韩精品一区二区三区| 超碰在线无需免费| 国产九区一区在线| 首页国产欧美日韩丝袜| 91视频免费看片| 欧美成人艳星乳罩| 英国三级经典在线观看| 日韩av影视| 国产麻豆欧美日韩一区| 国产无遮无挡120秒| 亚洲女人天堂视频| 亚洲成人1区| www.射射射| 日本一区二区免费在线观看视频| 国产精品探花视频| 久久久久这里只有精品| 国产一区二区三区站长工具| www.桃色.com| 欧美午夜视频一区二区| 精品美女在线观看视频在线观看| 国产伦精品一区二区三区视频黑人| 久久久久国产精品一区三寸| 国产探花在线视频| 亚洲黄色有码视频| 99精品美女视频在线观看热舞| 免费观看国产精品视频| 日本一区二区三区四区| 亚洲精品久久久久久久久久 | 久久精品国产久精国产一老狼| 91精品短视频| 粉色视频免费看| 偷拍亚洲欧洲综合|