美文网首页
【算法】堆排序

【算法】堆排序

作者: mapleYe | 来源:发表于2018-06-12 18:11 被阅读0次

    堆排序

    堆是一种树形结构,在排序的过程中,把元素看成是一颗完全二叉树。用数组来表示一颗完全二叉树的话,对于每个节点 i 存在以下关系:
    1)父节点 = (i - 1) / 2
    2)左孩子 = 2 * i + 1
    3)右孩子 = 2 * i + 2

    大根堆,小根堆

    父节点都比子节点大的堆成为大根堆,用于升序
    父节点都比子节点小的堆成为小根堆,用于降序

    如图所示:


    大根堆 小根堆

    算法思路

    因此,我们需要把一个树构造成大根堆或小根堆,以大根堆为例子:
    1)构造大根堆
    2)把根节点和尾节点进行交换,堆的size--
    3)把剩余的堆进行调整,重新调整为大根堆
    3)重复2,3步骤,直至堆的size为0

    1、构造算法

    每次插入一颗子节点,都与父节点进行比较,若比父节点大,则与父节点交换后,再重复以上步骤,直至不比父节点大。

      /// 把下标为index的值插入,建立堆
      /// 堆与数组的转换:
      /// 对于当前下标为index的数,其父亲为 (index - 1) / 2
      /// 左节点为 2 * index + 1, 右节点为 2 * index + 2
      public static void heapInsert(int[] arr, int index) {
        // 比父节点大,则交换,直至比父节点小
        while (arr[index] > arr[(index - 1) / 2]) {
          swap(arr, index, (index - 1) / 2);
          index = (index - 1) / 2;
        }
      }
    

    2、调整算法

    父节点依次与左右孩子比较,若其父节点小于左右孩子,则与左右孩子较大者交换,然后重复以上步骤,直至父节点大于左右孩子

    /// 重新调整为大根堆,size表示:在数组建立了堆,堆的size
      public static void heapify(int arr[], int index, int size) {
        // 左节点
        int left = index * 2 + 1;
        while(left < size) {
          // 右节点
          int right = left + 1;
          // 设左孩子为最大
          int largest = left;
          if (right < size) {
            // 存在右节点,选出其中最大的
            largest = arr[left] > arr[right] ? left : right;
          }
          // 比较父节点和最大子节点的值
          largest = arr[index] > arr[largest] ? index : largest;
          // 若当前节点就是最大的,则调整完毕
          if (largest == index) {
            return;
          }
          // 否则交换
          swap(arr, largest, index);
          // 继续以上过程
          index = largest;
          left = index * 2 - 1;
        }
      }
    

    3、完整代码

      public static void heapSort(int arr[]) {
        if (arr == null || arr.length < 2) {
          return;
        }
        // 建立大根堆
        for(int i = 0; i < arr.length; i++) {
          heapInsert(arr, i);
        }
        int size = arr.length;
        // 将头部换到最后,开始调整,直至size = 0
        swap(arr, 0, --size);
        while(size > 0) {
          heapify(arr, 0, size);
          swap(arr, 0, --size);
        }
      }
    
      /// 把下标为index的值插入,建立堆
      /// 堆与数组的转换:
      /// 对于当前下标为index的数,其父亲为 (index - 1) / 2
      /// 左节点为 2 * index + 1, 右节点为 2 * index + 2
      public static void heapInsert(int[] arr, int index) {
        // 比父节点大,则交换,直至比父节点小
        while (arr[index] > arr[(index - 1) / 2]) {
          swap(arr, index, (index - 1) / 2);
          index = (index - 1) / 2;
        }
      }
    
      /// 重新调整为大根堆,size表示:在数组建立了堆,堆的size
      public static void heapify(int arr[], int index, int size) {
        // 左节点
        int left = index * 2 + 1;
        while(left < size) {
          // 右节点
          int right = left + 1;
          // 设左孩子为最大
          int largest = left;
          if (right < size) {
            // 存在右节点,选出其中最大的
            largest = arr[left] > arr[right] ? left : right;
          }
          // 比较父节点和最大子节点的值
          largest = arr[index] > arr[largest] ? index : largest;
          // 若当前节点就是最大的,则调整完毕
          if (largest == index) {
            return;
          }
          // 否则交换
          swap(arr, largest, index);
          // 继续以上过程
          index = largest;
          left = index * 2 - 1;
        }
      }
    
      public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
      }
    

    相关文章

      网友评论

          本文标题:【算法】堆排序

          本文链接:https://www.haomeiwen.com/subject/peereftx.html