直接插入排序、二分插入排序、二路插入排序、希尔排序
插入排序抽象类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
本人所学有限,不足之处,请大家及时指出,谢谢