排序算法-插入排序


 插入排序简单来说 就是将一个数据插入到已经到排好的序列中,但要求插入后仍然有序。这种方法一般适用少量数据的。

一、主要的插入排序

            直接插入排序 , 二分插入排序 , 链表插入排序,希尔排序, 是属于稳定排序的一种。

二、直接插入排序:

 把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,将它插入到有序表中的适当位置,使之成为新的有序表,重复n-1次可完成排序过程。

(一)简单方法
首先在当前有序区R[1..i-1]中查找R[i]的正确插入位置k(1≤k≤i-1);然后将R[k..i-1]中的记录均后移一个位置,腾出k位置上的空间插入R[i]。
注意:若R[i]的关键字大于等于R[1..i-1]中所有记录的关键字,则R[i]就是插入原位置。
     (二)改进的方法
一种查找比较操作和记录移动操作交替地进行的方法。具体做法:
将待插入记录R[i]的关键字从右向左依次与有序区中记录R[j](j=i-1,i-2,…,1)的关键字进行比较:
① 若R[j]的关键字大于R[i]的关键字,则将R[j]后移一个位置;
②若R[j]的关键字小于或等于R[i]的关键字,则查找过程结束,j+1即为R[i]的插入位置。
关键字比R[i]的关键字大的记录均已后移,所以j+1的位置已经腾空,只要将R[i]直接插入此位置即可完成一趟直接插入排序。
(三)哨兵的作用
算法中引进的附加记录R[0]称监视哨或哨兵(Sentinel)。
哨兵有两个作用:
① 进人查找(插入位置)循环之前,它保存了R[i]的副本,使不致于因记录后移而丢失R[i]的内容;
② 它的主要作用是:在查找循环中"监视"下标变量j是否越界。一旦越界(即j=0),因为R[0].key和自己比较,循环判定条件不成立使得查找循环结束,从而避免了在该循环内的每一次均要检测j是否越界(即省略了循环判定条件"j>=1")。

图片示意:


备注此图片来自于百度图片

三、性能

直接插入排序属于稳定的排序,最坏时间复杂性为O(n^2),空间复杂度为O(1)。

四、算法:

不带哨兵:

public void directInsertSort(int[] a) {
		for (int i = 0; i < a.length ; i++) {
			int temp = a[i];
			int j = 0;
			for (j = i; j > 0 && temp < a[j - 1]; j--) {
				a[j] = a[j - 1];
			}
			a[j] = temp;
		}
	}

带哨兵的算法

public void directWithShao(int[] a) {
		
		int[] arr = new int[a.length + 1];
		for (int i = 0; i < a.length; i++) {
			arr[i+1] = a[i];
		}
		for (int i = 1; i < arr.length; i++) {
			arr[0] = arr[i];
			for (int j = i -1; arr[j] > arr[0]; j--) {
				arr[j + 1] = arr[j];
				arr[j] = arr[0];
			}
		
		}
	}

五、测试结果

package com.albertshao.algorith.study;

public class DirectInsertSort {

	public static void main(String[] args) {
		int[] a = { 46, 58, 15, 45, 90, 18, 10, 62 };
		DirectInsertSort dis = new DirectInsertSort();
		dis.directWithShao(a);
	}

	public void directInsertSort(int[] a) {
		for (int i = 0; i < a.length ; i++) {
			int temp = a[i];
			int j = 0;
			for (j = i; j > 0 && temp < a[j - 1]; j--) {
				a[j] = a[j - 1];
			}
			a[j] = temp;
			
			System.out.print("第" + (i+1) +"趟: ");
			for (int k = 0; k < a.length; k++) {
				System.out.print(a[k] + " ");
			}
			System.out.println();
		}
	}

	
	public void directWithShao(int[] a) {
		
		int[] arr = new int[a.length + 1];
		for (int i = 0; i < a.length; i++) {
			arr[i+1] = a[i];
		}
		
		for (int i = 1; i < arr.length; i++) {
			arr[0] = arr[i];
			for (int j = i -1; arr[j] > arr[0]; j--) {
				arr[j + 1] = arr[j];
				arr[j] = arr[0];
			}
			
			System.out.print("第" + (i) +"趟: 哨兵(" + arr[0]+") ");
			for (int k = 1; k < arr.length; k++) {
				System.out.print(arr[k] + " ");
			}
			System.out.println();
		}
	}
}

运行结果:

第1趟: 哨兵(46) 46 58 15 45 90 18 10 62 
第2趟: 哨兵(58) 46 58 15 45 90 18 10 62 
第3趟: 哨兵(15) 15 46 58 45 90 18 10 62 
第4趟: 哨兵(45) 15 45 46 58 90 18 10 62 
第5趟: 哨兵(90) 15 45 46 58 90 18 10 62 
第6趟: 哨兵(18) 15 18 45 46 58 90 10 62 
第7趟: 哨兵(10) 10 15 18 45 46 58 90 62 
第8趟: 哨兵(62) 10 15 18 45 46 58 62 90 

第1趟: 46 58 15 45 90 18 10 62 
第2趟: 46 58 15 45 90 18 10 62 
第3趟: 15 46 58 45 90 18 10 62 
第4趟: 15 45 46 58 90 18 10 62 
第5趟: 15 45 46 58 90 18 10 62 
第6趟: 15 18 45 46 58 90 10 62 
第7趟: 10 15 18 45 46 58 90 62 
第8趟: 10 15 18 45 46 58 62 90 















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值