希尔排序(java)

网上代码很多的,找个易理解的学习。
基本思想:希尔排序把n个元素按一定的间隔分成几组,然后按组为单位进行插入排序。 。

将待排记录序列以一定的增量间隔h 分割成多个子序列,对每个子序列分别进行一趟直接插入排序, 然后逐步减小分组的步长h ,对于每一个步长h 下的各个子序列进行同样方法的排序,直到步长为1 时再进行一次整体插入排序。

因为不管记录序列多么庞大,关键字多么混乱,在先前较大的分组步长h下每个子序列的规模都不大,用直接插入排序效率都较高。 尽管在随后的步长h递减分组中子序列越来越大,但由于整个序列的有序性也越来越明显,则排序效率依然较高。这种改进抓住了直接插入排序的两点本质,大大提高了它的时间效率。

希尔算法的本质是缩小增量排序,是对直接插入排序算法的改进。

程序的增量序列常采用的表达式:
(1)h=3*h+1。(h=1,4,13,40,121,364...)
(2)h=2^k-1。(h=1,3,7,15,31,63...

例:待排序列:5,9,1,4,8,2,6,3,7

[img]http://dl.iteye.com/upload/attachment/0072/8562/f4a2cc2e-f17a-3597-9f70-966e6e6f2670.jpg[/img]

代码:
import java.util.Arrays; 
public class SortTest{

// 交换数组中的两个元素的位置
private void swap(int[] array, int i, int j) {
if (i != j) {//只有不是同一位置时才需交换
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}

/**
* 数组元素后移一位
* @param array 待移动的数组
* @param startIndex 从哪个开始移
* @param endIndex 到哪个元素止
*/
private void move(int[] array, int startIndex, int endIndex) {
for (int i = endIndex; i >= startIndex; i--) {
array[i + 1] = array[i];
}
}

/**
* 以指定的步长将数组元素后移,步长指定每个元素间的间隔
* @param array 待排序数组
* @param startIndex 从哪里开始移
* @param endIndex 到哪个元素止
* @param step 步长
*/
private void move(int[] array, int startIndex, int endIndex, int step) {
for (int i = endIndex; i >= startIndex; i -= step) {
array[i + step] = array[i];
}
}




/**
* 希尔排序算法的实现,对数组中指定的元素进行排序
* @param array 待排序的数组
*/
public void shelltSort(int[] array) {
//初始步长,实质为每轮的分组数
int step = initStep(array.length);

//第一层循环是对排序轮次进行循环。(step + 1) / 2 - 1 为下一轮步长值
for (; step >= 1; step = (step + 1) / 2 - 1) {
//对每轮里的每个分组进行循环
for (int groupIndex = 0; groupIndex < step; groupIndex++) {

//对每组进行直接插入排序
insertSort(array, groupIndex, step);
}
}
}


/**
* 直接插入排序实现
* @param array 待排序数组
* @param groupIndex 对每轮的哪一组进行排序
* @param step 步长
*/
private void insertSort(int[] array, int groupIndex, int step) {
int startIndex = groupIndex;//从哪里开始排序
int endIndex = startIndex;//排到哪里
/*
* 排到哪里需要计算得到,从开始排序元素开始,以step步长,可求得下元素是否在数组范围内,
* 如果在数组范围内,则继续循环,直到索引超现数组范围
*/
while ((endIndex + step) <= array.length-1) {
endIndex += step;
}


// i为每小组里的第二个元素开始
for (int i = groupIndex + step; i <= endIndex; i += step) {
for (int j = groupIndex; j < i; j += step) {
int insertedElem = array[i];
//从有序数组中最一个元素开始查找第一个大于待插入的元素
if (array[j]>insertedElem) {
//找到插入点后,从插入点开始向后所有元素后移step位
move(array, j, i - step, step);
array[j] = insertedElem;
break;
}
}
}
}


private static int initStep(int len) { //从最小步长1推导出最长初始步长值
/*
* 初始值设置为步长公式中的最小步长,从最小步长推导出最长初始步长值,即按照以下公式来推:
* 1,3,7,15,...,2^(k-1)-1,2^k-1
* 如果数组长度小于等于4时,步长为1,即长度小于等于4的数组不且分组,此时直接退化为直接插
* 入排序
*/
int step = 1;

//试探下一个步长是否满足条件,如果满足条件,则步长置为下一步长
while ((step + 1) * 2 - 1 < len - 1) {
step = (step + 1) * 2 - 1;
}

System.out.println("初始步长 : " + step);
return step;
}


/**
* 测试
* @param args
*/
public static void main(String[] args) {
int[] intArr = { 5, 9, 1, 4, 1, 2, 6, 3, 8, 0, 7 };
System.out.println("源 : " + Arrays.toString(intArr));
SortTest test=new SortTest();
//test.insertSort(intArr);
test.shelltSort(intArr);
System.out.println("升 : " + Arrays.toString(intArr));

}
}

源码下载:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值