快速排序算法與舍伍德快速排序算法

排序算法是比較常見的算法,道理也比較簡單,雙指針法。今天被朋友問了個舍伍德排序算法,也是快速排序那種形式。尷尬,第一次據說,特地學了一下。結合快速排序,寫了三個方法。
第一種:java

//不須要將基準值歸位的快速排序
public static void quickSort(int []a,int left,int right) {
	if(left>=right) return ;
	int i = left ;//左指針
	int j = right ;//右指針
	int key = a[i];//基準值
	while(i<j) {
		//右指針先遍歷,直到找到一個小於基準值的
		while(i<j&&a[j]>=key) j--;
		//交換右指針與左指針的值
		if(i<j&&a[j]<key) {
			int temp = a[i];
			a[i] = a[j];
			a[j] = temp;
		}
		//左指針遍歷,直到找到一個大於基準值的
		while(i<j&&a[i]<=key)i++;
		//交換左右指針的值
		if(i<j&&a[j]>key) {
			int temp = a[i];
			a[i] = a[j];
			a[j] = temp;
		}
	}
	//遞歸處理左右數組
	quickSort(a,left,i-1);
	quickSort(a,i+1,right);
	
}

第二種:web

//須要將基準值歸位的快速排序
public static void quickSort2(int []a,int left,int right) {
	if(left>=right) return ;
	int i = left ;//左指針
	int j = right ;//右指針
	int key = a[i];//基準值
	while(i<j) {
		//右指針先遍歷,直到找到一個小於基準值的
		while(i<j&&a[j]>=key) j--;
		//左指針遍歷,直到找到一個大於基準值的
		while(i<j&&a[i]<=key)i++;
		//交換左右指針的值
		if(i<j) {
			int temp = a[i];
			a[i] = a[j];
			a[j] = temp;
		}
	}
	a[left]=a[j];
	a[j] = key;
	//遞歸處理左右數組
	quickSort(a,left,i-1);
	quickSort(a,i+1,right);
	
}

第三種:舍伍德算法
通常快速排序存在最好最壞狀況。
最好狀況:
當一組數無序,每次劃分紅兩個數組時,都能均勻的分紅兩部分。這樣最好狀況複雜度爲nlogn。()
最壞狀況:
當一組數有序,每次劃分都只能劃分掉一個數,最終複雜度爲n^2.
如1 2 3 4 5 第一次分爲 1 2345
第二次分爲 2 345
第三次分爲 3 45
第四次 4 5
這樣至關於要劃分n次,每次比較數也看作n,則爲n^2。
雖然快速排序平均複雜度能夠看作nlogn.但算法複雜度與輸入實例之間有關係,未必都是平均時間複雜度。
這就是要採用舍伍德快速排序的緣由,消除掉算法複雜度與輸入實例之間的關係。算法

//舍伍德快速排序算法(找到第K大的數)
public static int quickSort3(int []a,int k) throws Exception {
	if(k>a.length||k<=0) throw new Exception("k值輸入不在異常");
	int l= 0;
	int r = a.length-1;
	while(true) {
	if(l>=r) return a[l];
	int i = l;
	//隨機獲取一個基準
	Random rnd = new Random();
	int j = 1+rnd.nextInt(r-1);
	//交換a[i]與基準的值,使得基準爲左邊第一個
	swap(a,i,j);
	j = r+1;
	int pivot = a[l];
	while(true) {
		//找到大於pivot的值後,跳出循環
		while(i<a.length-1&&a[++i]<pivot) ;
		//找到小於pivot的值後,跳出循環
		while(j>0&&a[--j]>pivot) ;
		if(i>=j) break;
		swap(a,i,j);
	}
	//第一次循環結束後,判斷此時的j,處在第幾大的位置
	if(j-l+1 == k) return pivot;
	//基準歸位,由於此時j的值小於基準,而基準在第一個位置,下面
	//兩條語句交換完後,保證左邊的數都小於基準,右邊的都大於
	a[l] = a[j];
	a[j] = pivot;
	//對子數組從新進行劃分
	if(j-l+1<k) {
		k = k-j+l-1;
		l=j+1;//若是左邊的數小於K個,l=j+1從右邊數組繼續劃分 
	}else r=j-1;
	}
	
	
	
	
}