堆排序

  • 简介
堆是一种基于数的数据结构,这些数必须满足堆性质,即任一父节点都大(小)于或等于它的任一子节点。
常见的堆结构有二叉堆,二项堆和fibonacci堆。
  • 二叉堆
二叉堆是一棵完全二叉树。包括了小顶堆(最小堆)和大顶堆(最大堆)。

性质:
    对于大顶堆,树中的任一父节点的值始终大于或等于全部子节点的值。反之为小顶堆。
    堆的实现一般直接使用数组作为存储结构,而不必自己构建二叉树。

二叉堆的元素,使用数组来进行表示:
arr[i]的左右子节点分别为arr[2i+1]和arr[2i+2];
arr[i]的父节点为arr[floor((i-1)/2)]和arr[2i+2],floor():向下取整。

二叉堆的构建一般采用自下而上的方式。
  • 例子
 int[] arr = {0, 3, 1, 5, 6, 4, 2};
----------------------创建大顶堆----------------------
自下而上,自右向左: 
step1:将数组构造为二叉树,注意,并不是真的构建为二叉树,仅仅是将其看作一棵二叉树。
step2:从非叶子节点的最底层开始,检查子树是否符合二叉堆性质,即子树的父节点是否比子节点大。如果子节点比父节点大,则对调。

创建大顶堆的过程

  • 排序
step1:数组头元素(最大值)与末尾元素交换,将最大元素放置到数组末端
step2:将指针往前移使得已获得的最大值不参与接下来堆的创建

总结:就是不断的选堆顶放到数组的尾部。
  • 代码实现
//时间复杂度:O(nlogn)
public class HeapSort {
    public static void main(String[] args) {

        int[] arr = {0, 3, 1, 5, 6, 4, 2};

        heapSort(arr);
    }

    //堆排序
    public static void heapSort(int[] arr) {

        //创建大顶堆
        int n = 1;
        for (int i = arr.length / 2 - 1; i >= 0; i--) {

            createHeap(arr, i, arr.length);
            System.out.println("-------------第 "+(n++)+" 次对调----------------------");
            for (int ij : arr) {
                System.out.printf("%d\t", ij);
            }
            System.out.println();
        }
        System.out.println();
        for (int i : arr) {
            System.out.printf("%d\t", i);
        }
        //排序
        int temp = 0;
        for (int j = arr.length - 1; j > 0; j--) {
            //step1:交换堆顶元素与末尾元素交换,将最大元素放置到数组末端
            //step2:j--将指针往前移使得已获得的最大值不参与堆的创建
            temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            createHeap(arr, 0, j);
        }
        System.out.println();
        for (int i : arr) {
            System.out.printf("%d\t", i);
        }

    }

    //创建大顶堆
    public static void createHeap(int[] arr, int i, int len) {

        int temp = arr[i];
        //k = 2*i+1:k是i的左子节点
        for (int k = 2 * i + 1; k < len; k = k * 2 + 1) {
            //如果左右子节点读比父节点的值大,比较左右子节点,将k指向较大的那个节点
            if (k + 1 < len && arr[k] < arr[k + 1]) {  
                k++;   
            }
            if (arr[k] > temp) { //如果子节点大于父节点
                arr[i] = arr[k]; //把较大的值,赋给当前的节点
                i = k; //把 i 指向 k, 继续循环比较
            } else
                break;
        }
        arr[i] = temp; 
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值