QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1524|回复: 0
打印 上一主题 下一主题

十大经典排序算法之堆排序(Java语言)

[复制链接]
字体大小: 正常 放大
杨利霞        

5273

主题

82

听众

17万

积分

  • TA的每日心情
    开心
    2021-8-11 17:59
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    网络挑战赛参赛者

    网络挑战赛参赛者

    自我介绍
    本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。

    群组2018美赛大象算法课程

    群组2018美赛护航培训课程

    群组2019年 数学中国站长建

    群组2019年数据分析师课程

    群组2018年大象老师国赛优

    跳转到指定楼层
    1#
    发表于 2020-4-23 15:00 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    - m9 W4 c0 G1 \0 R9 h
    十大经典排序算法之堆排序(Java语言)2 n& Z! z. ?9 Y8 k
    文章目录
    : H  }3 ]; \: w2 w, @& S5 _  f, U+ P9 T5 p  f- F
    什么是堆
    ' m8 p& C: x* ]4 m- y4 Z如何进行堆排序呢& Q" a$ ]' _2 ?7 i# _! k
    用数组构建一个堆: @5 @  |0 e8 f3 A: Z8 G
    上代码
    3 Z) Q% Y4 ~+ D7 r( P8 f什么是堆
    1 f; i$ A! \( k1 N2 l* J* A2 e: ~* P9 e
    在了解什么是堆之前一定要先了解什么是完全二叉树
    / l* `2 [4 _! K( O) \- @8 L- i看一下百度百科的介绍3 l, ~* e8 D9 q6 L( f! F
    8 I5 g+ H! z+ i
    若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
      d( X! i5 |; A; x百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下, Y! O0 R" d5 Q# ~# s. @) z

    , y" w: o- y( n! X完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    + }- R, V$ V% c5 \(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)3 r1 X2 \( i& c+ s. ?" p- D
    (2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
    4 O: D' \8 Q: x! `/ Y; t* ^一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。+ v3 k; c1 R$ d* \" j3 B  S
    那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    9 R5 `+ o( v$ e堆有以下两个性质6 q9 E2 t7 r4 W$ `5 ~2 y

    . h+ q7 L4 ^  ~1 堆中某个节点的值总是不大于或不小于其父节点的值;; w' Y: B) d3 R8 `
    2 堆总是一棵完全二叉树。9 f% l; h" @) ~6 {0 R8 w
    其中堆顶就对应二叉树的根
    : |2 G5 a) p9 _" j; ]* s* |7 B; M- L$ ]9 k
    堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分
    - u! s+ Q1 `. H( V3 U# s; D: x6 M( e9 o6 E% ]! p' V
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
    % u. A4 U7 c4 K% s9 Z. M' Z! ^3 u如何进行堆排序呢0 H: W+ B. X: s2 e$ U
    7 D- T, g* v: ]: S( }0 [8 [1 h
    堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的# X$ w4 c/ [' t  v) y5 ^' ]
    ' |2 T( X; \* ~/ `& k" S. i5 H6 C4 b
    用数组构建一个堆0 i6 L9 p. v) f5 h" R

    ' h& j" d* K# s; D6 K" ?因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储. L. Z, e1 {/ _; s) @
    对于用数组存储的二叉树,我们可以用如下方法来定义:2 z1 K4 k$ N! H( \8 O, x+ O' M
    假设当前节点的下标为 n
    ( ~5 G( E7 R! Q5 i# K% j
    ( a1 r8 y4 R4 z  |2 j, \0 W/ [1、那么他的左子节点的下标 2*n + 1
    * N5 a" y' j, c% Q3 h4 M) K2、那么他的右子节点的下标 2*n + 21 e" Q2 f3 p6 d8 F+ o0 c: y$ W$ W
    3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-18 z7 F( E8 ]9 W( |2 H( q
    4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断& t2 w" A. g: z  U6 z+ T
    那么有了上面四条性质,我们就可以开始动手了8 d8 [  \$ d& C$ {2 Y, x1 H

    8 G+ R: K& x8 ?3 |# N1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层6 J( z+ P' K. @: T
    2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了! f; e3 A+ T8 ]2 P% R, ?
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆7 [) L( c- E; T/ c, M* U8 N
    7 A/ v. W3 |( V; z
    堆排序的性质
    " b' R; ?/ B, p: i) I6 @% N# m1 l
    & t6 l, M% x; U& h0 S0 A中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性
    3 O3 `5 Q6 m1 d  A: r堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定
    - n) j) x& |+ R, B# l上代码' ?- L# q$ w0 v
    , ^$ e# P, I) ~  S
    /**5 N6 h  H' Z: K8 h/ E
    * 交换第n和m个元素
    + m" `. U$ Q% _- \ */+ T1 `) ?' F; q  N
    private static void swap(int arr[], int n, int m){
    5 c9 P+ S1 _+ Z% _( u    int temp = arr[n];
    6 K* R! y7 o/ {9 A! C    arr[n] = arr[m];9 S2 @* d# l2 t) v
        arr[m] = temp;
    : \% r; C/ X# Y9 T}( w4 y$ V  n+ ]. V- P9 u

    % `: b% A$ R0 Y+ p) B5 z- s+ g/**
    5 l3 l9 F0 ^) X' |5 d$ d2 m+ m * 调整指定节点和其子节点  w. f7 I* J. Y$ L+ f# O
    * @param tree 整棵树" g9 S/ K0 v3 {. K
    * @param n 数组长度,树的元素个数$ q- v- c/ y' T: {- p/ W7 Y
    * @param i 要调整的节点的下标1 ^& F% G6 m: ]: r
    */
    ) B# ^0 k& X% X+ L6 Pprivate static void heapIfy(int tree[], int n, int i){
    1 i/ E5 l; K+ j/ E+ u# y    if(i >= n){+ c: ?  z1 c0 U& u; ]7 B7 e
            return;. ~9 J* @* v, e
        }
    4 Z* l/ X9 B' t; N    int c1 = 2 * i + 1;//左子节点的下标3 K1 [# b. k0 I; k, K# \
        int c2 = 2 * i + 2;//右子节点的下标8 R8 a: V9 X5 S* }$ a
        int max = i;//假设父节点是最大的8 M" P+ S& a; V9 _+ T$ [9 ^4 I. K% e
        //找出最大值的下下标/ D% r. a. h, |
        if(c1 < n && tree[c1] > tree[max]){: \7 ]' d" ~- K5 R
            max = c1;
    4 m! A9 c: y5 s+ [+ k    }7 l. p4 Y& Q! q
        if(c2 < n && tree[c2] > tree[max]){" X1 E* L9 F& y3 d8 E0 z9 F) V. B
            max = c2;, W  u/ a" H, X5 |* J
        }
    9 A# \- v! j- c1 C" X' B    if(max != i){//如果最大值不是父节点,需要做换位置操作
    7 [5 u+ t5 N' f- M' y        swap(tree, max, i);
    8 O$ l9 f* U* v+ l  q( _0 P: O        //此时,i节点被换成最大值了,符合大顶堆的性质! g! }3 @& e- N2 @& N- ^/ g2 x
            //但是换到下面的节点不能保证比他的两个子节点都要大/ E( i; k& R' d4 ?+ v
            //所以被换位置的节点继续调整$ D! R" ?/ k& s% _& d5 j' P
            heapIfy(tree, n, max);2 j/ g, Z. x( R% {. g/ P, M8 p
        }0 [! n, ?, R6 i+ L
    }8 w- z5 B0 m' \3 P* E$ p. |
    ! U! `8 i2 N* T& D4 z2 o
    /**6 u; S, U6 w- X7 k
    * 完整构建大顶堆% D: g2 b; v1 E! r9 f0 V
    * @param arr 用于构建堆的数组& D' [9 x; g4 E" g2 _* d7 T1 _1 o
    * @param n 堆的最后一个节点的下标8 ]: M4 }( W6 ?" H/ j0 a3 G
    */0 `- Q. @$ i% C8 B/ J
    private static void buildHeap(int arr[],int n){
    % a3 Q1 b- Y7 D) \    int lastNode = n - 1;5 Y$ B+ p8 s3 N6 J. ]* Z4 M2 L' ?
        int parent = (lastNode - 1) / 2;" F4 p% \; n, c8 N. r% x3 r
        for (int i = parent; i >= 0; i--){
    8 O, ?+ D" K1 H( M! u" g1 z" u        heapIfy(arr, n, i);
      a7 r7 A  P, d" @    }7 r; D) G5 ]' m% y  v) A; x
    }
    % Y# |0 b' \: u$ i) H  X5 J% c* @- e
    /**3 o* G' T7 G* I! i
    * 堆排序
    3 D' k1 I6 B5 e; L/ N3 a8 X" \ * @param arr 待排数组
    * X' ]% R( S  T- N6 G */
    2 R1 A) ?1 p$ j+ \6 u% bpublic static void sort(int arr[]){
    + p  s) F% h$ Y2 w    buildHeap(arr, arr.length);//先构造大顶堆
    % H! Z0 w' e) O2 [' d, E% x    //每次构建堆后将根节点和最后一个节点进行交换
    3 u6 O6 P. z* e* }0 |8 `) s    //然后砍断最后一个节点) C* \  d0 l1 f5 N! H
        //所以从最后一个节点向前循环
    " `. G  r( T7 s* ]/ m    for (int i = arr.length - 1; i > 0; i--){! A0 H+ g2 g) \% h2 |
            swap(arr, 0, i);
    ! B* A" l  x/ z2 X        heapIfy(arr, i, 0);% s, B3 b* C6 H
        }
    ( B" B$ P8 P4 N6 G( x" d! p9 r}
    8 p/ n* U+ v' c' H! {; ^————————————————
    ) G! {2 M/ F- F8 z$ S- Y0 c: Y' B版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    ! P) i6 R) @9 y9 v* u原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644
    ( z3 W9 L9 l/ L+ e  |( F5 e$ B  k6 U0 F; ]* {9 S" T

    8 H& Z6 M3 |! q, K
    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2026-9-10 10:33 , Processed in 0.460503 second(s), 51 queries .

    回顶部