首页 > 编程语言 >排序算法 -堆排序

排序算法 -堆排序

时间:2024-11-12 12:46:32浏览次数:3  
标签:arr log int 复杂度 堆排序 算法 排序 节点

文章目录

1. 堆排序(Heap Sort)

1.1 简介

堆是一种特殊的完全二叉树,分为最大堆(Max Heap)和最小堆(Min Heap)。在最大堆中,每个节点的值都大于或等于其子节点的值;在最小堆中,每个节点的值都小于或等于其子节点的值。堆排序通常使用最大堆来实现升序排序,本文使用最大堆。

1.2 堆排序的步骤

  1. 构建最大堆

    • 将数组视为完全二叉树,从最后一个非叶子节点开始,自底向上进行堆化(heapify)操作,使得每个子树都满足最大堆的性质。
  2. 排序过程

    • 将堆顶元素(最大值)与数组的最后一个元素交换,此时数组的最后一个元素就是最大值。
    • 将堆的大小减1(排除已排定的最大元素),然后重新对堆顶元素进行堆化,使其满足最大堆的性质。
    • 重复上述步骤,直到堆的大小为1,此时数组已完全排序。

1.3 堆排序C语言实现

#include <stdio.h>
 
// 堆化函数,用于维护最大堆的性质
void heapify(int arr[], int n, int i) {
    int largest = i;    // 初始化largest为根节点
    int left = 2 * i + 1; // 左子节点
    int right = 2 * i + 2; // 右子节点
 
    // 如果左子节点存在且大于根节点
    if (left < n && arr[left] > arr[largest])
        largest = left;
 
    // 如果右子节点存在且大于largest
    if (right < n && arr[right] > arr[largest])
        largest = right;
 
    // 如果largest不是根节点
    if (largest != i) {
        int swap = arr[i];
        arr[i] = arr[largest];
        arr[largest] = swap;
 
        // 递归堆化受影响的子树
        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--) {
        // 移动当前根到数组末尾
        int temp = arr[0];
        arr[0] = arr[i];
        arr[i] = temp;
 
        // 调整堆
        heapify(arr, i, 0);
    }
}
 
// 打印数组函数
void printArray(int arr[], int size) {
    for (int i = 0; i < size; 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;
}

1.4 时间复杂度

  1. 构建最大堆(或最小堆)

    • 对于一个包含 n n n 个元素的数组,构建最大堆的过程需要遍历数组中的每个非叶子节点,并对每个节点执行 heapify 操作。
    • 在最坏情况下,每个 heapify 操作需要 O ( log ⁡ n ) O(\log n) O(logn) 的时间(因为堆是一棵完全二叉树,其高度为 log ⁡ n \log n logn)。
    • 由于数组中有 O ( n ) O(n) O(n) 个节点,且每个节点最多被 heapify 一次(在构建堆的过程中),所以构建堆的时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)。
  2. 排序过程

    • 在排序过程中,我们反复执行以下操作:
      • 将堆顶元素(最大值或最小值)与数组的最后一个元素交换。
      • 减少堆的有效大小(即忽略已经排好序的部分)。
      • 对新的堆顶元素执行 heapify 操作,以维护堆的性质。
    • 这个过程需要执行 n − 1 n-1 n−1 次(因为我们需要将 n − 1 n-1 n−1 个元素移动到它们最终的位置上),每次 heapify 操作的时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn)。
    • 因此,排序过程的时间复杂度为 O ( ( n − 1 ) log ⁡ n ) O((n-1) \log n) O((n−1)logn),这可以简化为 O ( n log ⁡ n ) O(n \log n) O(nlogn)。

综上所述,堆排序的总时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)。

1.5 空间复杂度

  • 堆排序是原地排序算法(in-place sorting algorithm),它只需要一个常数级别的额外空间来存储临时变量(例如,用于交换元素的变量)。
  • 与归并排序等需要额外数组空间的排序算法相比,堆排序的空间复杂度非常低。
  • 因此,堆排序的空间复杂度为 O ( 1 ) O(1) O(1)(不考虑输入数组本身所占用的空间)。

总结:

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn)
  • 空间复杂度: O ( 1 ) O(1) O(1)(原地排序)

标签:arr,log,int,复杂度,堆排序,算法,排序,节点
From: https://blog.csdn.net/qq_46538985/article/details/143706377

相关文章

  • 【HAProxy05】企业级反向代理HAProxy调度算法之静态算法与动态算法
    HAProxy调度算法HAProxy通过固定参数balance指明对后端服务器的调度算法,该参数可以配置在listen或backend选项中。HAProxy的调度算法分为静态和动态调度算法,但是有些算法可以根据不同的参数实现静态和动态算法相互转换。官方文档:http://cbonte.github.io/haproxy-dcon......
  • 模拟鼠标真人移动轨迹算法-易语言
    一.简介鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。鼠标轨迹算法的底层实现采用C/C++语言,原因在于C/C++提供了高性能的执行能力和直接访问操作系统底层资源的能力。鼠标轨迹算法具有以下优势:模拟人工轨迹:算法能够模拟出非贝塞尔曲线......
  • 代码随想录算法训练营第三天(LeetCode203.移除链表元素;LeetCode707.设计链表;LeetCode20
    LeetCode203.移除链表元素题目链接:LeetCode203.移除链表元素题目链接思路这道题目主要考察的是移除一个链表当中的元素,我们可以先在给定的链表前面加一个虚拟头结点,这样我们对给定链表头结点的操作和给定链表其余结点的操作就会变得相同。代码classSolution{p......
  • 代码随想录算法训练营第四天(LeetCode24.两两交换链表中的节点;LeetCode10.删除链表的倒
    LeetCode24.两两交换链表中的节点题目链接:两两交换链表中的节点题目链接思路这道题其实就是一个模拟题,要求每次交换链表中两个相邻的节点(1、2节点互换;3、4节点互换;2、3节点不互换,意思就是交换过的节点不参与后续的交换了),同时只能进行节点交换,不能进行值交换。主要考......
  • 【MATLAB源码-第290期】基于matlab的MRC检测算法在OTFS通信系统中的仿真,输出误码率曲
    操作环境:MATLAB2022a1、算法描述在无线通信系统的发展历程中,随着频谱的日益紧张以及高频通信需求的增加,传统的通信方法逐渐显露出其在复杂信道环境中的局限性。尤其是在高速移动、多径传播和多普勒效应严重的环境下,传统的OFDM(正交频分复用)等技术往往难以应对这些挑战。因此......
  • leetcode算法题-有效的括号(简单)
    有效的括号(简单)leetcode:https://leetcode.cn/problems/valid-parentheses/description/前言防止脑袋生锈,做一下leetcode的简单算法题,难得也做不来哈哈。大佬绕道,小白可看。题目描述给定一个只包括'(',')','{','}','[',']'的字符串s,判断字符串是否有效。有效字符串需满足:......
  • Python 进行数据挖掘的算法介绍
    1.决策树决策树是一种用于分类和回归任务的监督学习算法。它通过树状结构来表示决策过程,每个内部节点表示一个属性上的测试,每个分支代表一个测试结果,每个叶节点代表一种分类结果。示例代码:fromsklearn.datasetsimportload_irisfromsklearn.treeimportDecisionTreeCl......
  • 【初阶数据结构与算法】线性表之链表的分类以及双链表的定义与实现
    文章目录一、链表的分类二、双链表的实现1.双链表结构的定义2.双链表的初始化和销毁初始化函数1初始化函数2销毁函数3.双链表的打印以及节点的申请打印函数节点的申请4.双链表的头插和尾插头插函数尾插函数5.双链表的查找和判空查找函数判空函数6.双链表的头删和尾......
  • 浅谈python回归算法及其应用
    Python中有很多常用的回归算法,可以用于解决不同的问题。以下是几种常见的回归算法及其应用:1.线性回归:线性回归是一种最简单的回归算法,用于建立自变量和因变量之间的线性关系。它可以用于预测房价、销售量等连续变量。2.多项式回归:多项式回归允许自变量与因变量之间的非线......
  • 第四届算法、微芯片与网络应用国际会议(AMNA 2025) 2025 4th International Conference
    重要信息官网:https://ais.cn/u/vEbMBz......