QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1473|回复: 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
      a. V! E) `  x  _/ X
    十大经典排序算法之堆排序(Java语言)
    2 a' X6 p* b" V( A' k文章目录- `8 o9 W2 E- x2 G( ^/ ]
    & {1 Y; _& ]! |: S# ^9 ~
    什么是堆7 Z8 }7 O3 y( c- g* I7 K6 R
    如何进行堆排序呢& V  n. p  I) r/ s# E. G& q
    用数组构建一个堆" ^  Y7 p* N  {  m- G
    上代码
    / s! h; O) Y: O8 @, \3 \什么是堆
    3 z2 r2 i6 ?. f, N% `! R+ g' e. y
    , x  E7 {4 {) x' c在了解什么是堆之前一定要先了解什么是完全二叉树
    + o6 {3 v$ M! |( E$ j! o5 O看一下百度百科的介绍; U* n0 L) J( ^( V* }) ~5 M
    8 o0 `0 ]/ J2 `2 y( ?3 |2 Y4 U: k
    若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。9 M' H: M) C4 M3 f6 s  T
    百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    0 w. s5 J4 X4 R" N/ J
    5 V4 P+ J$ A5 b- V2 j. L+ N完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。# e1 g! R" n3 ?- m6 R
    (1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    9 w4 K1 d) w& u+ P" I(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
    8 l0 H  {2 t3 Z( S5 F; ]一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。0 z2 c; ]  x+ r0 S; f
    那么在了解到什么是完全二叉树之后,我们再来看什么是堆" w" b3 r& o4 U  P- V
    堆有以下两个性质% z. Z6 Z' _0 w4 M; M0 y4 ~& F& r

    $ G0 N9 g6 u& d% N& b, F1 堆中某个节点的值总是不大于或不小于其父节点的值;
    6 A& ]2 G6 I1 D0 D& L2 堆总是一棵完全二叉树。+ @5 ?# U- ~& F, g3 P/ e; R0 a
    其中堆顶就对应二叉树的根9 T; M4 B8 v# H

    / J3 M  ]2 @1 w/ n堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分
    3 a, o2 E7 I: H, U8 O. h% d1 f9 x
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
    ; S0 d, U& j0 ]0 L  S如何进行堆排序呢
    6 m  x! ~6 _$ w/ ?0 ~
      ?  p* X  a& x. R4 \堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的
    3 j% }: K- U( D
    2 ?6 L' ~* R# w* l- M: V1 ]) `用数组构建一个堆4 i$ {8 N2 z3 v9 \0 l$ l

    3 k' ]( R& c6 Z& I  M2 t3 C因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储% c4 c9 `% ]- p( l+ d, p
    对于用数组存储的二叉树,我们可以用如下方法来定义:8 O3 I8 t/ O2 T
    假设当前节点的下标为 n/ g! {+ G: w: J% V) R

    4 D- y4 T0 u6 F& A1 {6 J8 g1、那么他的左子节点的下标 2*n + 19 ~3 v# G% I  v
    2、那么他的右子节点的下标 2*n + 2
    * @; }- k( ]  `- @2 M- h. V( M3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1( {3 a2 ^# e( f4 [/ D8 m
    4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断
    - c! Q4 r2 C& ]1 d$ \4 {( ~; {那么有了上面四条性质,我们就可以开始动手了
      c& V; `  R, ?2 G. V* c" v, _$ L$ v7 y3 r  I( e
    1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层
    + q9 M( z7 d/ Y! R( f- c$ r2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了5 x9 L  E- B) w( s) e# C
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆
    ' F9 L& v* L$ `9 p  j* W+ d
    & |; p& u7 P7 r- A) |堆排序的性质
    7 `/ q6 h5 y' b; D5 s7 k4 d) M0 v% L8 i+ c& x
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性6 T$ N& O: ]" @( G7 ~- k
    堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定( s5 \$ _' Z4 L+ N
    上代码
    $ I) c: S$ b: g1 ]5 Z# O+ v9 x8 w0 q; o7 T
    /**( s4 b- J) N4 b& J& X0 q3 F
    * 交换第n和m个元素1 G$ w9 Q& j% J
    */
    " z( [, W! Q3 S- T( }7 |0 o2 Fprivate static void swap(int arr[], int n, int m){
      ?8 C5 w8 A% l$ w    int temp = arr[n];
    : Y! S0 N  B0 N7 ~- k$ t    arr[n] = arr[m];' H* c5 ]$ j; @5 |
        arr[m] = temp;
    " `4 f! ^) d" s' a& f# r}
    7 h) b; D; Y6 E- d" t1 H+ K2 q% z6 r1 d2 \! S
    /**: z, C" R. u9 o; {+ P9 z9 W+ M
    * 调整指定节点和其子节点
    # @7 ~! w# O/ n4 } * @param tree 整棵树8 m4 R, ]4 v$ z$ w
    * @param n 数组长度,树的元素个数5 ]+ {: q% [& t+ c. `
    * @param i 要调整的节点的下标
    / x0 C( \9 q( \: | */
    6 C2 }+ b3 x2 v2 x1 l1 q% yprivate static void heapIfy(int tree[], int n, int i){
    5 y8 j" D8 y0 C: Z& a1 E: Q    if(i >= n){
    ( o: Q# n  k" h+ q+ N, u. {; w        return;
    . o* a# L+ s5 q- a    }
    # F" r- U6 O6 T    int c1 = 2 * i + 1;//左子节点的下标) ^  X& Q" `1 q" u0 c+ `( U  t' n. @& @
        int c2 = 2 * i + 2;//右子节点的下标+ K2 H& p+ v0 D
        int max = i;//假设父节点是最大的' ]8 R  L$ N: v
        //找出最大值的下下标/ m% Y: s6 }3 q
        if(c1 < n && tree[c1] > tree[max]){
    3 f  k( G; {. F( {        max = c1;( G' N- t; j9 a9 O
        }6 x; `3 c$ K; u% Y' n7 R6 u
        if(c2 < n && tree[c2] > tree[max]){
    4 \5 t1 R: P6 V( w( Q        max = c2;' |  @1 x& a/ d0 S9 @
        }
    4 B, n1 l8 D/ c2 P# U+ O* S    if(max != i){//如果最大值不是父节点,需要做换位置操作
    . W; I% N6 {9 v  c+ V, S        swap(tree, max, i);
    . O- w8 k; T( T: |        //此时,i节点被换成最大值了,符合大顶堆的性质
    0 s' t6 P6 G* F  x5 Y        //但是换到下面的节点不能保证比他的两个子节点都要大
    : `  S9 y" L* D. i& A        //所以被换位置的节点继续调整* N$ s) K6 z1 p* _% {. L
            heapIfy(tree, n, max);9 h. e# D: P) i8 r
        }
    8 w# _1 g* q! F% @, x0 h}
    ( i; L! l$ _5 U# O9 L; T; I  L# `2 l8 E4 ?) a: E: z: ~
    /**2 w& a9 ~. l+ M7 |6 f
    * 完整构建大顶堆* U- F$ u7 E/ H  c7 s; p
    * @param arr 用于构建堆的数组
    # e% r' W6 l3 y6 s7 b8 `# o% U * @param n 堆的最后一个节点的下标
    ( `+ l2 o* [# S3 o1 r0 J */
    ( U; x, x) ~" n$ s3 ~: eprivate static void buildHeap(int arr[],int n){& Q6 ~: F' L# |& I; f0 n
        int lastNode = n - 1;
    : N- u& d2 j2 W: N    int parent = (lastNode - 1) / 2;" v3 O8 o* J$ M$ W
        for (int i = parent; i >= 0; i--){& S% ]4 L% Y9 j& T/ D! v
            heapIfy(arr, n, i);! M% B% O+ q8 l6 I
        }
    ; d  O5 I- v& O, B7 L}
    , ?" g: S9 V3 J) z' I. P
    ( \. G/ E) Q+ ^/**
    + V6 q0 n# F$ S! L  d* l' J% | * 堆排序  q* M: B8 s: `4 u+ q4 x9 c3 O
    * @param arr 待排数组* X/ Y8 U4 T( f) k
    */
    - g1 y( c6 i+ b$ Q/ kpublic static void sort(int arr[]){( h* J% V, z+ h/ _- X. H
        buildHeap(arr, arr.length);//先构造大顶堆
    + a, v/ q2 P. r0 H, t    //每次构建堆后将根节点和最后一个节点进行交换- I+ m+ Q' |4 S0 C8 a  W
        //然后砍断最后一个节点
    ! I4 R0 c. _' ~$ j7 `    //所以从最后一个节点向前循环0 d- [9 n1 r$ r7 Y' z
        for (int i = arr.length - 1; i > 0; i--){
    * f/ O8 B9 E) _% Z  F        swap(arr, 0, i);1 S; {( }- [! V
            heapIfy(arr, i, 0);* A* X3 c9 s3 l" s3 Q% B- G1 H
        }
    & e0 Q9 s. C- y# i1 f8 N}
    ; ~: s! w# Z" k8 Q* v+ K————————————————5 K5 M* q. k+ h& W; s+ F; w4 z" E: X
    版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    " O& {; H8 l7 ?6 g0 O2 j5 {" V' B原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644
    9 H8 t+ s3 B1 B8 Z+ l& }+ s$ h3 @& U: m6 c% G; }; v6 h9 o( v
    + c# u* Z  {0 q5 i8 l- F
    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-9 20:04 , Processed in 0.298946 second(s), 50 queries .

    回顶部