3.比較排序之堆排序

来源:http://www.cnblogs.com/yulinfeng/archive/2017/06/21/7061681.html
-Advertisement-
Play Games

對於堆排序會涉及一些完全二叉樹知識。對於待排序列{10, 2, 11, 8, 7},把它看成是一顆完全二叉樹,如下圖所示。 堆分為大根堆和小根堆:大根堆表示每個根節點均大於其子節點(L(i) >= L(2i) && L(i) >= L(2i + 1)),小根堆表示每個根節點均小於其子節點(L(i)  ...


 

  對於堆排序會涉及一些完全二叉樹知識。對於待排序列{10, 2, 11, 8, 7},把它看成是一顆完全二叉樹,如下圖所示。

  堆分為大根堆和小根堆:大根堆表示每個根節點均大於其子節點(L(i) >= L(2i) && L(i) >= L(2i + 1)),小根堆表示每個根節點均小於其子節點(L(i) <= L(2i) && L(i) <= L(2i + 1))。(在完全二叉樹中第i個節點的左子節點為2i,其右位元組點為2i + 1

  本文將以大根堆的構建作為示例進行講解。

  堆排序的第一步——構建初始堆。如何構建初始堆呢?根據定義,關鍵點在於每個根節點。觀察上述待排序列的完全二叉樹,不難發現存在節點2和節點10有子節點,它們是需要關註的節點。

  如何定位節點2呢?發現它是葉子節點,或者最後一個節點的父節點,根據完全二叉樹的性質可知,除根節點外任意節點的父節點的編號為⌊n / 2⌋。已知n = 5,易知節點2的編號為⌊5 / 2⌋ = ②。比較它與左右子節點的大小並調整。

  最後剩下根節點10,已知節點2的編號為② - 1 = ①即得到根節點10的編號。比較它與左右子節點的大小並調整。

  調整完畢後發現已經構成了一個大根堆,示例中的待排序列較為簡單,再給出一個較為複雜的待排序列,觀察其構建大根堆的過程。對於待排序列{53, 17, 78, 09, 45, 65, 87, 32},將它看成一顆完全二叉樹。

  同樣我們來看它所需要關註的節點有哪些。

  根據第一個例子,我們很容易能定位節點09的編號為⌊8 / 2⌋ = ④,節點78的編號為④ - 1 = ③……,依次類推,發現了一定的規律,即需要調整的節點位置從n / 2開始依次遞減直到根節點結束(n / 2 ~ 1)。現在開始調整。

  在第四次調整結束後發現節點53不滿足大根堆的定義,其右子節點大於它,此時需要做進一步的向下調整。

 

  註意向下調整是每次向上調整的時候都需要做的判斷是否需要向下調整,而不是在所有的向上調整結束過後再回過頭來向下調整。這樣大根堆就建立好了,此時待排序列數組情況已經發生了改變:{87, 45, 78, 32, 17, 65, 53, 09}。接下來是如何進行排序的問題。將大根堆的根節點與最後一個節點互換,並調整二叉樹使其仍然滿足大根堆。

  可以看到將根節點與最後一個節點呼喚後,待排序列的最大值已經放到了數組的最後一個位置{……, 87},此時完成了第一趟排序,但這第一趟排序還沒有結束,此時除節點87外,其餘節點並不滿足大根堆的條件,所以需要對其餘節點進行調整為大根堆。排序過程不再給出,JavaPython3的代碼實現如下。

  Java

 1 package com.algorithm.sort.heap;
 2 
 3 import java.util.Arrays;
 4 
 5 /**
 6  * 堆排序
 7  * Created by yulinfeng on 6/20/17.
 8  */
 9 public class Heap {
10     
11     public static void main(String[] args) {
12         int[] nums = {53, 17, 78, 09, 45, 65, 87, 32};
13         nums = heapSort(nums);
14         System.out.println(Arrays.toString(nums));
15     }
16     
17     /**
18      * 堆排序
19      * @param nums 待排序數組序列
20      * @return 排好序的數組序列
21      */
22     private static int[] heapSort(int[] nums) {
23     
24         for (int i = nums.length / 2 - 1; i >= 0; i--) {
25             heapAdjust(nums, i, nums.length);
26         }
27         for (int i = nums.length - 1; i > 0; i--) {
28             int temp = nums[i];
29             nums[i] = nums[0];
30             nums[0] = temp;
31             heapAdjust(nums, 0, i);
32         }
33         return nums;
34     }
35     
36     /**
37      * 調整堆
38      *
39      * @param nums   待排序序列
40      * @param parent      待調整根節點
41      * @param length 數組序列長度
42      */
43     private static void heapAdjust(int[] nums, int parent, int length) {
44         int temp = nums[parent];
45         int childIndex = 2 * parent + 1;    //完全二叉樹節點i從編號1開始的左子節點位置在2i,此處數組下標從0開始,即左子節點所在數組索引位置為:2i + 1
46         while (childIndex  < length) {
47             if (childIndex + 1 < length && nums[childIndex] < nums[childIndex + 1]) {
48                 childIndex++;   //節點有右子節點,且右子節點大於左子節點,則選取右子節點
49             }
50             if (temp > nums[childIndex]) {
51                 break;  //如果選中節點大於其子節點,直接返回
52             }
53             nums[parent] = nums[childIndex];
54             parent = childIndex;
55             childIndex = 2 * parent + 1;    //繼續向下調整
56         }
57         nums[parent] = temp;
58     }
59 }

  Python3

 1 #堆排序
 2 def heap_sort(nums):
 3 
 4     for i in range(int(len(nums) / 2 - 1), -1, -1):
 5         heap_adjust(nums, i, len(nums))
 6     
 7     for i in range(len(nums) - 1, -1, -1):
 8         temp = nums[i]
 9         nums[i] = nums[0]
10         nums[0] = temp
11         heap_adjust(nums, 0, i)
12     
13     return nums
14 
15 #調整堆
16 def heap_adjust(nums, parent, length):
17     
18     temp = nums[parent]
19     childIndex = 2 * parent + 1
20     while childIndex < length:
21         if childIndex + 1 < length and nums[childIndex] < nums[childIndex + 1]:
22             childIndex += 1
23         if temp > nums[childIndex]:
24             break
25         nums[parent] = nums[childIndex]
26         parent = childIndex
27         childIndex = 2 * parent + 1
28     
29     nums[parent] = temp
30         
31 nums = [53, 17, 78, 09, 45, 65, 87, 32]
32 nums = heap_sort(nums) 33 print(nums)

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 因為沒有AspNetCoreModule所以無法正常運行 http://download.microsoft.com/download/3/8/1/381CBBF3-36DA-4983-BFF3-5881548A70BE/DotNetCore.1.0.4_1.1.1-WindowsHosting.e ...
  • using System.Xml; using System.Data; namespace DotNet.Utilities { /// <summary> /// Xml的操作公共類 /// </summary> public class XmlHelper { #region 欄位定義 /// ...
  • https加密鏈接,在訪問的過程中,可以保護你的隱私,保證你的敏感數據不會被別人偷窺,竊取。如果你的伺服器在境外,使用https,可以有更穩定的訪問體驗。接下來我們看一下ZKEACMS如何配置使用HTTPS。 ...
  • using System; using System.Security.Cryptography; using System.Text; namespace DotNet.Utilities { /// <summary> /// Encrypt 的摘要說明。 /// </summary> publ ...
  • 一、使用線程的理由 1、可以使用線程將代碼同其他代碼隔離,提高應用程式的可靠性。 2、可以使用線程來簡化編碼。 3、可以使用線程來實現併發執行。 二、基本知識 1、進程與線程:進程作為操作系統執行程式的基本單位,擁有應用程式的資源,進程包含線程,進程的資源被線程共用,線程不擁有資源。 2、前臺線程和 ...
  • using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; namespace Utils { /// <summary> /// <para> </para> /// 常用 ...
  • WPF簡介 Windows Presentation Foundation(WPF)是微軟新一代圖形系統,運行在.NET Framework 3.0架構下,為用戶界面、2D/3D 圖形、文檔和媒體提供了統一的描述和操作方法。基於DirectX 9/10技術的WPF不僅帶來了前所未有的3D界面,而且其 ...
  • 在.Net框架中,如果您查看所有類型的的基類:System.Object類,將找到如下4個與相等判斷的方法: static Equals() virtual Equals() static ReferenceEquals() virtual GetHashCode() 除此之外,Microsoft已 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...