排序算法三:插入排序

插入排序

插入排序(Insert Sort)即从前向后,每取一个元素,将其放入到已经排列好的前面的队列之中,并保证加入该元素的队列仍然为有序的队列,直到取到最后一个元素并完整排序为止。
下面给出Java代码,
	/**
	 * 插入排序
	 * @param data
	 */
	private static void insertSort(int[] data) {
		
		if (null == data || data.length < 2) {
			return;
		}
		
		for (int i = 1; i < data.length; i++) {
			//如果算上当前元素前面的队列不是顺序的
			if (data[i-1]>data[i]) {
				//先将当前元素取出
				int temp = data[i];
				//要记住比较的元素位置
				int j = i;
				//从后向前检查元素,如果满足大于当前元素,那么依次向后移位
				for (; j>0 && data[j-1]>temp; j--) {
					data[j] = data[j-1];
				}
				//将当前元素放入合适的位置
				data[j] = temp;
			}
		}
		
	}
实际上,我们还有另外一种实现方式,它的每一轮外层循环的结果与插入排序的结果是一致的,但是其内部实现方式却是不一样的。我这里称其为伪插入排序,实际上它仍然是一种选择排序。其代码如下,
	/**
	 * 伪插入排序,实际上是一种选择排序
	 * @param data
	 */
	private static void fakeInsertSort(int[] data) {
		if (null == data || data.length < 2) {
			return;
		}
		
		for (int i = 1; i < data.length; i++) {
			//使前i+1个数有序
			for (int j = 0; j < i; j++) {
				//保证第i+1个位置一定是前i+1个元素的最大值
				if(data[j]>data[i]){
					swap(data, i, j);
				}			
			}
		}		
	}

	/**
	 * 数组内 i 坐标元素与 j 坐标元素互换
	 * @param data
	 * @param i
	 * @param j
	 */
	private static void swap(int[] data, int i, int j) {
		int temp = data[i];
		data[i] = data[j];
		data[j] = temp;	
	}
选择排序始终保证第k轮外层循环的第k个位置上一定是后面length-k+1个元素的最优值,而这里则始终保证第k轮外层循环的第k个位置上一定是前k个元素的最优值,二者恰好相对称。因为该实现方式没有“插入”的特点,因此我不认为它是一种插入算法,而应该算作选择排序的一种。
同样的,我们也可以给出冒泡形式的伪插入排序,代码如下,
/**
	 * 伪插入排序(冒泡排序)
	 * @param data
	 */
	private static void fakeInsertSort2(int[] data) {
		if (null == data || data.length < 2) {
			return;
		}
		
		for (int i = 1; i < data.length; i++) {
			//使前i+1个数有序
			for (int j = i; j > 0; j--) {
				if(data[j-1]>data[j]){
					swap(data, j - 1, j);
				}			
			}
		}
		
	}

	/**
	 * 数组内 i 坐标元素与 j 坐标元素互换
	 * @param data
	 * @param i
	 * @param j
	 */
	private static void swap(int[] data, int i, int j) {
		int temp = data[i];
		data[i] = data[j];
		data[j] = temp;	
	}

折半插入排序

因为我们的插入排序算法始终保证插入某一数据元素之前,该元素之前的数据是有序的,因此,可以通过折半查找的方式获得插入元素的终点。折半插入排序的Java代码如下:
	/**
	 * 折半插入排序
	 * @param data
	 */
	private static void binaryInsertionSort(int[] data) {
	    if (null == data || data.length < 2) {
            return;
        }
        
        for (int i = 1; i < data.length; i++) {
            //如果算上当前元素前面的队列不是顺序的
            if (data[i-1]>data[i]) {
                //先将当前元素取出
                int temp = data[i];
                //要记住比较的元素位置
                int j = i;
                //左端位置
                int left = 0;
                //右端位置
                int right = i-1;
                //中间位置
                int mid = (left + right)/2;
                //进行折半查找
                while (left<right) {
                    if (data[mid]<=temp) {
                        left = mid+1;
                    }else {
                        right = mid;
                    }
                    mid = (left + right)/2;
                }
                //依次向后移位
                for (; j>mid; j--) {
                    data[j] = data[j-1];
                }
                //将当前元素放入合适的位置
                data[j] = temp;
            }
        }
        
    }
	
	/**
     * 数组内 i 坐标元素与 j 坐标元素互换
     * @param data
     * @param i
     * @param j
     */
    private static void swap(int[] data, int i, int j) {
        int temp = data[i];
        data[i] = data[j];
        data[j] = temp; 
    }

折半插入排序相对于插入排序减少了插入判断的次数,但是数据交换次数并没有减少。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值