QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1479|回复: 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
    2 y! S" G5 |/ k7 ^3 U1 E& G0 m1 b
    十大经典排序算法之堆排序(Java语言)0 y. q& o" p  o! R4 m  b
    文章目录0 g1 _; F8 m* d4 U6 D7 G' l

    & F  r: e9 i6 G0 I) A1 E什么是堆" ?  {& }9 T5 ^6 ^/ J( X
    如何进行堆排序呢. V! \$ X' w6 w. e) c+ l
    用数组构建一个堆3 B/ g" S, ]; R* |/ W
    上代码
    9 _* B* u& x8 f! ~; W什么是堆9 [( f* @+ g) N3 D3 Y- g& j
    / e+ J! W, B2 c$ c- n7 f
    在了解什么是堆之前一定要先了解什么是完全二叉树& g" l5 h  L% z$ T* J- l3 }& ]
    看一下百度百科的介绍4 N3 G# o3 B* F  ?6 S! w
    & x6 m8 v2 I' p- }4 Z6 p
    若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。, y& R9 j6 ]5 J: R* q2 N9 l
    百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    1 v2 w% d) F/ `* P& E1 L
    $ O  V2 U! L1 C$ n完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。: u7 C/ n, x& t+ I) R, h" F( [9 x2 ?
    (1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    4 ]6 [  [# `/ L6 b3 S7 L9 O(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
    2 |% E5 W7 y" }5 F; Z8 e一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
    + e3 x, X9 z* k% w8 {那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    1 Y6 S. w* Z7 W* o/ K2 _堆有以下两个性质* i& c0 U9 U: H- T# g: _8 O) G

    9 \4 B* i3 v, W/ G1 b* @. j1 堆中某个节点的值总是不大于或不小于其父节点的值;
    ! G, ]/ \. p( r7 |# B2 堆总是一棵完全二叉树。/ ]* S2 ^9 W3 P; E0 o
    其中堆顶就对应二叉树的根
    0 v! M: z$ [5 r2 l8 H8 E, k# D6 Q. p9 j1 i0 y6 @/ G* n
    堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分( N' q: E, A3 Z) r2 L( I  ^

    * q5 ^6 b  Q) J当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
    / q' x# |2 p3 H( q$ x: R% H3 \! h如何进行堆排序呢! e6 Z3 i9 k1 D1 K$ \* X. F, l
    " A) s# w0 Y% r
    堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的7 \$ N0 i2 ~) S( ]/ b2 x/ F5 A

    1 i  M0 V; W, v用数组构建一个堆
      j+ m! K* w( e- \0 z1 s0 J' s
    3 p: @$ V5 p; }8 O& t' ]因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储! M/ j* @3 h2 p( ?! ]' R. V
    对于用数组存储的二叉树,我们可以用如下方法来定义:
    7 C! L2 g8 L+ Z" J1 a* g0 P0 r假设当前节点的下标为 n
    ! Q4 ?' n* P3 ~
    ! U7 o; M. b: H, X1、那么他的左子节点的下标 2*n + 1
    # }8 y7 @! r6 C( f- N, d5 k2、那么他的右子节点的下标 2*n + 2
    9 w$ k1 d! p: D4 [3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1
    7 p8 V/ |1 [) z2 r4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断2 C2 E& E; T% E8 K" ?
    那么有了上面四条性质,我们就可以开始动手了
    . u: H0 T' N/ Y8 e# n6 ^; B5 {, N: g+ ?- s$ V% |  F! \3 n. f
    1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层1 V/ U& B2 r: E
    2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了
    # s" x. H- w3 n3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆
    ) N) Q0 e3 A, u5 U% Q0 Y0 V5 P+ X* s5 x. |( y& R4 |/ v
    堆排序的性质! W4 W5 D4 @7 F' B4 J
    1 D% t7 E' P. u
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性. b3 A2 y% Q2 g# X% L9 y0 i  \
    堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定9 Y$ o# O1 D* C$ Q* ~
    上代码- e/ A  r1 Q4 t' n
    ! Q1 x& k7 |8 `! Z. J+ ~) i
    /**4 J) U; ^! L2 s& n8 d! i
    * 交换第n和m个元素
    1 j* G( g; ?7 D; X1 ?3 y2 y */  n- Q* H# w4 w: ?
    private static void swap(int arr[], int n, int m){' b3 V- `. d  p5 S
        int temp = arr[n];/ |5 w- K% H1 y( A- w2 m. g  H! i
        arr[n] = arr[m];2 U/ L0 t- h# r4 t% I: ?  U8 N
        arr[m] = temp;) t2 J$ |+ \6 L+ ]7 ^$ r
    }8 O4 u  k- k# E# J! U; U
      F/ C+ m6 W) h' |$ K0 s1 _
    /**" s/ o5 z/ \9 L) r" a0 c
    * 调整指定节点和其子节点
    ; }3 U3 O8 ~, E  r# ] * @param tree 整棵树6 b8 h: s$ f- x1 d6 O, O6 |9 _
    * @param n 数组长度,树的元素个数! T  q& [! h2 R( e& p
    * @param i 要调整的节点的下标
    7 z% m3 x1 @( Z9 m. J, ?5 L */3 \! }+ Y* P" E' p" f
    private static void heapIfy(int tree[], int n, int i){4 O/ T$ p8 q% g& K/ g! k
        if(i >= n){+ b8 b* J; B7 Q
            return;
    6 x' \# F3 ?% C& V) k2 Q2 ?- s+ l    }- @- e  k) N# `* z
        int c1 = 2 * i + 1;//左子节点的下标
    7 U7 G1 U+ H; V2 m  @1 o- L    int c2 = 2 * i + 2;//右子节点的下标& A1 }( o" s  G7 T/ b8 V
        int max = i;//假设父节点是最大的
    9 G7 K, [$ u  ^0 E) V  K) B2 P3 V    //找出最大值的下下标1 F$ G+ t3 u6 G" u" X1 \$ o" f
        if(c1 < n && tree[c1] > tree[max]){
    3 S. f6 V. o, r- p/ L        max = c1;
    , l* v* E! n; E1 A# Y    }" @! Q5 G1 g+ J% |6 f
        if(c2 < n && tree[c2] > tree[max]){  }) L( A9 b3 Z- c8 ?7 ^
            max = c2;
    ) g2 `/ C2 i9 y+ W/ O7 N$ Z    }
    5 M; F! h! E0 _! Z5 v1 V    if(max != i){//如果最大值不是父节点,需要做换位置操作
    ! U: z1 [& g! q' |/ A- ^        swap(tree, max, i);7 k0 R( Y/ m# P
            //此时,i节点被换成最大值了,符合大顶堆的性质9 A, O" ]. L, Q, V" ?& U" Y
            //但是换到下面的节点不能保证比他的两个子节点都要大( C9 }. K* ]: T/ ^9 I% N9 R, a6 x
            //所以被换位置的节点继续调整2 H: N9 L* D) d( @: `1 {
            heapIfy(tree, n, max);
      S0 n8 W0 I8 n& D- l3 c! R    }
    ' I5 ]% T4 R, i1 r8 ^}
    ) ^" s7 b4 u5 x5 N7 C. R. E& Z5 D3 K) p8 A5 H% |* R
    /**
    # W+ p; n: |+ F5 q * 完整构建大顶堆
    0 B( e2 B! C' {+ t+ O8 Z * @param arr 用于构建堆的数组$ N6 v! i" s  t1 g! C9 J- c! X8 ]
    * @param n 堆的最后一个节点的下标8 n" N7 [/ i  o# A" D# m
    */1 P& J7 o* M3 u+ {* }1 a
    private static void buildHeap(int arr[],int n){+ [% U/ M7 s3 G! C0 A, n3 r3 h
        int lastNode = n - 1;( F: k% u8 u0 [" A) `4 h7 [/ K. j
        int parent = (lastNode - 1) / 2;* M$ e3 |7 i( L) Z0 U
        for (int i = parent; i >= 0; i--){
    - v* P5 b4 [" b' z        heapIfy(arr, n, i);' \" L3 ~4 G# Q
        }2 c. h# N: m4 e* p* \
    }
    $ Y5 v1 {* w- y5 x$ o. Y  N  v6 ^1 Q0 B3 d" F$ S
    /**9 R, u! G3 A2 k0 t+ t" o+ y
    * 堆排序  C+ J: N) `& R, e
    * @param arr 待排数组: l. g0 d( c1 m7 n% ~8 A
    */
    8 U" q3 e3 j' z: M# Qpublic static void sort(int arr[]){
    , q5 A1 ^8 o: {4 A7 p' w1 j+ _    buildHeap(arr, arr.length);//先构造大顶堆5 O, i0 N8 p2 v+ f- x$ K2 h
        //每次构建堆后将根节点和最后一个节点进行交换
    / x) w5 @2 |/ j( b: _2 U    //然后砍断最后一个节点; X# K. q% S; c
        //所以从最后一个节点向前循环) E' T! ^# q3 }% }8 i& x
        for (int i = arr.length - 1; i > 0; i--){
    - \' [0 h$ x6 [9 v/ q        swap(arr, 0, i);- F& s, `5 ]' C! P- U2 z2 z
            heapIfy(arr, i, 0);; }" n" A5 @$ D8 q
        }
    5 r! r; S; [% I# C7 s+ J/ H}
    7 M9 b+ w1 Y- Y8 f# {4 q9 W————————————————7 [2 h/ j$ N( ?9 I+ [$ T; U: I
    版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    7 H, ]6 ~. ?; U2 I" z2 C' H8 Y% D原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644. r2 @6 l4 }  M# r! Q
    % ]7 [/ z  _; X8 h( s/ V, ]
    * a% n" J6 ^- N" Z
    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-6-10 04:40 , Processed in 0.390032 second(s), 50 queries .

    回顶部