Java数据结构之 常见排序

一. 冒泡排序

思想:大的沉下去,小的升上来。

public class TestDemo1 {
	//冒泡排序优化
	public static void bubbleBetterSort(int[] array){
		int tmp = 0;//交换用于存值
		int count = 0;//用于判断数组是否有序
		for(int i = 0;i <array.length-1;i++){
			for(int j = 0;j < array.length-i-1;j++){
				if(array[j] > array[j+1]){
					tmp = array[j];
					array[j] = array[j+1];
					array[j+1] = tmp;
					count++;//如果交换过,count自增
				}
			}
			if(count == 0)//当前数组已经有序
				break;
		}
		System.out.println(Arrays.toString(array));
	}

这里写的是已经优化好的冒泡排序,如果数组 本身有序,就不需要进行那么多趟的比较。因此用count来记录第一趟里if执行的次数,一次都没有执行,说明数组本身有序。

二. 选择排序

思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

public static void selectSort(int[] array){
		int min=0;//找最小值的下标
		int tmp;//用于交换
		int j;
		for(int i = 0;i < array.length-1;i++){
			min = i;
			for(j = i+1;j < array.length;j++){//从i+1位置开始找最小值
				if(array[j]<array[min]){
					min = j;
				}
			}
			//将最小值放到本趟比较的最前面
			tmp = array[i];
			array[i] = array[min];
			array[min] = tmp;
		}
		System.out.println(Arrays.toString(array));
	}

三. 直接插入排序

思想:假设待排序的数据是数组A[1….n]。初始时,A[1]自成1个有序区,无序区为A[2….n]。在排序的过程中,依次将A[i] (i=2,3,….,n)从后往前插入到前面已排好序的子数组A[1,…,i-1]中的适当位置,当所有的A[i] 插入完毕,数组A中就包含了已排好序的输出序列。

public class TestDemo3 {
	public static void insrtSort(int[] array){
		int tmp = 0;
		int j;
		for(int i = 1;i < array.length;i++){//从i号位值开始
			tmp = array[i];
			for(j = i-1;j >= 0;j--){//找合适的位置进行插入
				if(array[j] > tmp){
					array[j+1] = array[j];
				}
				//在循环中找到了比tmp小的第一个元素跳出循环
				else{
					break;
				}
			}
			//把tmp赋值到最小值的后面
			array[j+1] = tmp;
		}
		System.out.println(Arrays.toString(array));
	}

 

四. 希尔排序(shell排序)

 

思想:是直接插入排序的一种更高效的版本,又称“缩小增量排序”。希尔排序是把记录按下标的一定增量分组,组内采用直接插入排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个数组恰被分成一组,算法便终止。

增量序列如何选取?

①互为质数  ②最后一个增量为一

一般情况下选取[5,3,1]作为增量序列

接下来以图来进行希尔排序

原始序列:

①将序列分为5组

如图,相同颜色的线为同一组。接下来组内进行直接插入排序。

排序后结果:

②:第一次排序后的序列分为三组

排序后:

③最后对这个序列整个进行直接插入排序

排序后结果:

接下来实现shell排序

public static void shell(int[] array,int gap){//gap表示分成几组
		int tmp = 0;//存放要交换的数据元素
		for(int i = gap;i < array.length;i++){//第一次要排序的元素是gap,不能写成i=i+gap
			tmp = array[i];
			int j = 0;
			for(j = i-gap;j >= 0;j -= gap){
				if(array[j] > tmp){
					array[j+gap] = array[j];
				}else{
					break;
				}
			}
			array[j+gap] = tmp;
		}
	}
	public static void shellSort(int[] array){
		int[] d = {5,3,1};//增量序列
		for(int i = 0;i < d.length;i++){
			shell(array,d[i]);//每一次分的组进行直接插入排序
		}
	}

五. 快速排序

思想:①在数组中找一个数作为基准(我们以零号数组下标作为第一个基准)

          ②比基准小的放在它的左边,比基准大的放在它的右边

          ③对左右区域分别重复第二步操作,直至左右区域都只剩下一个元素。

1.快速排序的递归实现

原始序列:

①:从high开始往前找,找到第一个比基准21小的,将high指向的4放在low指向的地方。执行后如图:

②:从low往后找,找到第一个比基准21大的,将low指向的32放在high指向的位置。执行后如图:

③:high继续往前找比基准小的,执行如图:

因为high和low相遇,此时将low(或high)位置的数用基准替代。执行后如图

现在发现基准21左边都比它小,右边都比它大。这样第一趟快速排序就结束了。

之后再分别对左右两边用与上述相同的方法排序,就会得到一个有序的序列了。

代码实现:

public static int partition(int[] array,int start,int end){//返回基准的下标
		int low = start;
		int high = end;
		int tmp = array[low];
		while(low < high){
			while(low < high&&array[high] >= tmp){//从后往前找比基准小的后退出循环
				--high;
			}
			if(low >= high){//判断low与high是否相遇
				break;
			}else{
				array[low] = array[high];
			}
			while(low < high&&array[low] <= tmp){//从前往后找比基准大的退出循环
				++low;
			}
			if(low >= high){
				break;
			}else{
				array[high] = array[low];
			}
		}
		array[low] = tmp;
		return low;
	}
	public static void quick(int[] array,int start,int end){
		int par = partition(array, start, end);
		if(par > start+1){//左半部分在进行快排
			quick(array, start, par-1);
		}
		if(par < end - 1){//右半部分进行快排
			quick(array, par+1, end);
		}
	}
	public static void quickSort(int[] array){
		int low = 0;
		int high = array.length - 1;
		quick(array, low, high);
	}

 

2.非递归实现

 

用栈来实现

public static int partition(int[] array,int start,int end){//返回基准的下标
		int low = start;
		int high = end;
		int tmp = array[low];
		while(low < high){
			while(low < high&&array[high] >= tmp){
				--high;
			}
			if(low >= high){
				break;
			}else{
				array[low] = array[high];
			}
			while(low < high&&array[low] <= tmp){
				++low;
			}
			if(low >= high){
				break;
			}else{
				array[high] = array[low];
			}
		}
		array[low] = tmp;
		return low;
	}
	public static void quickSort(int[] array){
		int[] stack = new int[array.length];
		int top = 0;
		int low = 0;
		int high = array.length-1;
		//入栈
		int par = partition(array,low,high);
		if(par > low+1){
			stack[top++] = low;
			stack[top++] = par-1;
		}
		if(par < high-1){
			stack[top++] = par+1;
			stack[top++] = high;
		}
		//出栈
		while(top > 0){
			high = stack[--top];
			low = stack[--top];
			
			par = partition(array, low, high);
			
			if(par >low+1){
				stack[top++] = low;
				stack[top++] = par-1;
			}
			if(par < high-1){
				stack[top++] = par+1;
				stack[top++] = high;
			}
		}
	}

 

以上排序的复杂度与稳定性:

 

 

 时间复杂度稳定性
冒泡排序O(n²)稳定
选择排序O(n²)不稳定
直接插入排序O(n²)(最好O(n))稳定
希尔排序O(n^1.3)最坏(O(n²))不稳定
快速排序O(nlogn)(最坏O(n²))不稳定

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值