前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【算法】堆排序

【算法】堆排序

作者头像
MapleYe
发布2020-03-28 21:02:32
5050
发布2020-03-28 21:02:32
举报
文章被收录于专栏:MapleYeMapleYe

堆排序

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

大根堆,小根堆

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

如图所示:

算法思路

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

1、构造算法

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

代码语言:javascript
复制
  /// 把下标为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、调整算法

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

代码语言:javascript
复制
/// 重新调整为大根堆,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、完整代码

代码语言:javascript
复制
  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;
  }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 堆排序
      • 大根堆,小根堆
        • 算法思路
          • 1、构造算法
          • 2、调整算法
          • 3、完整代码
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档