排序算法(三):直接插入排序算法及其优化分析

8 篇文章 0 订阅

目录

1.直接插入排序:

2.算法优化分析:

3.时间复杂度分析:

4.空间复杂度分析:


1.直接插入排序:

插入排序:就是将一个元素插入到一个排好序的有序数组中。具体怎么理解呢?

对于一个包含N个数组的元素,他会从 [0,1] 区间开始插入排序,即将 1 插入到数组 {2} 的合适位置;接着从 [0,2] 区间开始排序,即将 4 插入到数组 {1,2}的合适位置。依次类推,总共执行N-1轮。

注意:将待排序元素插入到数组的合适位置时,其后的数组元素需要一次后移一位。

原始数组   2     4   3   5

一轮排序   1   2   4   3   5

二轮排序   1   2   4     5

三轮排序   1   2   3   4   5

四轮排序   1   2   3   4   5

public class InsertSort {
	
	public static void insertSort(int[] arr) {
		
		//正常情况下,插入排序需要N-1轮的循环遍历
		for(int i=0 ; i<arr.length-1 ; i++) {
			//判断当前元素是否大于前面有序数组的最后一个元素
			if(arr[i] > arr[i+1]) {
				
				int temp = arr[i+1];      //将待排序元素存入临时变量
				int k = i+1;              //将待排序元素的索引赋值给变量k    
				//在括号中为true时,while才会执行循环
				while(k>0 && arr[k-1]>temp) {
					
					arr[k] = arr[k-1];    //将数组中满足条件的元素后移一位
					
					k--;                  //维护变量,即继续对有序数组前面的元素进行遍历
				}
				arr[k] = temp;            //将临时变量中的待排序元素放到数组的合适位置
			}
		}
	}	
}

2.算法优化分析:

插入排序需要不断将一个元素插入到有序数组的合适位置,正常情况下需要从一端逐个比较,直到满足条件为止。最坏的情况下需要与有序数组中的每个元素都比较一下,因此在查找有序数组合适位置时可以使用二分查找算法进行优化。

public class InsertSort_Opt {
	/**
	 * 在[left,right]的数组区间中寻找元素high的合适位置,以升序为例
	 * @param arr
	 * @param start
	 * @param end
	 * @param high
	 * @return 返回一个插入位置的索引值
	 */
	public static int binarySelect(int[] arr,int start,int end,int high) {
		
		//定义二分查找的区间位置变量,以及中间位置变量
		int left = start;
		int right = end;
		
		//设定递归算法的结束标志:数组最后一轮区间容量为1.left=right
		if(left >= right) {
			return (high>=arr[left]) ? left+1:left;
		}else {
			//给定二分查找的中间位置
			int middleIndex = (left+right)/2;
			
			if(high == arr[middleIndex]) {
				return middleIndex;
			}else if(high > arr[middleIndex]) {
				left = middleIndex+1;
				return binarySelect(arr,left,right,high);    //递归调用二分查找算法
			}else {
				right = middleIndex-1;
				return binarySelect(arr,left,right,high);
			}
		}
	}
	
	public static void insertSort(int[] arr) {
		
		for(int i=0 ; i<arr.length-1 ; i++) {
			//比较i+1位置的元素与升序的有序区最后一个元素的大小
			if(arr[i] > arr[i+1]) {
				
				int temp = arr[i+1];
				int k = i+1;             //无序位置的索引
				int index = binarySelect(arr,0,i,arr[i+1]);   //待排序元素的插入位置
				
				while(k-1 >= index) {    //k-1为有序位置的索引
					arr[k] = arr[k-1];   //将插入位置及其后面的数组元素依次后移一位
					k--;
				}
				arr[index] = temp;
			}
		}
	}
}

3.时间复杂度分析:

3.1优化前:

对于元素个数为N的数组:

1.第一轮从第二个元素开始,与前面的有序数组元素依次比较,需要比较 1 次,之后插入到数组的合适位置,其后元素依次后移一位,同时维护待排序元素的索引值(+1);

2.第二轮从第三个元素开始,与前面的有序数组元素依次比较,需要比较 2 次,之后插入到数组的合适位置,其后元素依次后移一位,同时维护待排序元素的索引值(+1);

......

3.第N-1轮从第N个元素开始,与前面的有序数组元素依次比较,需要比较 N-1 次,之后插入到数组的合适位置,其后元素依次后移一位,同时维护待排序元素的索引值(+1);

根据等差数列的求和公式:Sn = (a1+an)*(N-1)/2。得到插入排序最坏的时间复杂度为O(N^2)

3.2优化后:

对于N个元素的数组而言,逐个对比数组元素寻找合适位置的时间复杂度最坏为O(N),而使用二分查找算法寻找合适位置的时间复杂度最坏为O(log(N))。因此,时间复杂度较优化前有很大的性能提升。

4.空间复杂度分析:

算法优化前后,都需要个位数以内的临时变量,因此空间复杂度为O(1)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值