[排序算法]:Java实现冒泡排序和快速排序

       这段时间看了许多经典排序算法,所以就索性写一下个人对于这些排序的理解。方便以后回顾算法知识。当然,大部分都是以代码作为切入点,至于排序算法的理论知识可能不会过多讲解,请自行查阅,敬请谅解!

冒泡排序

思想:
       整个过程像气泡一样往上升,单向冒泡排序的基本思想是(假设由小到大排序):对于给定n个记录,从第一个记录开始依次对相邻的两个记录进行比较,当前面的记录大于后面的记录时,交换位置,进行一轮比较和换位后,n个记录的最大记录将位于第n位,然后对前(n-1)个记录进行第二轮比较;重复该过程,直到记录剩下一个为止。
Java代码:
public class Test {
	public static void main(String[] args) {
		int[] arr = {32,45,34,5,63,54,21};
		bubbleSort(arr);
		System.out.println(Arrays.toString(arr));
		//输出结果:[5, 21, 32, 34, 45, 54, 63]
	}
	//冒泡排序
	public static void bubbleSort(int[] arr) {
		int temp = 0; //记录临时值		
		for(int i = 0; i < arr.length - 1; i++) {
			for(int j = 0; j < arr.length - 1 - i; j++) {
				//和后面进行比较,值小的往前移动
				if(arr[j] > arr[j+1]) {
					temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}
			}
		}
	}	
}

冒泡代码解析:
       冒泡排序需要对每一个数都进行比较,如果需要比较8个数,那么只要比较出其中7个,则最后一个无需再次比较的,所以外循环中,比较次数可以设为length - 1。
       这时候,再来看内行循环做了什么,内循环每次都以第一位元素作为起始点,然后和剩余数值进行比较,这一过程会将较小值放到前面来,但不一定是最小值,但一定会把最大值放到最后:
	public static void bubbleSort(int[] arr) {
		int temp = 0; //记录临时值		
		for(int i = 0; i < arr.length - 1; i++) {
			for(int j = 0; j < arr.length -1 - i; j++) {
				if(arr[j] > arr[j+1]) {
					temp = arr[j];
					arr[j] = arr[j+1];
					arr[j+1] = temp;
				}
				System.out.println("第" +(j+1)+ "次:"  + Arrays.toString(arr));//打印比较过程
			}
			System.out.println("---------------------------------");
		}
	}	

如图:第一次比较完成后,最大值就沉底了~,但剩余元素还需要进行排序
[排序算法]:Java实现冒泡排序和快速排序_第1张图片


再次看图:每比较一次就把剩余的元素中的最大值放到后面,下面是比较两次,最大值都被依次放在后面了。
[排序算法]:Java实现冒泡排序和快速排序_第2张图片 [排序算法]:Java实现冒泡排序和快速排序_第3张图片

这意味着不需要每次都全部比较一遍,每次比较的流程可以进行优化,即 j < arr.length - 1 - i  。外循环每比较一次,内循环下次比较时相应减少比较次数。因为后面的已经排序好了,无需再次比较,浪费效率。

至于排序是从小到大,还是从大到小,根据需求调整相应比较条件既可。

至此,冒泡排序的使用和解析完成。



快速排序

思想:
     快速排序是对冒泡排序的一种改进。它的基本思想是:通过一躺排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一不部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
	//再次封装一层,对起始点和结束位置都进行默认设置
	public static void quickSort(int[] arr) {
		quick(arr, 0, arr.length -1); //默认以第一个数作为基准值,结束位置则是最后一个数
	}	
	//low:起始点 , high :结束位置
	private static void quick(int[] a, int low, int high) {
		int left = low;    //左边起始位置
		int right = high;  //右边起始位置
		int key = a[low];  //以low来作为参照值的下标,即基准值
		
		//从两端分别进行扫描,left = right时 则全部比较完成
		while(left < right) {
			//从右边开始扫描,未找到比基准值小的就递减
			while(left < right && a[right] >= key) right--;
			//找到小的,和左边交换
			if(a[right] < key) swap(a, right, left);
			
			//从左边开始扫描,未找到比基准值大的就递增
			while(left < right && a[left] <= key) left++;
			//找到大的,和右边交换
			if(a[left] > key)  swap(a, left, right);
		}
		//循环结束,分成左右两个序列,左边均小于右边,此时位置下标分布:  low----left=基准值=right----high
		//再次使用递归对左右序列进行快速排序,直到分成一个元素一个序列,即比较完成!
		if(left > low) quick(a, low, left - 1); //处理左序列
		if(right < high) quick(a, right + 1, high);//处理右序列
	}
	//给定数组,交换指定下标的值
	private static void swap(int[] arr, int a, int b) {
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
	}


快排代码解析:
       快排的思想是“分治法”,每完成一次排序都会分成左右序列 ,左边序列的值均小于右边序列,然后再对左、右序列再次进行快速排序,一直分到左边等于右边,这时候就意味着元素已经全部排序完成了,这个过程可以交给递归来完成,后面会说到。
首先,需要指定要排序的起始点和结束位置,一般默认是0和数组长度-1,还需要为序列指定一个基准值,用于和序列的值进行比较。基准值的作用就是在每次循环之后,把序列分成两段,左边所有数值均小于右边,这是核心。
代码和图示:
	//打印每次交换的序列以及循环结束后分割一次。次要代码就不贴上来了
			if(a[right] < key) {
				swap(a, right, left);
				System.out.println("右边" + Arrays.toString(a) + "left:" + left + " , right:" + right+ ",基准值:" +key);
			}		
			//从左边开始扫描
			while(left < right && a[left] <= key) left++;
			//找到大的,和右边交换
			if(a[left] > key) {
				swap(a, left, right);
				System.out.println("左边" + Arrays.toString(a)+ "left:" + left + " , right:" + right + ",基准值:" +key);
			}
		}
		System.out.println("=========循环结束==========");


[排序算法]:Java实现冒泡排序和快速排序_第4张图片

通过运行的执行结果可以很直观看出左右两端通过基准值来调换位置,在循环结束后,基准值的左边均小于右边。而执行结果中会发现有多次连续的循环结束,那是因为已经比较完成,但是还需要对分好的左右序列再次递归使用快速排序。




     
这段时间看了许多经典排序算法,冒泡排序算是排序算法中最容易理解的,下面给上Java实现冒泡算法例子和代码实现过程解析。

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