希尔排序与堆排序

目录

希尔排序

堆排序


希尔排序

       待排序区间划分成若干个有跨度的子区间,然后进行插入排序,当最后跨度缩小到1的时候来一次完整的插入排序。

 第一次排序:length = 10; gap = a.length / 2 = 5; 将待排序的区间分成五个相同跨度的子区间。得到{49,13} {38,27} {65,49*} {97,55} {76,4}五个子区间,进行插入排序,得到排序后的区间为:{13,49} {27,38} {49*,65} {97,55} {4,76}

{13,27,49*,55,4,49,38,65,97,76}

第二次排序:gap = gap / 2 = 2; 将区间分为两个子区间。得到{13,49*,4,38,97} {27, 55, 49, 65, 76}两个子区间,插入排序后得到{4,13,38,49*,97} 和 {27,49,55,65,76}

{4,27,13,49,38,55,49*,65,97,76}

第三次排序:gap = gap / 2 = 1; 所以直接对{4,27,13,49,38,55,49*,65,97,76}进插入排序,就可以得到排序后的区间为{4,13,27,38,49,49*,55,65,76,97}

import java.util.Arrays;
import java.util.Scanner;

public class shellSort {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int[] a = new int[10];
        for (int i = 0; i < a.length; i++) {
            a[i] = scanner.nextInt();
        }
        shell(a);
        System.out.println(Arrays.toString(a));
    }

    public static void shell(int[] a) {
        for (int gap = a.length / 2; gap > 0 ; gap /= 2) {
            //没分一组就直接进行插入排序
            for (int i = gap; i < a.length; i++) {
                int j = i;//存放每一组中当前要处理的那个数据
                while (j - gap >= 0 && a[j - gap] >a[j]) {
                    //大的数据往后移动
                    int temp = a[j];
                    a[j] = a[j - gap];
                    a[j - gap] = temp;
                    j -= gap;//下一次继续从分组里的前一个位置开始
                }
            }

        }
    }
}

堆排序

初始数组为:int[] a = {57, 68, 59, 52, 72, 28, 96, 33, 24};

(1)用数组存储,第i个节点的叶子分别是2i+1和2i+2

(2)根的值小于(或者大于)左右子树,子树也需要满足这个定义

(3)堆看起来是一棵完全二叉树,存储却只需要用到数组即可

(4)开始建堆的时候数组顺序与二叉树层次遍历对应,逐步从非叶子节点到根调整

(5)堆排序以大根堆为例,每次堆顶和最后的那个叶子对调,保证大的放到目前堆的最后,然后把顶部元素调整好,最后就是升序排列

import java.util.Arrays;

//堆排序
public class heapSort {
    public static void main(String[] args) {
        int[] a = {57, 68, 59, 52, 72, 28, 96, 33, 24};//待排序数组的初始顺序
        heap(a);
        System.out.println(Arrays.toString(a));
    }

    public static void heap(int[] a) {
        //从倒数第一个非叶子结点开始调整,一直调整到根,让数组满足大根堆的递归定义
        for (int i = a.length / 2 - 1; i >= 0 ; i--) {//a.length / 2 - 1 是堆的最后一个非叶子结点
            //对数组的第i个元素当做根,调整的范围是目前无序的空间
            adjustHeap(a, i, a.length);//a.length 是目前无序的空间
        }
        for (int i = a.length - 1; i > 0 ; i--) {
            swap(a, 0, i);//交换数组里的根和无序堆中的最后一个数
            adjustHeap(a, 0, i);//每一轮都把前i个里最大的数放到最后,这样无序的范围都是0到i
        }
    }

    //swap方法完成数组中根和无序堆中最后一个数的交换
    private static void swap(int[] a, int root, int last) {//root为根  last为最后的数
        int temp = a[root];
        a[root] = a[last];
        a[last] = temp;
    }

    //左右子树挑大的进行交换,继续对左右子树进行调整,保证整个堆递归满足大根堆的定义
    private static void adjustHeap(int[] a, int i, int length) {
        int bak = a[i];//备份一下要调整的元素

        //开始的时候,从待调整的元素i的左子树开始 2 * i + 1,后面每次递归 2 * j + 1
        for (int j = 2 * i + 1; j < length; j = 2 * j + 1) {
            if (j + 1 < length && a[j + 1] > a[j]) {
                //j + 1为右子树,需要小于length并且让j永远都指向自己左右子树里大的那个
                j++;
            }
            if (bak < a[j]) {
                //如果bak的元素小于左右子树中大的那一个
                a[i] = a[j];//大的元素拷贝到i这个位置
                i = j;//下一次从以i为根的子树开始,让i等于这个j作为根
            }
            else break;//不小于说明位置已经调整好了
        }
        a[i] = bak;//一次性把最原始要调整的a[i]放到该放的位置
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_71646897/article/details/129487181