直接插入排序

直接插入排序<详解>
这几天为了工作和毕业设计的事,折腾的,感觉挺累,而且很乱,好几天没有写博客了,有几天没有静下来做我喜欢做的事情了:写代码。今天给自己一点时间,让自己静一静,接着以前的路程,将排序法写下去。前面写了比较排序,冒泡排序,选择排序加上今天的直接插入排序,这四个排序都属于简单的排序,时间复杂度都是O(n²)。
不懂得直接插入排序的人应该打过牌,在揭牌的时候,我们会将5插入到3和6之间,后面揭到4就会好像无意识的插入到3和5之间,比如下面的几张牌:

@此时我们会将2放到3的左边,然后将4插入到3和5之间,这样就有序了。

@就以上面的简单的理牌为例,分析插入排序的过程:
第一轮:从下标为一的记录开始,就是5,此时先将5出列,并记录空缺的位置,再将5与之前的每一个元素进行比较,比较5>3,是正序,就不用移动,比较完毕,5回归到空缺的位置,进入下一轮;
第二轮:从下标为二的记录开始,就是4,此时先将4出列,并记录空缺的位置,再将4与之前的每一个元素进行比较,比较4<5,是反序,就将5后移,空缺位置变为之前5所在的位置,然后比较4>3正序,不用移动,比较完毕,将4置于新的空缺位置。
......

直接插入排序:将一个记录插入到已经排好序的有序表中,从而得到一个新的,记录增加1的有序表。

大学军训:
刚来大学时,大家都是从五湖四海过来,兴奋激动不已,军训第一天,都满怀期待来到操场集合,都想站前排展现一下下自己,于是乎一开始大家就先来先到,一个挨着一个站着,参差不齐,甚是难看,结果教官来了,看后有点生气,然后急中生智,就雷厉风行:“第二个,王小二,你要是比前面的同学矮点就站出来,王小二前面的同学,如果王小二站出来了,自己就看看,如果比王小二高就往后一步走(假设一个人刚好占据了一步的距离空间),结果王小二一看,比最前面的白大褂高一点就没有站出来了。然后,从王小二后面的每一位同学,依次看看,如果比前面的同学矮点就出列,出列同学前面的同学好好看看,如果比出列同学高的同学,自觉往后移动一步,然后出列的同学站到最后空缺的位置...”不到十分钟,一个由低到高的队形出来了,这个教官将直接插入排序法灵活地运用到了生活中,真是妙啊~ ~


编程世界与现实生活的结合,我相信直接插入排序法的精髓和灵魂不难理解了,那么看看代码是怎么实现的,下面就以上面的理牌说,说说真个理牌的过程,下面列出前两轮排序

@在第一轮中,5>3,5不用出列,直接进入下一轮。
@在第二轮中,4<5,4出列,当前空缺位置为int  vacancy = 2。
@比较5>4,5后移一位,vacancy = 1。
@比较3<4,不用移动,然后将出列的4放到空缺位置。


回到编程世界,菜鸟开始写代码:
看看核心的代码:
/**
	 * 直接插入排序的核心程序
	 * @param array
	 */
	public void insertSort(int... array) {
		int length = array.length;
		// 此循环从1开始,就是将0下标的元素当做一个参照
		for (int i = 1; i < length; i++) {
			if (array[i] < array[i - 1]) { // 将当前下标的值与参照元素比较,如果小于就进入里面
				int vacancy = i; // 用于记录比较过程中那个空缺出来的位置
				int sentry = array[i]; // 设置哨兵,将当前下标对应的值赋给哨兵
				// 这个循环很关键,从当前下标之前一个元素开始倒序遍历,比较结果如果比当前大的,就后移
				for (int j = i - 1; j >= 0 && array[j] > sentry; j--) {
					vacancy = j;
					array[j + 1] = array[j]; // 后移比当前元素大的元素
				}
				array[vacancy] = sentry; // 将哨兵,也就是当前下标对应的值置入空缺出来的位置
			}
		}
	}
@外部循环的开始条件是int i = 1,里面有个if(array[i] > array[i - 1]),也就是如果当前记录比前面的记录小的时候才出列,出列后用sentry = array[i],记录下这个记录,并用vacancy = i,记录下空缺位置。
for (int i = 1; i < length; i++) {
			if (array[i] < array[i - 1]) { // 将当前下标的值与参照元素比较,如果小于就进入里面
				int vacancy = i; // 用于记录比较过程中那个空缺出来的位置
				int sentry = array[i]; // 设置哨兵,将当前下标对应的值赋给哨兵
@如果出列了,注意内部循环的条件,是从当前记录的前一个开始的,然后倒序遍历,条件是如果遍历过程中有大于sentry的记录,就后移记录array[j + 1]  = array[j],然后将空缺位置变为j。
for (int j = i - 1; j >= 0 && array[j] > sentry; j--) {
					vacancy = j;
					array[j + 1] = array[j]; // 后移比当前元素大的元素
				}
@比较完毕之后,array[vacancy] = sentry,是将出列的位置放到空缺位置。
array[vacancy] = sentry; // 将哨兵,也就是当前下标对应的值置入空缺出来的位置


我想,这个过程已经将直接插入排序说的不能再往下说了,至少我已经不能说下去了,下面提供完整的代码:
/**
 * 直接插入排序算法
 * @author PingCX
 *
 */
public class InsertSort {

	public static void main(String[] args) {
		InsertSort insertSort = new InsertSort();
		int[] array = { 3, 5, 4, 2, 6};
		System.out.println(Arrays.toString(array));
		insertSort.insertSort(array);// 调用快速排序的方法
		System.out.println(Arrays.toString(array));// 打印排序后的数组元素
	}

	/**
	 * 直接插入排序的核心程序
	 * @param array
	 */
	public void insertSort(int... array) {
		int length = array.length;
		// 此循环从1开始,就是将0下标的元素当做一个参照
		for (int i = 1; i < length; i++) {
			if (array[i] < array[i - 1]) { // 将当前下标的值与参照元素比较,如果小于就进入里面
				int vacancy = i; // 用于记录比较过程中那个空缺出来的位置
				int sentry = array[i]; // 设置哨兵,将当前下标对应的值赋给哨兵
				// 这个循环很关键,从当前下标之前一个元素开始倒序遍历,比较结果如果比当前大的,就后移
				for (int j = i - 1; j >= 0 && array[j] > sentry; j--) {
					vacancy = j;
					array[j + 1] = array[j]; // 后移比当前元素大的元素
				}
				array[vacancy] = sentry; // 将哨兵,也就是当前下标对应的值置入空缺出来的位置
			}
		}
	}
}


下面是用于面向对象语言中可比较的任意类型的直接插入排序:
/**
 * 任何可以比较的类型的直接插入排序算法
 * 
 * @author PingCX
 * 
 */
public class InsertSortT {

	public static void main(String[] args) {
		InsertSortT insertSort = new InsertSortT();
		Integer[] array = {  3, 5, 4, 2, 6 };
		System.out.println(Arrays.toString(array));
		insertSort.insertSort(array);// 调用快速排序的方法
		System.out.println(Arrays.toString(array));// 打印排序后的数组元素
	}

	/**
	 * 直接插入排序的核心程序
	 * 
	 * @param array
	 */
	public <T extends Comparable<T>> void insertSort(T[] array) {
		int length = array.length;
		// 此循环从1开始,就是将0下标的元素当做一个参照
		for (int i = 1; i < length; i++) {
			if (array[i].compareTo(array[i - 1]) < 0) { // 将当前下标的值与参照元素比较,如果小于就进入里面
				T sentry = array[i]; // 设置哨兵,将当前下标对应的值赋给哨兵
				int vacancy = i; // 用于记录比较过程中那个空缺出来的位置
				// 这个循环很关键,从当前下标之前一个元素开始倒序遍历,比较结果如果比当前大的,就后移
				for (int j = i - 1; j >= 0 && array[j].compareTo(sentry) > 0; j--) {
					vacancy = j;
					array[j + 1] = array[j]; // 后移比当前元素大的元素
				}
				array[vacancy] = sentry; // 将哨兵,也就是当前下标对应的值置入空缺出来的位置
			}
		}
	}
}


尾声:
生活中不要循规蹈矩,特别是作为一名程序员,要想有所成就,就必须灵活变通,哪里有机会就往哪里插,把握机会,当然也要一步一个脚印,踏踏实实地走好每一步。
食得菜根,可做百事~





  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值