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

排序算法是比较常见的算法,道理也比较简单,双指针法。今天被朋友问了个舍伍德排序算法,也是快速排序那种形式。尴尬,第一次听说,特意学了一下。结合快速排序,写了三个方法。
第一种:

	//不需要将基准值归位的快速排序
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);
	
}

第二种:

//需要将基准值归位的快速排序
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;
	}
	
	
	
	
}

你可能感兴趣的:(算法学习)