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

堆也叫二叉堆,是一个数组,可以被看作一个近似的完全二叉树,树上的每一个节点对应数组中的一个元素。除了最底层外,该树实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)

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

二叉堆可以分为最大堆和最小堆。最大堆满足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;
     }
    }
  2. 实现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);
         }
     }
  3. 实现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;
     }
  4. 实现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);
         }
     }

天道酬勤
1 声望1 粉丝

« 上一篇
JDK动态代理