QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1494|回复: 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

    - `3 F; @! e+ T. R十大经典排序算法之堆排序(Java语言), X5 l. p" u% ?2 e5 {; G- }+ q
    文章目录6 v1 B( G6 b( h- f6 X1 N! a

    7 @" B* |2 U$ U什么是堆
    " A. g. J7 t- i如何进行堆排序呢9 [$ d, ]- p$ ^; X+ ?7 w! A% \' Q
    用数组构建一个堆. U' C3 f8 `! _" W* Y
    上代码1 |* Y& t' F3 g! V4 [/ e
    什么是堆( z. V- f, u6 {1 B+ {. u

    3 z- p% K) ]8 f$ l在了解什么是堆之前一定要先了解什么是完全二叉树
    - a3 N- P. n9 k5 ^看一下百度百科的介绍% i4 r# W4 G/ o* }' X0 n/ o

    " ^- `  m) e/ k8 j4 k, a9 K: L; i# w若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
    & w$ x* x! E3 `  o6 B5 Q& _百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下% y$ ~/ H" s' M
    / }/ a& U; P: b+ H
    完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    8 N2 o' R4 c$ W3 {/ X: C1 s; u9 M(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    # Q6 O1 O8 S' K3 O- N! O' s. b(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。$ i4 m. V4 D7 B( `  G
    一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。4 Y( K4 X/ Y2 F0 T: O) C: T
    那么在了解到什么是完全二叉树之后,我们再来看什么是堆
      D, F" l& z, S堆有以下两个性质+ b: t# o# L; G8 q$ s0 w
    % [5 d* ^! _* ]! J
    1 堆中某个节点的值总是不大于或不小于其父节点的值;
    ( D4 ^3 O% e1 l' G9 c% \2 堆总是一棵完全二叉树。
    4 E# t  F6 j- O( e其中堆顶就对应二叉树的根! Y; i3 F+ b" [' A* X8 G  w+ z# h
    * |+ @3 U. u$ x! V3 F- p
    堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分
    ; k, e9 k* T; y) G
    * k4 j7 X$ U& a: m/ m当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
    - @7 q6 H0 F# `如何进行堆排序呢
    . {0 [4 @7 ?5 o, i) z; F# F1 S8 Q
      w+ {) `* D. P3 n堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的: g% `$ O" `3 _  {+ Y: Z( N
      w) ]( S; A+ {, u; E' u: u  Z/ c
    用数组构建一个堆
    3 _4 K: c8 }7 @6 C9 q* q& Z% [- l$ e' Q) m
    因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储6 x8 @+ g8 l% v. I/ X/ K
    对于用数组存储的二叉树,我们可以用如下方法来定义:
    ( e3 a$ ^& k: L) s. C假设当前节点的下标为 n  o9 w4 l$ o# B* |" v# w- f
    ! b* C+ I  G/ r8 |' W; j6 O+ {' `1 m) m
    1、那么他的左子节点的下标 2*n + 1
    ; r; Q/ P/ d& G8 W6 ?0 _2、那么他的右子节点的下标 2*n + 2; B: [" ^6 e, ^/ D
    3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1
    5 @6 u$ \' Q4 T4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断3 x9 U. X. Q+ V+ l: z; v
    那么有了上面四条性质,我们就可以开始动手了; K! Q4 z5 w/ `, m5 `
    5 {/ g! X  S- j# T& c: J9 f5 R
    1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层
    5 h* c# H4 |" g2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了- i5 V2 S& Y7 W( x
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆0 r* {0 n- g, {+ p: v( u6 {/ [+ x

    % H7 `2 _- k! |3 k- q堆排序的性质- {7 M1 Q" _9 {4 R! S1 J
    4 J) U8 s/ g5 W5 R& z3 S
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性
    * Y) E1 }% `# j2 R) e. Y+ B堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定  h7 E- i1 _* o1 {2 J, j' A+ o
    上代码
    , A0 b/ I4 e6 X" z# ~- r9 \1 Q- M# b
    /**+ J5 W% e; e$ z/ C
    * 交换第n和m个元素
    1 j) C7 J+ e& m) K5 e  Q6 d1 D */
    # v3 s* c; L' x( L) dprivate static void swap(int arr[], int n, int m){
    * W7 D# }  c% N- I1 k; j% B    int temp = arr[n];9 L- Q9 E0 u" P+ Z2 e/ N9 ^& A
        arr[n] = arr[m];
    $ B. L" Y& E  z: @* T    arr[m] = temp;
    7 a/ h& s& T" B% M: q4 p5 h}. l, A5 p4 P( z- o) B9 K& \

    , W# k2 P$ m+ O' T! o- J/**
    - H) p# q7 C1 `" D. ^ * 调整指定节点和其子节点% r) m8 ~! U. w" O# `
    * @param tree 整棵树, _# I( D* x0 O7 B/ x, v( m
    * @param n 数组长度,树的元素个数; V; Y7 K. ~7 a- Z* U# K) O
    * @param i 要调整的节点的下标! D  E  f% n0 U  ^& Y, j: v, X/ [
    */
    ( s$ Y% @6 {; _9 }private static void heapIfy(int tree[], int n, int i){
    2 N, k/ B( [  p* O% f! P5 {    if(i >= n){
    - S: |' v' j7 n        return;
    * O3 v- p1 i! q% {# R; ?" {0 y" V+ ]    }
    ' g9 \: V" b. h9 O6 o    int c1 = 2 * i + 1;//左子节点的下标8 T, M" y! V6 r% ?
        int c2 = 2 * i + 2;//右子节点的下标
    9 i  J- ]  N; p* ]" w) o6 u2 C    int max = i;//假设父节点是最大的
    , Z4 D7 K7 k, U    //找出最大值的下下标
    & N& W* M' \, ]    if(c1 < n && tree[c1] > tree[max]){
    6 X; @9 V/ c' H1 l- t1 x# W        max = c1;0 l% R5 y! z: a- s6 a" @
        }  @/ y+ w9 p- S: t
        if(c2 < n && tree[c2] > tree[max]){
    $ L6 ]$ W# b% L% R        max = c2;
    0 K! g9 G7 c. C  g" H    }+ ^& j* ?5 H3 M$ I! S
        if(max != i){//如果最大值不是父节点,需要做换位置操作
    , \/ u4 o; g5 z8 t1 i; B3 A3 B        swap(tree, max, i);
    8 m  l, C2 ^% ~        //此时,i节点被换成最大值了,符合大顶堆的性质: O% q: q7 r* `) r' t
            //但是换到下面的节点不能保证比他的两个子节点都要大
    ) y9 S+ i" Y+ g1 Q# x        //所以被换位置的节点继续调整
    % k$ ~  n1 I& J        heapIfy(tree, n, max);
    3 a" R! {! ^4 j4 e* J5 u    }# H9 _; X) D9 D$ j
    }% m* w+ v& v5 D5 n# a6 ]& K: G

    3 d5 u9 }, W* N( C/**5 t- S3 N) j) `1 }- |$ h" r
    * 完整构建大顶堆
    # @: `% h6 G3 V2 D& c- } * @param arr 用于构建堆的数组
    2 E+ C* D8 K7 B. t) k+ [0 q7 s+ @ * @param n 堆的最后一个节点的下标2 f" D7 o  }- L! `) a
    */
    8 P1 |2 L! b" `) ~& Eprivate static void buildHeap(int arr[],int n){
    5 {2 w5 r) c) Y6 o. P% ]    int lastNode = n - 1;, Z; x/ s7 R, [) p3 F
        int parent = (lastNode - 1) / 2;
    3 A- m- C! p( i# }3 W6 f    for (int i = parent; i >= 0; i--){
    + B- P  R  h! }$ ^, L- R        heapIfy(arr, n, i);' R0 \1 `' M  F/ {" j
        }4 a" g4 I* m4 U0 P8 L+ F5 _
    }1 K' }3 E" ~! g+ i8 p, A4 G/ w2 z

    2 P# ^0 m0 K3 v$ r% ]- E/**
    & \2 i9 ~2 t' {  X7 @4 ^0 V * 堆排序  {/ T; Z) q9 Y3 Q
    * @param arr 待排数组& d/ V7 d/ P7 q8 a; d
    */1 ]+ F* I+ ?, B. g1 P( s
    public static void sort(int arr[]){% @: K3 l# I" f: ]1 Z( K
        buildHeap(arr, arr.length);//先构造大顶堆% `0 a& V3 m, Q1 n1 f( q* z
        //每次构建堆后将根节点和最后一个节点进行交换
    8 a" `0 j; ~& g2 m- T    //然后砍断最后一个节点
    3 @8 a- ~- j$ `# {) V' J% W    //所以从最后一个节点向前循环% H. n7 l3 B& O5 n% `  _
        for (int i = arr.length - 1; i > 0; i--){
    ! ~& ], |) D! A* [% ]        swap(arr, 0, i);) |7 l" K  b5 A% {
            heapIfy(arr, i, 0);
    - S. r" S8 i5 m: Y- `2 m    }' Q1 D$ X/ U- Q8 L# f
    }0 Q. ~# k, i# I# D6 M
    ————————————————
    , f9 q3 G( f; O% y' D( u版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。% w7 m: k! ~+ n
    原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644
    2 {2 t/ z6 h# Y6 K  E. Y
    ) n- s( L0 h+ k* ]7 p
    $ d1 `% `( C9 q+ 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-7-26 00:02 , Processed in 0.432560 second(s), 51 queries .

    回顶部