TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
一、直接插入排序
我们把数组分为已排序和未排序两部分,把未排序的元素一次一个插入到已排序部分的合适位置上。
已排序部分逐渐增大,直到整个数组变成有序的。
下面通过一个例子来说明这个排序流程:待排序列: 49, 38 , 65 , 97, 76 , 13, 27 ,49 插入49: 49 插入38: 38, 49 插入65: 38, 49, 65 插入97: 38, 49, 65, 97 插入76: 38, 49, 65, 76, 97 插入13: 13, 38, 49, 65, 76, 97 插入27: 13, 27, 38, 49, 65, 76, 97 插入49: 13, 27, 38, 49, 49, 65, 76, 97
二、希尔排序
基本思想:希尔排序把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
- import java.util.Arrays;
- import java.util.Random;
- public class SortTest{
- /**
- * 交换数组中的两个元素的位置
- * @param array 待交换的数组
- * @param i 第一个元素
- * @param j 第二个元素
- */
- 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];
- }
- }
- //生成随机数组
- @SuppressWarnings("unchecked")
- public int[] randomArray() {
- Random r = new Random(System.currentTimeMillis());
- int[] a = new int[r.nextInt(30)];
- for (int i = 0; i < a.length; i++) {
- a[i] = r.nextInt(100);
- }
- return a;
- }
-
- /**
- * 插入排序算法的实现,对数组中指定的元素进行排序
- * @param array 待排序的数组
- * @param from 从哪里开始排序
- * @param end 排到哪里
- * @param c 比较器
- */
- public void insertSort(int[] array) { //升序排列
-
- /*
- * 第一层循环:对待插入(排序)的元素进行循环
- * 从待排序数组断的第二个元素开始循环,到最后一个元素(包括)止
- */
- for (int i =1; i < array.length; i++) {
- /*
- * 第二层循环:对有序数组进行循环,且从有序数组最第一个元素开始向后循环
- * 找到第一个大于待插入的元素
- * 有序数组初始元素只有一个,且为源数组的第一个元素,一个元素数组总是有序的
- */
- for (int j = 0; j < i; j++) {
- int insertedElem = array[i];//待插入到有序数组的元素
- //从有序数组中最一个元素开始查找第一个大于待插入的元素
- if (array[j]>insertedElem) {
- //找到插入点后,从插入点开始向后所有元素后移一位
- move(array, j, i - 1);
- //将待排序元素插入到有序数组中
- array[j] = insertedElem;
- break;
- }
- }
- }
- }
- /**
- * 希尔排序算法的实现,对数组中指定的元素进行排序
- * @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 步长
- * @param end 整个数组要排哪个元素止
- * @param c 比较器
- */
- 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));
-
-
- }
- }
复制代码 运行结果:
D:java>java SortTest
源 : [5, 9, 1, 4, 1, 2, 6, 3, 8, 0, 7]
初始步长 : 7
升 : [0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9]
源码下载:http://file.javaxxz.com/2014/12/7/000712968.zip |
|