C++堆排序詳解

一、堆排序簡介

堆排序是一種基於比較的排序演算法,其時間複雜度為O(n log n)。它的基本思想是將待排序的序列構造成一個堆,然後依次取出堆頂元素(最大或最小值),並將剩餘待排序元素重新調整為堆。

堆是一種特殊的樹形數據結構,它通常用數組來實現。堆滿足以下兩個條件:

  • 任意節點的值都不大於(或不小於)其左右兒子節點的值,稱為大根堆(或小根堆)
  • 堆總是一棵完全二叉樹

二、堆排序過程

堆排序的過程可以分為兩個階段:

1、構建堆

首先將待排序的序列構建成一個大根堆(也可以是小根堆),具體過程如下:

  • 從最後一個非葉子節點(即len/2-1)開始,依次將每個節點和其子節點進行比較,如果節點值小於其子節點值,則將其與最大值節點進行交換
  • 交換後,被交換的節點位置變為其子節點位置,重複上述過程,直到所有節點都被交換到最後一層為止
  • 構建好的堆就是一個符合大根堆或小根堆條件的序列

2、排序

接下來,我們需要將堆頂元素(最大或最小值)取出,然後將剩餘待排序元素重新構建堆,依次進行如下操作:

  • 將堆頂元素與最後一個元素交換,最後一個元素為已排序的數據,堆大小減一
  • 將剩餘待排序元素重新構建堆

重複以上操作,直到堆中只剩下一個元素,排序完成。

三、C++堆排序代碼

#include <iostream>
using namespace std;

// 建立大根堆
void adjustHeap(int arr[], int len, int i) {
    int j = i;
    // 左子節點
    int left = 2 * i + 1;
    // 右子節點
    int right = 2 * i + 2;
    // 找到最大值
    if (left < len && arr[left] > arr[j]) {
        j = left;
    }
    if (right < len && arr[right] > arr[j]) {
        j = right;
    }
    // 如果當前節點已經是最大值,退出遞歸
    if (j != i) {
        swap(arr[i], arr[j]);
        adjustHeap(arr, len, j);
    }
}

// 堆排序
void heapSort(int arr[], int len) {
    // 構建大根堆
    for (int i = len / 2 - 1; i >= 0; i--) {
        adjustHeap(arr, len, i);
    }
    // 排序
    for (int i = len - 1; i > 0; i--) {
        swap(arr[0], arr[i]);
        adjustHeap(arr, i, 0);
    }
}

int main() {
    int arr[] = {9, 2, 4, 1, 3, 7, 8, 5};
    int len = sizeof(arr) / sizeof(arr[0]);
    heapSort(arr, len);
    for (int i = 0; i < len; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

四、堆排序優化

以上代碼是最基本的堆排序演算法,但是我們可以通過一些優化,進一步提升堆排序的效率。

1、堆化優化

在建堆過程中,我們可以將數組從後往前遍歷,對於每個節點,只需將其與其子節點進行比較,而不必和所有子孫節點都進行比較。這樣可以減少比較次數,提升效率。

// 建立大根堆
void adjustHeap(int arr[], int len, int i) {
    int j = i;
    // 左子節點
    int left = 2 * i + 1;
    // 右子節點
    int right = 2 * i + 2;
    // 找到最大值
    if (left < len && arr[left] > arr[j]) {
        j = left;
    }
    if (right < len && arr[right] > arr[j]) {
        j = right;
    }
    // 如果當前節點已經是最大值或者當前節點沒有子節點,退出遞歸
    if (j != i) {
        swap(arr[i], arr[j]);
        adjustHeap(arr, len, j);
    }
}

2、堆排序優化

在排序過程中,我們可以將堆大小作為參數傳入,不必每次都重新計算。同時,在將堆頂元素與最後一個元素交換位置後,僅需對根節點進行堆化,可以減少一半的比較次數。

// 堆排序
void heapSort(int arr[], int len) {
    // 構建大根堆
    for (int i = len / 2 - 1; i >= 0; i--) {
        adjustHeap(arr, len, i);
    }
    // 排序
    for (int i = len - 1; i > 0; i--) {
        swap(arr[0], arr[i]);
        adjustHeap(arr, i, 0);
    }
}

五、總結

堆排序是一種高效的排序演算法,通過構建堆結構,可以使排序過程的時間複雜度達到O(n log n)。C++提供了豐富的數據結構和演算法庫,可以更方便地實現堆排序,同時優化堆化和排序過程,可以進一步提高演算法的效率。

原創文章,作者:MJTYX,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/370721.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
MJTYX的頭像MJTYX
上一篇 2025-04-22 01:14
下一篇 2025-04-22 01:14

相關推薦

  • Linux sync詳解

    一、sync概述 sync是Linux中一個非常重要的命令,它可以將文件系統緩存中的內容,強制寫入磁碟中。在執行sync之前,所有的文件系統更新將不會立即寫入磁碟,而是先緩存在內存…

    編程 2025-04-25
  • 神經網路代碼詳解

    神經網路作為一種人工智慧技術,被廣泛應用於語音識別、圖像識別、自然語言處理等領域。而神經網路的模型編寫,離不開代碼。本文將從多個方面詳細闡述神經網路模型編寫的代碼技術。 一、神經網…

    編程 2025-04-25
  • Linux修改文件名命令詳解

    在Linux系統中,修改文件名是一個很常見的操作。Linux提供了多種方式來修改文件名,這篇文章將介紹Linux修改文件名的詳細操作。 一、mv命令 mv命令是Linux下的常用命…

    編程 2025-04-25
  • Python輸入輸出詳解

    一、文件讀寫 Python中文件的讀寫操作是必不可少的基本技能之一。讀寫文件分別使用open()函數中的’r’和’w’參數,讀取文件…

    編程 2025-04-25
  • nginx與apache應用開發詳解

    一、概述 nginx和apache都是常見的web伺服器。nginx是一個高性能的反向代理web伺服器,將負載均衡和緩存集成在了一起,可以動靜分離。apache是一個可擴展的web…

    編程 2025-04-25
  • MPU6050工作原理詳解

    一、什麼是MPU6050 MPU6050是一種六軸慣性感測器,能夠同時測量加速度和角速度。它由三個感測器組成:一個三軸加速度計和一個三軸陀螺儀。這個組合提供了非常精細的姿態解算,其…

    編程 2025-04-25
  • 詳解eclipse設置

    一、安裝與基礎設置 1、下載eclipse並進行安裝。 2、打開eclipse,選擇對應的工作空間路徑。 File -> Switch Workspace -> [選擇…

    編程 2025-04-25
  • C語言貪吃蛇詳解

    一、數據結構和演算法 C語言貪吃蛇主要運用了以下數據結構和演算法: 1. 鏈表 typedef struct body { int x; int y; struct body *nex…

    編程 2025-04-25
  • Python安裝OS庫詳解

    一、OS簡介 OS庫是Python標準庫的一部分,它提供了跨平台的操作系統功能,使得Python可以進行文件操作、進程管理、環境變數讀取等系統級操作。 OS庫中包含了大量的文件和目…

    編程 2025-04-25
  • Java BigDecimal 精度詳解

    一、基礎概念 Java BigDecimal 是一個用於高精度計算的類。普通的 double 或 float 類型只能精確表示有限的數字,而對於需要高精度計算的場景,BigDeci…

    編程 2025-04-25

發表回復

登錄後才能評論