堆排序java实现

堆和普通树的区别

堆并不能取代二叉搜索树,它们之间有相似之处也有一些不同。我们来看一下两者的主要差别:

节点的顺序。在二叉搜索树中,左子节点必须比父节点小,右子节点必须必比父节点大。但是在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。

内存占用。普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配额为是我内存。堆仅仅使用一个数据来村塾数组,且不使用指针。

平衡。二叉搜索树必须是“平衡”的情况下,其大部分操作的复杂度才能达到O(log n)。你可以按任意顺序位置插入/删除数据,或者使用 AVL 树或者红黑树,但是在堆中实际上不需要整棵树都是有序的。我们只需要满足对属性即可,所以在堆中平衡不是问题。因为堆中数据的组织方式可以保证O(log n) 的性能。

搜索。在二叉树中搜索会很快,但是在堆中搜索会很慢。在堆中搜索不是第一优先级,因为使用堆的目的是将最大(或者最小)的节点放在最前面,从而快速的进行相关插入、删除操作。

package com.myproject.demo.算法;

import java.util.Arrays;

/**
 * 堆是一个完全二叉树,初始建堆时间复杂度O(n)
 * 每次重建堆复杂度是O(log2^n)因为排序需要n次所以时间复杂度是O(nlog2^n)
 * 最优算法是从一个节点元素任意放置的二叉树开始,自底向上对每一个子树执行删除根节点时的Max-Heapify算法(这是对最大堆而言)使得当前子树成为一个二叉堆。具体而言,假设高度为h的子树均已完成二叉堆化,那么对于高度为h+1的子树,把其根节点沿着最大子节点的分枝做调整,最多需要h步完成二叉堆化。可以证明,这个算法的时间复杂度为O(n)
 * 时间复杂度为 T(n)<=O(n)+(n-1)*O(log2(n)),即等于第一次构造最大堆操作 加上 后面n-1次构造堆操作
 * 最后得到的T(n)=O(nlog2(n)).
 * java优先队列priorityQueen用的就是堆排序,因为他每次只要取一个元素复杂度O(log2^n),所以不使用快速排序O(nlogn)等其他的排序算法
 */

public class 堆排序 {
    public static void main(String args[]) {
        int[] a = new int[]{16, 25, 34, 27, 30, 5, 7, 4, 41, 55};
        堆排序.heapSort(a);
        System.out.println(Arrays.toString(a));
    }

    static int parent(int i) {
        return (i - 1) / 2;
    }

    static int left(int i) {
        return 2 * i + 1;
    }

    static int right(int i) {
        return 2 * i + 2;
    }

    static void maxHeapfy(int[] a, int i, int heapSize) { //数组a,第i个结点,heapSize是数组种实际要排序的元素的长度
        int left = left(i); //有的时候能够递归到叶子结点,叶子结点无后继,下面两个if都注意到了这一点
        int right = right(i);
        int largest = i;
        if (left < heapSize && a[left] > a[largest]) { //
            largest = left;
        }
        if (right < heapSize && a[right] > a[largest]) {
            largest = right;
        }
        if (largest != i) { //把最大值给父结点
            a[largest] = a[largest] ^ a[i];
            a[i] = a[largest] ^ a[i];
            a[largest] = a[largest] ^ a[i];
            maxHeapfy(a, largest, heapSize); //发生交换之后还要保证大根堆性质
        }
    }

    static void buildMaxHeap(int[] a, int heapSize) {
        for (int i = (heapSize - 2) / 2; i >= 0; i--) {
            maxHeapfy(a, i, heapSize);
        }
    }

    static void heapSort(int[] a) {
        int len = a.length;
        buildMaxHeap(a, len); //初始建堆
        a[len - 1] = a[0] ^ a[len - 1]; //交换
        a[0] = a[0] ^ a[a.length - 1];
        a[len - 1] = a[0] ^ a[len - 1];
        for (int i = 1; i < len - 1; i++) { //初始建堆之后还要排a.length-2次
            maxHeapfy(a, 0, len - i);
            a[len - 1 - i] = a[0] ^ a[len - 1 - i]; //交换
            a[0] = a[0] ^ a[len - 1 - i];
            a[len - 1 - i] = a[0] ^ a[len - 1 - i];
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值