排序算法——插入排序(直接插入,二分插入,希尔)

直接插入排序

思想:

第一个数默认有序。从第二个数开始,从后往前扫描。若取出数 < 当前数,则指针不断前移,直到取出数 >= 当前数时,把取出数插入到当前位置。

public static int[] insertSort(int[] arr){
	int pre,cur;   //pre:当前数指针,cur: 取出数
	for(int i = 1; i < arr.length; i++){   //从第二个数(索引为1)开始遍历
		pre = i - 1;
		cur = arr[i];
		while(pre >= 0 && arr[pre] > cur){ //防止索引越界,并当当前数 > 取出数时
			arr[pre+1] = arr[pre];
			--pre;
		}
		arr[pre+1] = cur;
	}
	return arr;
}

以下过程具体说明了两个数是怎么实现有序的

        pre
index:   1    2
data:	 5    2          cur = 2

->
arr[pre+1] = arr[pre]

        pre
index:   1    2
data:	 5    5          cur = 2

->
--pre

      pre
index: 0    1    2
data:	    5    5          cur = 2

->
arr[pre+1] = cur;

      pre
index: 0    1    2
data:	    2    5          cur = 2

复杂度分析:

最好的情况是序列已完全有序,则程序只for循环一次,while循环不执行,复杂度为O(n);最坏的情况是序列完全倒序,for循环扫描一轮,while循环也从后往前全部两两交换了一轮,复杂度为O(n^2); 平均复杂度为O(n^2);

稳定性:

该排序算法不改变相同元素的相对位置,所以是稳定的。


直接插入第二种写法

public void insert(int[] arr){
	for(int i = 1; i < arr.length; i++){
		for(int j = i; j > 0; j--){
			if(arr[j] < arr[j-1])
				swap(arr,j,j-1);
		}
	}
}

二分插入排序

思想:

利用二分查找,能够更快的定位元素,不用一个个向前移动寻找了

public void insert(int[] arr){
	for(int i = 1; i < arr.length; i++){
		int key = arr[i];
		int low = BinarySearch(arr,key,0,i-1);
		
		for(int j = i-1; j >= low; j--)
			arr[j+1] = arr[j];
		arr[low] = key;
	}
}

public int BinarySearch(int[] arr, int key, int low, int high){
	while(low <= high){
		int mid = ((high-low) >> 1) + low;
		if(key < arr[mid])
			high = mid - 1;
		else
			low = mid + 1;
	}
	return low;
}

希尔排序(本质是直接插入排序)

思想:

使用了一个增量,初始值为一般设为Math.floor(arr.length / 2);该增量把序列划分为几个gap,对跨gap的数进行直接插入排序,而后gap为 Math.floor(gap / 2),直到最后一轮 gap=1

public static int[] insertSort(int[] arr){
	for(int gap = (int)Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)){   //设置增量,划分gap
		for(int i = gap; i < arr.length; i++){    //对每个gap的数进行直接插入排序
			int j = i;
			int cur = arr[j];     //arr[j]是相对位置在后面的数,arr[j-gap]是相对位置在前面的数
			while(j-gap >= 0 && arr[j-gap] > cur){
				arr[j] = arr[j-gap];
				j = j - gap;
			}
			arr[j] = cur;
		}
	}
	return arr;
}

复杂度分析:

外层for循环不是在做循环。内层for循环从初始gap值处开始遍历数组,复杂度情况与直接插入排序一致,若序列已有序,复杂度为O(n);若完全倒序,复杂度为O(n^2);平均复杂度问题未解决,尚为数学界难题。

稳定性:

该排序算法改变相同元素的相对位置,所以是不稳定的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值