王清欢Randy 王清欢Randy
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
  • 基础算法

    • 双指针

      • 双指针基础
      • 碰撞指针
      • 快慢指针
      • 滑动窗口
    • 二分查找

      • 基础应用
      • 边界收缩
      • 局部有序
    • 排序算法

      • 01八大排序
      • 02快速排序
      • 03归并排序
      • 04桶排序
      • 05堆排序
        • 03 堆排序
          • 堆排序简介
          • 912 排序数组
    • 优先搜索

      • 01递归
      • 02网格结构深度优先搜索
      • 03树结构深度优先搜索
      • 04图结构深度优先搜索
      • 05网格结构广度优先搜索
      • 06树结构广度优先搜索
      • 07图结构广度优先搜索
    • 回溯算法

      • 01递归
      • 02 子集问题
      • 03 全排列问题
      • 04 组合问题
      • 05 回溯搜索问题
  • 基础数据结构

    • 线性表与哈希表

      • 01数组
      • 02栈和队列
      • 03单调栈
      • 04优先队列
      • 05双端队列
      • 06哈希表
      • 07多重集合
      • 08前缀和
      • 09数据结构设计
    • 字符串

      • 01字符串比较
      • 02回文字符串
      • 03字符串匹配
      • 04字符串算术表达式
    • 单链表

      • 01链表基础操作
      • 02链表遍历
    • 二叉树

      • 01二叉树的属性
      • 02二叉树的操作
      • 03层次遍历
      • 04前中后序遍历
      • 05二叉搜索树的属性
      • 06二叉搜索树的操作
      • 07字典树
      • 08二叉搜索树BST
    • 图

      • 01二分图
      • 02拓扑排序
      • 03并查集
      • 04最小生成树
      • 05最短路径
  • 进阶算法

    • 贪心算法

      • 01跳跃游戏
      • 02分配问题
      • 03区间问题
    • 分治策略

    • 动态规划

      • 01一维动态规划
      • 02二维动态规划
      • 03分割型动态规划
      • 04子序列问题
      • 05背包问题
      • 06字符串编辑问题
      • 07股票交易问题
  • 其他内容

    • 数学问题

      • 01公倍数与公因数
      • 02质数问题
      • 03进制转换问题
      • 04数字字符串求和问题
      • 05众数问题
      • 06中位数问题
      • 07数字处理问题
      • 08随机数问题
    • 位运算

      • 01位运算基础
      • 02妙用异或运算
      • 03二进制特性
  • LeetCode刷题笔记
  • 基础算法
  • 排序算法
王清欢
2023-03-24
目录

05堆排序

# 03 堆排序

# 堆排序简介

算法思想:

​ 堆排序是对简单选择排序的改进,其核心思想是利用大根堆或者小根堆的树形结构,不断获取堆顶元素存入排序序列。大根堆是指一棵二叉树的每个节点值都大于或者等于它的左右子节点值,其根节点为最大值;小根堆反之。

​ 实现堆排序由两个关键任务:一是要构建大根堆或者小根堆;二是在取出堆顶之后,调整堆保持大根堆或者小根堆的树形结构。

​ 堆构建过程:堆构建有自上而下和自下而上两种方法,我们采用简单的自上而下构建

  • 根据数组顺序插入树节点
  • 如果插入节点值小于父节点,继续插入其他节点
  • 如果插入节点值大于父节点,那么需要将该节点不断上浮,直到找到合适的插入位置
  • 需要注意的是大根堆或者小根堆都是一棵完全二叉树,可以直接使用数组映射完全二叉树,不需要去另外构建树节点结构体;使用数组映射完全二叉树,索引从 0 开始具有如下性质:
    • 当前节点的父节点索引为(i-1)/2
    • 当前节点的左节点索引为2*i+1
    • 当前节点的左节点索引为2*i+2 = 2*(i+1)

​ 堆调整过程:

  • 取出堆顶之后,用最后一个叶子节点与堆顶交换
  • 因为最后一个叶子节点是数组的最小元素,所以将它放到大根堆堆顶,就破坏大根堆堆的树形结构,需要调整堆
  • 选取根节点的左右节点中较大的节点与当前根节点交换
  • 交换后如果破坏了子树的堆结构,就需要按照上述调整步骤递归地调整堆结构

执行样例:

输入:[29,10,14,37,16,25,20]

为了友好展示快排的效果我们稍微调整了一下之前的例子,删去了重复的元素

  1. 大根堆构建过程

构建大根堆

  1. 堆排序过程

堆排序

算法实现:

// 下沉调整大根堆,比较节点及其子节点,节点值大的子节点与父节点交换
void sink(vector<int> &nums, int i,int heapSize){
    if(heapSize==0 || nums.empty()) return;

    // 找到当前节点、左节点、右节点中较大的一个节点索引
    int bigger = i;
    int leftChild = 2*i+1;
    if(leftChild < heapSize){
        bigger = nums[leftChild] > nums[i] ? leftChild:i;
    }
    int rightChild = 2*i+2;
    if(rightChild < heapSize){
        bigger = nums[rightChild] > nums[bigger] ? rightChild:bigger;
    }

    // 如果较大节点是左右节点中的一个,交换当前节点和较大节点
    if(bigger!=i){
        swap(nums[i],nums[bigger]);
        sink(nums,bigger,heapSize); // 递归调整
    }
}

void buildHeap(vector<int> &nums, int heapSize){
    // 从最后一个非叶子节点开始构造
    int i=(heapSize-1)/2;
    for(i;i>=0;--i){
        sink(nums,i,heapSize);
    }
}

// 递归排序时,堆根节点先与最后一个节点进行交换,交换后,堆大小减1,并对根节点进行下沉调整
void sort(vector<int> &nums, int &heapSize){
	swap(nums[0], nums[heapSize - 1]);
	--heapSize;
	sink(nums,0,heapSize);
}

void heapSort(vector<int> &nums){
    int heapSize = nums.size();
    buildHeap(nums,heapSize);
    for(int i=0;i<nums.size()-1;++i){
        sort(nums,heapSize);
    }
}

# 912 排序数组 (opens new window)

给你一个整数数组 nums,请你将该数组升序排列。

示例:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

解析:

class Solution {
public:
    void sink(vector<int>& nums, int root, int heapSize){
        if(heapSize <=0 || nums.empty()){
            return;
        }
        int bigger = root;
        int leftChild = 2*root+1;
        int rightChild = 2*root+2;
        if(leftChild<heapSize){
            bigger = nums[leftChild] > nums[root]?leftChild:root;
        }
        if(rightChild<heapSize){
            bigger = nums[rightChild] > nums[bigger]?rightChild:bigger;
        }

        if(bigger!=root){
            swap(nums[root],nums[bigger]);
            sink(nums,bigger,heapSize);
        }
    }

    void bulidHeap(vector<int>& nums, int heapSize){
        for(int root = (heapSize-1)/2;root>=0;--root){
            sink(nums,root,heapSize);
        }
    }

    void top(vector<int>& nums, int& heapSize){
        swap(nums[0],nums[heapSize-1]);
        --heapSize;
        sink(nums,0,heapSize);
    }

    vector<int> sortArray(vector<int>& nums) {
        int heapSize = nums.size();
        bulidHeap(nums,heapSize);
        for(int i=0;i<nums.size();++i){
            top(nums,heapSize);
        }
        return nums;
    }
};
上次更新: 2023/11/19, 12:55:48
04桶排序
01递归

← 04桶排序 01递归→

Theme by Vdoing | Copyright © 2023-2024 Wang Qinghuan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式