插入排序

直接插入排序、二分插入排序、二路插入排序、希尔排序


插入排序抽象类AbstractSort

package org.evon.test;

public abstract class AbstractSort {
	// 只考虑升序排列的情况
	public abstract void sort(int[] iArr, boolean isRec);
	
	public void print(int[] iArr) {
		print(iArr, 0);
	}
	
	public void print(int[] iArr, int startIndex) {
		if (iArr == null || iArr.length == 0) {
			System.out.println("待输出的数组为空!!!");
		} else {
			System.out.print("输出的数组为: ");
			for (int i = startIndex ; i < iArr.length; i++) {
				System.out.print(iArr[i] + " ");
			}
			System.out.println();
		}
	}
}


直接插入排序:

package org.evon.test;

public class StraightInsertSort extends AbstractSort {

	@Override
	public void sort(int[] iArr, boolean isRec) {
		// {0(哨兵), 5, 8, 1, 3, 4, 12, 7, 9}
		// 插入排序,输入数组的第一个元素为哨兵
		// 输入数组的第二个元素看成是一个有序序列
		// 排序从第三个元素开始
		for (int i = 2; i < iArr.length; i++) {
			iArr[0] = iArr[i];// 待排序元素标记为哨兵
			
			if (iArr[0] >= iArr[i-1]) {
				// 待排序元素大于有序序列的最后一个元素,本身是已排好序的,不作处理
				if (isRec) {// 记录一次排序结果
					print(iArr, 1);
				}
				continue;
			}
			
			int j = i-1;
			// 找到待插入的前一个位置
			while (j > 0 && iArr[0] < iArr[j])  {
				iArr[j+1] = iArr[j];// 待排序元素未找到插入位置,元素后移
				j--;
			}
			
			// 待排序元素找到插入位置,直接插入
			iArr[j+1] = iArr[0];
			
			if (isRec) {// 记录一次排序结果
				print(iArr, 1);
			}
		}
	}
}


二分插入排序:

package org.evon.test;

public class BinaryInsertSort extends AbstractSort {

	@Override
	public void sort(int[] iArr, boolean isRec) {
		// {0(哨兵), 5, 8, 1, 3, 4, 12, 7, 9}
		// 插入排序,输入数组的第一个元素为哨兵
		// 输入数组的第二个元素看成是一个有序序列
		// 排序从第三个元素开始
		for (int i = 2; i < iArr.length; i++) {
			iArr[0] = iArr[i];// 待排序元素标记为哨兵

			if (iArr[0] >= iArr[i - 1]) {
				// 待排序元素大于有序序列的最后一个元素,本身是已排好序的,不作处理
				if (isRec) {// 记录一次排序结果
					print(iArr, 1);
				}
				continue;
			}

			int low = 1;
			int high = i - 1;
			// 找到待插入位置
			while (high >= low) {
				int middle = (low + high)/2;
				if (iArr[0] >= iArr[middle]) {
					low = middle +1;
				} else {
					high = middle -1;
				} 
			}

			// 移动待插入位置及之后的元素
			for (int j = i-1; j >= low; j--) {
				iArr[j+1] = iArr[j];
			}
			
			// 待排序元素找到插入位置,直接插入
			iArr[low] = iArr[0];

			if (isRec) {// 记录一次排序结果
				print(iArr, 1);
			}
		}
	}

}


二路插入排序

package org.evon.test;

public class TwoLoadInsertSort extends AbstractSort {

	@Override
	public void sort(int[] iArr, boolean isRec) {
		// 用于辅助排序的数组
		int iCount = iArr.length;
		int tempLen = iCount -1;
		int[] temp = new int[tempLen];
		
		// 待排序数组的第一个元素为哨兵
		// 将待排序数组的第二个元素初始化为辅助数组的第一个值,作为基准元素
		temp[0] = iArr[1];
		
		int first = 0;// 辅助数组中最小元素的位置
		int last = 0;// 辅助数组中最大元素的位置
		for (int i = 2; i < iCount; i++) {
			if (iArr[i] >= temp[last]) {// 大于最大直接放后面
				last++;
				temp[last] = iArr[i];
			} else if (iArr[i] < temp[first]) {// 小于最小直接放前面
				first = (first -1 + tempLen) %tempLen;
				temp[first] = iArr[i];
			} else {// 最小与最大之间(含等于最小)
				if (iArr[i] >= temp[0]) {// 大于等于基准元素放右边
					int j = last;
					while (j > 0 && iArr[i] < temp[j]) {
						temp[j+1] = temp[j];
						j--;
					}
					temp[j+1] = iArr[i];
					last++;
				} else {// 小于基准元素放左边
					int j = first;
					while(j < tempLen && iArr[i] >= temp[j]) {
						temp[(j-1+tempLen)%tempLen] = temp[j];
						j++;
					}
					temp[j-1] = iArr[i];
					first = (first-1+tempLen)%tempLen;
				}
			}
			if (isRec) {// 记录一次排序结果
				print(temp, 0);
			}
		}
		
		// 将排好序的辅助数组插入原数组
		for (int i = 0; i < tempLen; i++) {
			iArr[i+1] = temp[first%tempLen];
			first++;
		}
		
		if (isRec) {// 记录一次排序结果
			print(iArr, 1);
		}
	}

}


希尔排序:

package org.evon.test;

public class ShellSort extends AbstractSort {

	@Override
	public void sort(int[] iArr, boolean isRec) {
		int iLen = iArr.length -1;
		// 先保证部分有序,最后保证全部有序
		// 选取关键字n/2,n/4,...,1
		int step = iLen/2;
		while (step > 1) {
			sort(iArr, step, isRec);
			step = step/2;
		}
		
		sort(iArr, 1, isRec);

	}
	
	public void sort(int[] iArr, int step, boolean isRec) {
		// {0(哨兵), 5, 8, 1, 3, 4, 12, 7, 9}
		// 插入排序,输入数组的第一个元素为哨兵
		// 输入数组的第二个元素看成是一个有序序列
		// 排序从第step+1个元素开始
		for (int i = step+1; i < iArr.length; i++) {
			iArr[0] = iArr[i];// 待排序元素标记为哨兵

			if (iArr[0] >= iArr[i - step]) {
				// 待排序元素大于有序序列的最后一个元素,本身是已排好序的,不作处理
				if (isRec) {// 记录一次排序结果
					print(iArr, 1);
				}
				continue;
			}

			int j = i - step;
			// 找到待插入的前一个位置
			while (j > 0 && iArr[0] < iArr[j]) {
				iArr[j + step] = iArr[j];// 待排序元素未找到插入位置,元素后移
				j = j - step;
			}

			// 待排序元素找到插入位置,直接插入
			iArr[j + step] = iArr[0];

			if (isRec) {// 记录一次排序结果
				print(iArr, 1);
			}
		}
	}

}


二分插入排序是在直接插入排序的基础上,减少了待移动元素的查找次数,效率上没有太大的提高

二路插入排序是在折半插入排序的基础上,通过在辅助数组上操作,减少了元素的移动次数

希尔排序是先使数组内部部分有序,最后使得整个数组有序,选取合适的关键字,能提高排序效率,但这个关键字的选取没有特别好的办法


直接插入排序、二分插入排序、二路插入排序都是稳定的,希尔排序是不稳定的



本篇,主要是将直接插入排序、二分插入排序、二路插入排序、希尔排序用代码实现

若要对各种插入排序算法移动次数、插入次数分析,对上述代码适当修改后就能满足需求


对其他排序算法有兴趣的伙伴可以点击进入http://blog.csdn.net/hguisu/article/details/7776068


本人所学有限,不足之处,请大家及时指出,谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值