堆排序java代码实现

133 阅读2分钟

堆排序使用了“堆”数据结构来进行信息管理,因此,首先需要介绍一个数据结构“堆”。

堆也叫二叉堆,是一个数组,可以被看作一个近似的完全二叉树,树上的每一个节点对应数组中的一个元素。除了最底层外,该树实2完全充满的,而且是从左向右填充。表示堆的对象A应有两个属性,A.data为数组,数组用于存储堆的数据,A.heapSize表示A.data[0,A.heapSize-1]中存放的是堆的有效元素。A.data的第一个元素为树的根节点。若下标从1开始,可以知道给定一个节点的下标i,该节点的父节点下标为i/2,该节点的左孩子下标为2i,右孩子下标为2i+1。但是往往在编写代码实现时,数组下标从0开始,此时,节点i的父节点下标为(i-1)/2,左孩子下标为2xi+1,右孩子下标为2x(i+1)

下图分别为一个堆的二叉树和数组展现形式。

二叉堆.png 二叉堆可以分为最大堆和最小堆。最大堆满足A.data[parent[i]] ≥ A.data[i],最小堆满足A.data[parent[i]] ≤ A.data[i]。

堆排序

基于堆实现排序,可通过以下方法实现:

  • MAX-HEAPIFY:此过程维护最大堆的性质,保证堆是一颗最大堆,时间复杂度为O(lgn);
  • BUILD-MAX-HEAP:此过程从无序数组中构建一个最大堆,具有线性时间复杂度;
  • HEAPSORT:对一个数组进行原址排序,时间复杂度为O(nlgn)。

java实现

  1. 定义堆的数据结构
 /**
  * 堆结构
  */
 public class Heap {
     /**
      * 堆的大小
      */
     private int heapSize;
 ​
     /**
      * 存储堆的数组
      */
     private int[] heapDate;
 ​
     public int getHeapSize() {
         return heapSize;
     }
 ​
     public void setHeapSize(int heapSize) {
         this.heapSize = heapSize;
     }
 ​
     public int[] getHeapDate() {
         return heapDate;
     }
 ​
     public void setHeapDate(int[] heapDate) {
         this.heapDate = heapDate;
     }
 }
  1. 实现MAX-HEAPIFY方法
 /**
  * 维护最大堆性质,时间复杂度为O(lgn)
     *
     * @param heap 最大堆
     * @param i    维护堆的起始索引,从1开始
     */
    private void maxHeapIfy(Heap heap, int i) {
        // 左孩子下标
        int left = 2 * i + 1;
        // 右孩子下标
        int right = 2 * (i + 1);
        int largest;

        int[] heapNums = heap.getHeapDate();
        // 每棵子树的孩子节点小于等于其父节点
        if (left <= heap.getHeapSize() - 1 && heapNums[left] > heapNums[i]) {
            largest = left;
        } else {
            largest = i;
        }
        if (right < heap.getHeapSize() - 1 && heapNums[right] > heapNums[largest]) {
            largest = right;
        }
        if (largest != i) {
            int temp = heapNums[i];
            heapNums[i] = heapNums[largest];
            heapNums[largest] = temp;
            maxHeapIfy(heap, largest);
        }
    }
  1. 实现BUILD-MAX-HEAP方法
 /**
   * 建堆
   *
   * @param nums 用来构建堆的数组
   * @return 建好的堆
   */
  private Heap buildHeap(int[] nums) {
      Heap heap = new Heap();
      heap.setHeapSize(nums.length);
      heap.setHeapDate(nums);
      for (int i = nums.length / 2; i >= 0; i--) {
          maxHeapIfy(heap, i);
      }
      return heap;
  }
  1. 实现HEAPSORT方法
/**
     * 堆排序
     *
     * @param nums 待排序的数组
     */
    public void heapSort(int[] nums) {
        // 建堆
        Heap heap = buildHeap(nums);
        int[] heapDate = heap.getHeapDate();
        // 从数组的最后一个元素开始,每次将堆的根节点与最后一个元素互换
        for (int i = heapDate.length - 1; i >= 0; i--) {
            int temp = nums[0];
            nums[0] = nums[i];
            nums[i] = temp;
            // 将堆的大小减一,再次进行调整,使其满足堆的性质
            heap.setHeapSize(heap.getHeapSize() - 1);
            maxHeapIfy(heap, 0);
        }
    }