首页 > 其他分享 >数据结构学习笔记-堆排序

数据结构学习笔记-堆排序

时间:2024-06-09 09:11:10浏览次数:15  
标签:arr int 元素 堆排序 笔记 heapify largest 数据结构 节点

堆排序算法的设计与分析

问题描述:设计并分析堆排序

【前置知识:什么是堆?】

堆(Heap)是一种特殊的树形数据结构,它满足以下两个条件之一:

  1. 最大堆(Max Heap)
    • 每个节点的值都大于或等于其子节点的值。
    • 换句话说,根节点的值是整个堆中最大的。
  2. 最小堆(Min Heap)
    • 每个节点的值都小于或等于其子节点的值。
    • 换句话说,根节点的值是整个堆中最小的。

堆的基本特点

  • 完全二叉树:堆通常被实现为完全二叉树,也就是说,除了最后一层,所有层都是满的,而且最后一层的节点都是从左到右排列的。
  • 堆的性质:对于最大堆,任意节点的值都大于或等于其子节点的值;对于最小堆,任意节点的值都小于或等于其子节点的值。

堆的操作

堆支持以下基本操作:

  1. 插入(Insert)
    • 在堆中插入一个新元素,首先将新元素放在堆的末尾,然后通过上浮操作使其恢复堆的性质。
  2. 删除(Delete)
    • 删除堆顶元素(最大堆的最大值或最小堆的最小值),用堆的最后一个元素替换堆顶元素,然后通过下沉操作使其恢复堆的性质。
  3. 堆化(Heapify)
    • 将一个无序数组调整为堆结构,可以通过自下而上的方法调整树的每个节点来实现。

堆的应用

堆有很多应用场景,包括但不限于:

  • 优先队列(Priority Queue):堆可以高效地实现优先队列,支持快速插入和删除操作。
  • 堆排序(Heap Sort):一种利用堆的性质进行排序的算法。
  • 求中位数:使用两个堆(一个最大堆和一个最小堆)可以高效地求动态数据流的中位数。

【算法设计思想】

构建最大堆

  • 从无序数组构建一个最大堆。最大堆是指每个节点的值都大于或等于其子节点的值,这样堆顶元素(即数组的第一个元素)就是整个数组的最大值。

交换堆顶和堆的最后一个元素

  • 将堆顶元素(即最大值)和堆的最后一个元素交换,这样最大值就被放到数组的末尾,接下来只需对前面部分进行堆调整即可。

堆调整

  • 调整交换后的堆,使其再次成为最大堆。这个过程称为堆调整(Heapify),确保交换后的堆依然满足堆的性质。

重复步骤2和步骤3

  • 不断将堆顶元素和堆的最后一个元素交换,然后对前面的部分进行堆调整,直到所有元素都被排序。

【算法描述】

// 堆调整函数,维护最大堆性质
void heapify(int arr[], int n, int i) {
    int largest = i;     // 初始化为根节点
    int left = 2 * i + 1; // 左子节点
    int right = 2 * i + 2; // 右子节点

    // 如果左子节点大于根节点
    if (left < n && arr[left] > arr[largest])
        largest = left;

    // 如果右子节点大于当前最大的节点
    if (right < n && arr[right] > arr[largest])
        largest = right;

    // 如果最大值不是根节点
    if (largest != i) {
        swap(&arr[i], &arr[largest]);
        // 递归调用heapify,维护堆性质
        heapify(arr, n, largest);
    }
}

// 主函数,进行堆排序
void heapSort(int arr[], int n) {
    // 构建最大堆
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);

    // 一个个取出元素进行排序
    for (int i = n - 1; i > 0; i--) {
        // 将当前根节点移到末尾
        swap(&arr[0], &arr[i]);
        // 调整堆
        heapify(arr, i, 0);
    }
}

【完整的测试程序】

#include <stdio.h>

// 交换两个元素的值
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 堆调整函数,维护最大堆性质
void heapify(int arr[], int n, int i) {
    int largest = i;     // 初始化为根节点
    int left = 2 * i + 1; // 左子节点
    int right = 2 * i + 2; // 右子节点

    // 如果左子节点大于根节点
    if (left < n && arr[left] > arr[largest])
        largest = left;

    // 如果右子节点大于当前最大的节点
    if (right < n && arr[right] > arr[largest])
        largest = right;

    // 如果最大值不是根节点
    if (largest != i) {
        swap(&arr[i], &arr[largest]);
        // 递归调用heapify,维护堆性质
        heapify(arr, n, largest);
    }
}

// 主函数,进行堆排序
void heapSort(int arr[], int n) {
    // 构建最大堆
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(arr, n, i);

    // 一个个取出元素进行排序
    for (int i = n - 1; i > 0; i--) {
        // 将当前根节点移到末尾
        swap(&arr[0], &arr[i]);
        // 调整堆
        heapify(arr, i, 0);
    }
}

// 打印数组
void printArray(int arr[], int n) {
    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

// 测试堆排序
int main() {
    int arr[] = {12, 11, 13, 5, 6, 7};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("排序前的数组:\n");
    printArray(arr, n);

    heapSort(arr, n);

    printf("排序后的数组:\n");
    printArray(arr, n);

    return 0;
}

标签:arr,int,元素,堆排序,笔记,heapify,largest,数据结构,节点
From: https://www.cnblogs.com/zeta186012/p/18239236

相关文章

  • C语言学习笔记(八)————数组
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言1一维数组1.2一维数组的引用1.3一维数组的初始化2二维数组2.1二维数组的定义2.2二维数组的存放顺序3多维数组总结前言一个学习C语言的小白,有问题评论或私信~本文主要记录C语言......
  • 计算机组成原理复习笔记
    前言就是按照考试的题型写的总结非常应试版题型一、进制转换只考十进制二进制十六进制之间的相互转换一个个看(1)十进制转其他转二进制:除以2从小到大取余数(0或1)转十六进制:除以16从小到大取余数(0到f)(2)二进制十六进制转十进制每位数字乘以相应的幂数再相......
  • 计算机系统基础笔记(12)——控制
    前言在持续输出ing一、条件码1.处理器状态(x86-64,部分的)当前程序的执行信息◼临时数据◼运行时栈的位置(栈顶)◼当前代码控制点的位置(即将要执行的指令地址)◼最近一次指令执行的状态2.条件码(隐式设置)简单的位寄存器条件码(隐式设置)CF进位标志(无符号数)SF符......
  • Centos7系统禁用Nouveau内核驱动程序【笔记】
    在CentOS系统中,Nouveau是开源的NVIDIA显卡驱动程序,但它与NVIDIA的官方驱动程序NVIDIAProprietaryDriver存在兼容性问题。如果你想要禁用Nouveau并使用NVIDIA官方驱动,可以按照以下步骤操作:1、创建一个黑名单文件以禁用Nouveau驱动。echo'blacklistnouveau'|sudote......
  • 做题笔记
    杂题DPAbandoningRoads看到\(n\leq70\),想一下朴素状压设\(f_{S,u}\),\(S\)表示处理完的连通块状态,\(u\)表示当前的节点因为只有两种边权,所以可以双队列求最短路,所以我们有了一个天然的\(O(2^nm)\)的做法无法通过捏\(m\)肯定没办法省略了那我们考虑减少\(2......
  • Python数据结构解析:从基本语法到实战应用,提升代码效率与性能
    基本语法Python提供了多种内置的数据结构,包括列表(List)、元组(Tuple)、集合(Set)、字典(Dictionary)等。这些数据结构具有不同的特点和用途,可以根据需求选择合适的数据结构。1.列表(List)列表是Python中最常用的数据结构之一,用于存储一系列元素,可以是不同类型的数据。列表使用......
  • Living-Dream 系列笔记 第59期
    T1这是一道manacher模板,但是我们使用二分+hash\(O(n\logn)\)的做法。显然地,若长为\(len\)的回文串存在,则长为\(len-2,len-4,...\)的回文串也一定存在(在两端各删去若干相同字符即可)。至此,我们发现回文串分两类:奇回文串、偶回文串,在每一类当中分别具有单调性。于是......
  • C语言笔记第12篇:自定义类型(struct结构体)
    1、结构体类型的声明为什么要有自定义的结构类型呢?这是因为稍微复杂的类型,直接使用内置类型是不行的!比如:描述一个人或 一本书的价格、版号等信息。1.1结构的创建结构体是一些值的集合,这些值称为成员变量,结构的每个成员可以是不同类型的变量。1.1.1 结构的声明structt......
  • 替罪羊树学习笔记
    替罪羊树学习笔记史!思想众所周知,替罪羊树是一种平衡二叉搜索树,其拥有虽然我不理解为什么,但是很牛的复杂度。其思想在于通过一个系数进行定期重构,使得维护所有信息的树是一棵接近平衡树的伪平衡树,那么他依然拥有\(O(\logn)\)级别的层高,因此对于跳转查询依旧具有优异的复杂度......
  • 通信原理第一章重点笔记
    通信原理第七版 樊昌信曹丽娜手写笔记参考小红书:香草味冰淇淋~第一章绪论1.消息、信息与信号消息:是信息的载体(可分为连续消息和离散消息);信息:是消息中所包含发的有效内容;信号:是消息的传输载体;  三者区别:消息是信息的物理形式,信息是消息的有效内容,信号是消息的传......