数组排序(冒泡、快速)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hebsun/article/details/83443447

面试的时候总爱问排序,其实排序并不难,只是将一个排序的思路转成编程语言实现。对于实际工作中,我们遇到的业务逻辑,要比排序的逻辑复杂的多,却奇怪于有的公司总爱问这个,更奇怪的是,总有朋友答不上来。(说来惭愧,答不上来的人里也包括我自己,不是不会写,只是不知道什么是快速排序)。这里整理了下面两个排序。

先来说说冒泡排序,冒泡排序就是将当前位置的数依次和后面位置的数比较,将大数放在前面,小数放在后面。

如:int[] arr = {3,2,6,4,1,5,8,9,7};排序完以后的结果:int[] arr = {9,8,7,6,5,4,3,2,1};

3和2比较,3在前面,不需要交换;3和6比较,6放前面;6和4比较,6放前面;。。。如此继续比较下去。

下面看看程序怎么写:

package mytest;

public class TestSortUtil {
	public static int[] sort(int[] arr) {
		for(int i=0;i<arr.length;i++) {
			for(int j=i+1;j<arr.length;j++) { //i=0,j=1,2,3,4,...j初始值是j=i+1=0+1。后面j++,也就是第一个元素和后面的元素依次比较。
				if(arr[i]<arr[j]) { //当arr[i]后面的元素小于后面的元素交换。
					int tmp = arr[i];
					arr[i]=arr[j];
					arr[j]=tmp;
				}
                //print(arr);//如果想看排序过程打开这里的输出就可以
			}
		}
		return arr;
	}
	public static void print(int[] arr) {
		for(int i=0;i<arr.length;i++) {
			System.out.print(" "+arr[i]);
		}
		System.out.println();
	}
	
	public static void main(String args[]) {
		int[] arr = {3,2,6,4,1,5,8,9,7};
		print(arr);
		print(sort(arr));
	}
}

冒泡排序就是这样。

我们再来说说快速排序;先看百科定义:快速排序(Quicksort)是对冒泡排序的一种改进;它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

首先,要选一个分割点key(百科叫关键数据),通常是数组的第一个数据。(分割点最好是随机从数组里取出来一个数据)

然后,就是第一遍排序,分割点值小的放前面,分割点大的数据放后面。一个从前向后比较arr[i]<key,取到第一个下标i;一个从后向前比较arr[j]>key,取到第一下标j;将第一个大于key的值和第一个小于key的值互换。i==j时比较到中间位置结束;这样就分成了两部分数据。举例:int[] arr = {3,2,6,4,1,5,8,9,7}; 如果key是3,从前向后找到的第一个值是6,从后向前找到的第一个值是1;则6和1交换。

然后,前后两部分分别再进行递归排序,这样就可以将程序写成一个递归调用。

下面再来看看程序

package mytest;

public class TestFastSort {

	
	public static int[] fastsort(int[] arr,int begin,int end) {
		int left = begin;//排序开始的时候:begin=0,end=N-1;
		int right = end;
		int key = arr[begin];//以第一个数组元素作为关键数据,赋值给key,即key=arr[begin];
		
		while(left != right) {
			
			while(arr[left] < key) {//从前向后搜索
				left++;
			}
			
			while(arr[right] > key) {//从后向前搜索
				right--;
			}
			
			//此时arr[left]是第一个大于key的值;arr[right]是第一个小于key的值
			int temp = arr[left];
			arr[left] = arr[right];
			arr[right]=temp;
			//完成这两个值交换
			
			print(arr);
		}//当left和right相同时,循环结束。
		
		if(begin<left) {
			fastsort(arr,begin,left-1);
		}
		if(right<end) {
			fastsort(arr,right+1,end);
		}
		
		return arr;
	}
	
	public static void print(int[] arr) {
		for(int i=0;i<arr.length;i++) {
			System.out.print(" "+arr[i]);
		}
		System.out.println();
	}
	
	public static void main(String args[]) {
		int[] arr = {3,2,6,4,1,5,8,9,0,7};
		print(arr);
		print(fastsort(arr,0,arr.length-1));
	}
}

如此,是不是明白了,为什么说快速排序就是冒泡排序的优化了吧?其实就是先进行第一遍排序,选出中间值分成两部分,然后对两部分再分别排序。

那多的这一步,为什么能比冒泡排序快呢?答降低了复杂度,那么如何降低了复杂度?

先来看看冒泡顺序:

1.        时间复杂度:O(n^2)

冒泡排序耗时的操作有:比较 + 交换(每次交换两次赋值)。时间复杂度如下:

1)        最好情况:序列是升序排列,在这种情况下,需要进行的比较操作为(n-1)次。交换操作为0次。即O(n)

2)        最坏情况:序列是降序排列,那么此时需要进行的比较共有n(n-1)/2次。交换操作数和比较操作数一样。即O(n^2)

3)        渐进时间复杂度(平均时间复杂度):O(n^2)

2.        空间复杂度:O(1)

从实现原理可知,冒泡排序是在原输入数组上进行比较交换的(称“就地排序”),所需开辟的辅助空间跟输入数组规模无关,所以空间复杂度为:O(1)1.   

再来看看快速排序


1.        时间复杂度:O(nlog2n)

快速排序耗时的操作有:比较 + 交换(每次交换两次赋值)。时间复杂度如下:

1)        最好情况:选择的基准值刚好是中间值,分区后两分区包含元素个数接近相等。因为,总共经过x次分区,根据2^x<=n得出x=log2n,每次分区需用n-1个元素与基准比较。所以O(nlog2n)

2)        最坏情况:每次分区后,只有一个分区包含除基准元素之外的元素。这样就和冒泡排序一样慢,需n(n-1)/2次比较。即O(n^2)

3)        渐进时间复杂度(平均时间复杂度):O(nlog2n)

2.        空间复杂度:O(1)

从实现原理可知,快速排序是在原输入数组上进行比较分区的(称“就地排序”),所需开辟的辅助空间跟输入数组规模无关,所以空间复杂度为:O(1)

猜你喜欢

转载自blog.csdn.net/hebsun/article/details/83443447