深入理解插入排序(why二分插入排序中left就是待插入位置)

>> 插入排序


本编重点在最后: 为什么二分插入left总是指向待插入的位置?

插入排序的思路: 给定一个数组,将数组划分为,已排序和未排序两部分,默认第一个元素已排序,然后一次遍历未排序数列,找到每个元素在已排序数列中的位置,移动元素,并插入。
平均时间复杂度: O(n^2)
最好情况: O(n)
最坏情况: O(n^2)
空间复杂度: O(1)
稳定性: 稳定 排序前相等的两个数,排序后位置不变


:)直接插入排序

代码如下:

import java.util.*;

/*
 *	插入排序---直接插入排序
 * */
public class InsertSort{
	private static Random rand = new Random();
	public static void insertSort(int[] value,int length){
		int temp;
		for(int i=1;i<length;i++){
			temp=value[i];
			int j=i-1;
			while(j>=0&&value[j]>temp){
				value[j+1]=value[j];
				j--;
			}
			//到这里的时候,要么是j小于0,要么value[j]小于了temp,所以直接
			//将value[j+1]z赋值为temp。
			value[j+1]=temp;
		}
	}
	public static void main(String[] args){
		int[] s = new int[100];
		for(int i = 0;i<s.length;i++){
			s[i]=Math.abs(rand.nextInt()%1000);
		}
		System.out.println(Arrays.toString(s));
		System.out.println("排序中...");
		insertSort(s,s.length);
		System.out.println(Arrays.toString(s));
	}
}

在寻找插入位置的过程中,如果遇到大于待插入的数,就直接向后移动,直到遇到小于它的数,这时候 j 指向的数的值就是第一个小于它的数的下标, 所以最后使用了 value[ j + 1 ]=temp。

:)二分插入排序

代码如下:

import java.util.*;
/*
 *	插入排序----二分法插入排序
 * */
public class InsertSort2{
	public static void insertSort2(int[] value,int length){
		for(int i=1;i<length;i++){
			int left = 0;
			int right = i-1;
			int temp = value[i];
			//这里必须为<=,因为,如果没有等于,那么i=1的时候,循环就已经结束了。
			//循环结束之后,left是要插入的位置,right是要插入位置的前一个位置。
			//这所以会出现,left是要插入的位置,right是要插入的前一个位置,是因为,left代表的待插入数字中的高位,right是低位。
			while(left<=right){
				int mid = (left+right)/2;
				if(value[mid]>temp)
					right=mid-1;
				else 
					left=mid+1;
			}
			//找打下标之后,将数字往后移,并且这个循环必须从最后一个数开始移动,避免覆盖掉前面的数字。
			for(int j=i-1;j>=left;j--){
				value[j+1]=value[j];
			}
			//将值插入相应的位置。
			value[left]=temp;
		}
	}
	public static void main(String[] args){
		Random rand = new Random();
		int[] s = new int[100];
		for(int i=0;i<s.length;i++){
			s[i]=Math.abs(rand.nextInt()%100);
		}
		System.out.println(Arrays.toString(s));
		System.out.println("排序中...");
		insertSort2(s,s.length);
		System.out.println(Arrays.toString(s));
	}
}

二分插入排序与直接插入排序的区别就在: 如何寻找待插入位置。

重点在为什么while循环之后left是待插入的位置

  • 根据我们在while循环体中的写法,我们可以保证left之前的数一定小于待插入的数,而right之后的数一定大于待插入的数。
  • 并且,不管什么情况,最后,left和right都会指向同一个下标
  • 以上两点连接起来就可以解决问题当最后left和right指向同一个下标,那么它们共同指向的这个数,与待插元素的大小就决定了,插入的位置。如果待插元素大于或等于这个数,那么就应该插入到这个数前面,这时根据代码可知left=mid+1;如果小于这个数,就应该插入到这个数后面,这时right=mid-1。
    但是不管如何,最后left和right一定满足这样一个关系:
    left = right+1
    所以,如果按照大小顺序排列的话,right将在left左边,这与为它们的命名产生矛盾。
    这时,再根据第一点来分析,left左边的数一定小于left指向的这个数,right右边的数一定大于这个数。但最后的left和right的排序却是
    right left
    我们将目光聚焦到left,分析可以,left左边的数一定小于待插元素,而此时,right在它左边,right右边的数一定大于待插元素,那么可以得出:
    left最后所指向的数,是待插位置右边那个数,如:7 插入 3 ,9之间,那么left就指向9。
    同理可以得出:
    right最后所指向的数,是待插位置左边那个数,如:7 插入 3 ,9之间,那么right就指向3。
    这就是为什么left所指向的是待插入的位置,因为最后大于待插入的数才会向后移动。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值