一,分割(partition)演算法介紹
所謂分割演算法,先選定乙個樞軸元素,然後 將陣列中的元素分成兩部分:比樞軸元素小的部分都位於樞軸元素左邊;比樞軸元素大的部分都位於樞軸元素右邊
此時,樞軸元素在陣列中的位置就被「永久地確定」下來了---將整個陣列排序,該樞軸元素的位置不會變化。
另外,樞軸元素的選取對分割演算法至關重要。一般而言,終極追求的是:將陣列平分。因此,盡可能地讓樞軸元素的選取隨機化和靠近中位數。
這裡採用「三數取中」法選取樞軸元素。
關於快速排序排序演算法,可參考:排序演算法總結之快速排序
二,分割演算法的實現
1//分割陣列,將陣列分成兩部分. 一部分比pivot(樞軸元素)大,另一部分比pivot小
2private
static
int parition(int arr, int left, int
right)
11while(arr[--j] >pivot){}
12if(i 13swap(arr, i, j);
14else
15break;16
}1718 swap(arr, i, right-1);//
restore pivot, 將樞軸元素放置到合適位置:arr左邊元素都比pivot小,右邊都比pivot大
19return i;//
返回 pivot的 索引
20 }
①第4行,樞軸元素是通過「三數取中」法選擇的。在「三數取中」時,還做了一些優化:將 樞軸元素 放到 陣列末尾的倒數第二個位置處。具體參考 media3()
需要注意的是:當輸入的陣列中長度為1 或者 2 時, partition會出現向下越界(但對快排而言,當陣列長度很小的,其實可以不用 partition,而是直接用插入排序)。因此,可加入以下的修改。
1//分割陣列,將陣列分成兩部分. 一部分比pivot(樞軸元素)大,另一部分比pivot小
2private
static
int parition(int arr, int left, int
right)
15while(arr[--j] >pivot){}
16if(i 17swap(arr, i, j);
18else
19break;20
}2122 swap(arr, i, right-1);//
restore pivot 將樞軸元素放置到合適位置:arr左邊元素都比pivot小,右邊都比pivot大
23return i;//
返回 pivot的 索引
24 }
再來看看,三數取中演算法,這裡也有個特殊情況:當陣列中元素個數都沒有3個時....怎麼辦?
1//三數取中,用在快排中隨機選擇樞軸元素時
2private
static
int media3(int arr, int left, int
right)
其實,這裡的「三數取中」的實現,與參考資料中提到的三數取中實現有一點不同。這是正常的,畢竟實現細節不同。如果有錯誤,需要自行除錯。
這裡提下第3-7行的兩個if語句:當需要 「取中」的目標陣列長度為1時,或者說 對陣列中某些範圍內[left, right]的元素進行「取中」時,若left=right,則根本就沒有3個數,違背了「三數取中」的本意(隨機地選取樞軸元素),故直接 return。
當陣列中元素只有乙個時,第18行會越界。為了防止這種情況,在第3-4行就先對陣列長度進行判斷。當陣列中只有兩個元素,其實就相當於 center=left,因此,程式也沒問題。
三,分割演算法的應用
給定乙個陣列,陣列中某個元素出現的次數超過了陣列大小的一半,找出這個元素。
比如輸入:[2,5,4,4,5,5,5,6,5] ,輸出 5
這個問題,其實可以轉化成求解中位數問題。因為,當陣列有序時,出現次數超過一半的那個元素一定位於陣列的中間。
所謂中位數,就是 假設 陣列是有序的情況下,中間那個元素。即 arr[arr.length/2]
而要求解中位數,當然可以先對陣列進行排序,但排序的時間複雜度為o(nlogn),那有沒有更快的演算法?
當然是有的。就是借助partition分割演算法 來 實現。
1//找出 arr 中 第 n/2 大的那個元素
2public
static
int media_number(int
arr)
15else19}
20return
arr[center];
21 }
上面演算法不僅可以求解「找出超過一半的數字」,也可以求解任何乙個陣列的中位數。
這裡遞迴表示式 t(n)=t(n/2)+o(n),o(n)表示將陣列 分成兩部分所花的代價。
故時間複雜度為o(n)
四,參考資料
整個完整**
publicclass
middle_large
else
}return
arr[center];
}//分割陣列,將陣列分成兩部分. 一部分比pivot(樞軸元素)大,另一部分比pivot小
private
static
int parition(int arr, int left, int
right)
while(arr[--j] >pivot){}
if(i swap(arr, i, j);
else
break
; }
swap(arr, i, right-1);//
restore pivot 將樞軸元素放置到合適位置:arr左邊元素都比pivot小,右邊都比pivot大
return i;//
返回 pivot的 索引
}
//三數取中,用在快排中隨機選擇樞軸元素時
private
static
int media3(int arr, int left, int
right)
private
static
void swap(int arr, int left, int
right)
public
static
void
main(string args) ;
int result =media_number(arr);
system.out.println(result);
}}
快速排序中的分割演算法的解析與應用
一,分割 partition 演算法介紹 所謂分割演算法,先選定乙個樞軸元素,然後 將陣列中的元素分成兩部分 比樞軸元素小的部分都位於樞軸元素左邊 比樞軸元素大的部分都位於樞軸元素右邊 此時,樞軸元素在陣列中的位置就被 永久地確定 下來了 將整個陣列排序,該樞軸元素的位置不會變化。另外,樞軸元素的選...
Hadoop中的快速排序演算法
在hadoop中,排序是mapreduce框架中最重要的操作之一,map task和reduce task都會對資料按照key排序,不管邏輯上是否真的需要排序,任何程式中的資料都會被排序,這是hadoop的預設行為。b mapreduce中使用了兩種排序演算法 快速排序和優先佇列。在map和redu...
談談演算法中的快速排序
快速排序 快速排序是c.r.a.hoare於1962年提出的一種劃分交換排序。它採用了一種分治的策略,通常稱其為分治法 divide and conquermethod 快速排序使用分治法把乙個陣列,分為兩個子陣列,該方法的基本思想是 1 先從數列中取出乙個數作為基準數。2 分割槽過程,將比這個數大...