【最易懂的代码】Java冒泡排序、选择排序、插入排序、归并排序

一、冒泡排序:

两个相邻元素之间,两两进行相互比较,若前一个数比后一个数大,则交换位置。每经过一次循环,则都把较大的一个数放在后面。代码实现:

/**Java排序之 冒泡排序*/
public class BubbleSort {
	public void bubbleSort(int [] arr) {
		//如果arr没有元素或只有一个元素
		if(arr == null || arr.length < 2) {
			return;
		}
		//0~n-1 0~n-2  0~n-3 0~n-4 两两比较每次都选出最大的数据
		for(int end = arr.length - 1; end > 0; end --)
			for(int i = 0 ; i < end ; i++){
                if(arr[i] > arr[i + 1])
                    swap(arr,i,i+1);
            }            
	}
	//交换位置方法
	private void swap(int[] arr, int j, int i) {
		int temp = arr[j];
		arr[j] = arr[i];
		arr[i] = temp;
	}	
}

冒泡排序时间复杂度为:O(n²)  ,额外时间复杂度 O(1)

第一次for循环(N) 第二次(N-1) 第三次(N-2)...是等差数列 An² + Bn +c (只要高阶项,不要低阶项,也不要高阶项的系数)则为n²。

 

 

二、选择排序:(记录最小值的下标)

如:一个数组中,arr[0]~arr[n-1]范围内找一个最小的数放在arr[0]位置,arr[1]~arr[n-1]范围内找一个最小的数再放arr[1]位置,arr[2]~arr[n-1]范围内找一个最小的数再放arr[2]位置......备注:n为arr.length数组长度。看代码:

/**Java排序之选择排序*/
public class SelectionSort {
	public void selectionSort(int[] arr) {
		if (arr == null || arr.length < 2) {
			return;
		}
		// 0~n-1  1~n-1  2~n-1  3~n-1 每次记录最小的下标与初始下标交换值
		for (int i = 0; i < arr.length - 1; i++) {
			//假设每次循环开始,arr[i]最小
			int minIndex = i;
			//最开始状态arr[0]和arr[0+1]比较,arr[1]和arr[1+1]比较
			for (int j = i + 1; j < arr.length; j++) {
				minIndex = arr[j] < arr[minIndex] ? j : minIndex;
			}
			if(minIndex != i) {
				swap(arr,i,minIndex);
			}
		}
	}
	
	private void swap(int[] arr, int i, int minIndex) {
		int temp = arr[i];
		arr[i] = arr[minIndex];
		arr[minIndex] = temp;
	}
}

选择排序复杂度也是O(n²),无法实现稳定性

 

三、插入排序

对于前两个冒泡排序和选择排序,基本不会出现在生产环境中,适合入门教学,而接下来讲的插入排序,则在生产环境中比较常见,举个例子介绍一下什么是插入排序:

我们应该都玩过扑克牌,从A-K,我们抓牌后都会把牌按从小到大排序。现在,我手中的牌都是按顺序排好的,我现在摸一张牌,比如是8,那么我就应该把它放到7和9之间。这就是插入排序,映射在JAVA代码中就是将8这张牌从大到小进行比较,进而进行移动,则当移动到8位置,把牌放入。此时停!!!不需要再往7~1之间比较遍历,因为其他顺序都是排好的。

  /**插入排序*/
public class InsertSort {
	public void insertSort(int [] arr) {
		if(arr == null || arr.length <2)
		    return ;

		//0~0已经"排好序",从0~1开始比,即下标为[1]开始和前面数比
		for(int i = 1; i < arr.length ; i++) {  //最终执行到[arr.length-1]即arr最后一个元素
			/**
			 * j为i前面的数,初始是i前面一个数
			 * 需要满足才发生插入:
			 * 1、j>=0
			 * 2、arr[j] (前面的数) > arr[j+1] (后面的数)
			 */
			for(int j = i -1 ; j >= 0 && arr[j] > arr[j+1] ; j--) {
				swap(arr,j,j+1);
			}
		}
	}
	private void swap(int[] arr, int i, int j) {
		arr[i] = arr[i] ^ arr[j];
		arr[j] = arr[i] ^ arr[j];
		arr[i] = arr[i] ^ arr[j];
	}
}

冒泡排序和选择排序都与数据的状况没有关系,而插入排序与数据状况有关系。

如数据为1、2、3、4、5,则从头到尾无需交换位置,只需要遍历经过5个元素即可,时间复杂度为O(n)。

如数据为5、4、3、2、1,则从头到尾都需交换位置,时间复杂度为O(n²)。

但时间复杂度都是考虑最坏情况,所以选择排序的时间复杂度依然为O(n²)。

 

四、归并排序

基于递归实现+外排。

①首先,把集合或数组递归分为左右两个子序列(即无序向量的递归分解),系统递并各个子序列为有序向量,左右部分排好序。

②准备一个辅助数组help,p1和p2分别指向L和mid+1位置,谁小谁被添加到help数组中,并移动index。

③整体排好序后,拷贝回原数组

public class MergeSort {
	public static void mergeSort(int[] arr) {
		if (arr == null || arr.length < 2)
		   return;
		mergeSort(arr, 0, arr.length - 1);
	}

	public static void mergeSort(int[] arr, int l, int r) {
		if (l == r)
             //该范围只有一个数,无需排序
		   return;
		int mid = l + ((r - l) >> 1);
		mergeSort(arr, l, mid);
		mergeSort(arr, mid + 1, r);
		merge(arr, l, mid, r);
	}

	public static void merge(int[] arr, int l, int m, int r) {
		int[] help = new int[r - l + 1];
		int i = 0;
		int p1 = l;
		int p2 = m + 1;
		while (p1 <= m && p2 <= r)
		  help[i++] = arr[p1] > arr[p2] ? arr[p2++] : arr[p1++];
		while (p1 <= m)
		  help[i++] = arr[p1++];
		while (p2 <= r)
		  help[i++] = arr[p2++];
		for (i = 0; i < help.length; i++)
		  arr[l + i] = help[i];
	}
}

O(N) = 2T(N/2)*(N)     a=2,b=2,d=1  由master公式 :

log(b,a) = d -> 复杂度为O(N^d * logN) 

时间复杂度O(N*logN),额外空间复杂度O(N)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值