[ 算法 ] -- 堆排序,Java实现

6 篇文章 0 订阅
6 篇文章 0 订阅

堆的基本概念:

堆是一棵所有元素按完全二叉树的顺序存储方式存储的完全二叉树。

堆的性质:

                  --堆中某个节点的值总不大于或不小于其父节点的值;

                  --堆总是一棵完全二叉树。

小根堆:每个节点的值小于等于左、右孩子的值(根节点最小的堆)

大根堆:每个节点的值大于等于左、右孩子的值(根节点最大的堆)

父节点 n ==> 左孩子:2*n+1、右孩子:2*n+2

孩子节点 n ==> 父节点:(n - 1)/2

时间复杂度:On * log 2n)

空间复杂度:O(1)

稳定性:不稳定

堆排序的具体实现步骤:

1. 将无序的序列构建成堆,根据要拍的升序降序选择建立大根堆还是小根堆(升序建立大根堆,降序建立小根堆);

1.1 按照完全二叉树的顺序存储方式,先将待排数组转换为完全二叉树

1.2 建立大根堆

从当前完全二叉树的最后一个子树开始调整,找孩子节点中的最大值与父节点进行交换,交换完成后往前走比较倒数第二棵子树,依次往前,直到每个子树的父节点大于等于孩子节点。

如下图先从父节点为67的子树开始,左孩子78大于父节点,将二者进行交换:

比较父节点为56的子树,右孩子89较大,将二者进行交换,得到以89为父节点的整个子树是大根堆:

比较以34为父节点的子树,其中左孩子91最大,将其与父节点34交换:

最后调整以45为父结点的子树,右孩子91最大,将其与45进行交换后可得到大根堆(如果交换后发现以45为父节点的子树孩子节点大于父节点,须对其进行调整,保证每个节点大于等于左右孩子节点):

2. 交换堆顶元素与末尾元素,将最大值换到数组末端;

3. 重新调整,使其仍为大根堆(小根堆),此时不包括末尾元素;

4. 循环2、3步骤,直到整个序列都有序。

代码实现:

import java.util.Arrays;

public class HeapSort {

    public static void main(String[] args) {
        int[] array = {45,56,34,67,89,91,12,78,23};
        System.out.println("排序之前:"+Arrays.toString(array));
        HeapSort(array);
        System.out.println("排序之后:"+Arrays.toString(array));
    }

    public static void HeapSort(int[] array){
        //向下(从下往上)调整建立大根堆
        //i为子节点,(array.length-2)/2为父节点
        for (int i = (array.length-2)/2; i >= 0 ; i--) {
            AdjustDown(array,i,array.length);
        }
        //交换堆顶和最后一个下标
        int end = array.length - 1;
        while (end > 0){
            int tmp = array[0];
            array[0] = array[end];
            array[end] = tmp;
            AdjustDown(array,0,end);
            end--;
        }
    }

    //向下调整,从每个子树的根节点开始调整,调整的长度为length
    private static void AdjustDown(int[] array, int root, int length) {
        int parent = root;
        int left = 2*parent+1;//左孩子节点
        int right = 2*parent+2;//右孩子节点
        int child;//孩子节点中的最大值
        while (left < length){
            if ( right < length && array[left] < array[right]){
                child = right;
            }else {
                child = left;
            }
            //孩子节点大于父节点,进行交换,然后
            if (array[child] > array[parent]){
                int tmp = array[child];
                array[child] = array[parent];
                array[parent] = tmp;
                parent = child;
                left = 2*parent +1;
                right = 2*parent+2;
            }else {
                break;
            }
        }
    }
}

运行结果:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值