QQ登录

只需要一步,快速开始

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

    5 ]' k% m3 [$ y5 E4 V5 e$ E! H十大经典排序算法之堆排序(Java语言)
    - u9 D6 g# Y" F; u) k文章目录
    0 y+ `# l. X9 L1 p* n4 ~/ q; E2 g, C' Z+ |8 p+ m1 `
    什么是堆1 T8 }0 k; V/ a; _% s/ K
    如何进行堆排序呢3 P. G; A. z- Q# |  t/ _6 P
    用数组构建一个堆
    3 P9 Q1 S5 y* b( ?上代码& r7 D! d1 @* [& r6 `% o7 i
    什么是堆4 r3 d7 u9 E3 i. M
    : g& T1 F, G  f! d0 ]: Y' Q4 t
    在了解什么是堆之前一定要先了解什么是完全二叉树9 {6 s, F( }5 G8 q! U* S4 C
    看一下百度百科的介绍
    2 l, k6 F8 a- `- g' |
    / l9 T/ o, ?3 q. M若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
    " e) o& b6 V+ l8 z1 P百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    3 }7 K4 {0 v9 K" K
    : v; R; r! f+ S4 z2 t' Q完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    1 |0 O" N' R: q! O1 W0 X3 P(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    + N8 {, e7 U+ K+ v( U0 z' t(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。' b4 p3 D1 t3 R: K: o+ x  s
    一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。3 |* n: \8 h  n
    那么在了解到什么是完全二叉树之后,我们再来看什么是堆- z7 `; b8 z) ^+ J: k) {7 L% r4 n
    堆有以下两个性质
    3 G+ d) L2 B5 W, x4 @
    : I0 J8 [; H! n" `( g1 堆中某个节点的值总是不大于或不小于其父节点的值;2 X* R( y6 \" k5 R$ E4 Q
    2 堆总是一棵完全二叉树。
    & v' ?" ]! p5 v9 j- N! h5 t其中堆顶就对应二叉树的根
    % f7 C# U0 L& ]) L) [# L/ ~
    ! J7 p1 C& p( l# {  b堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分
    ' ^% ~4 X- k& O
    3 v0 ?, f5 _* D) {6 H当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
    % E1 H+ `; [4 P3 m; `如何进行堆排序呢+ t4 j5 s4 C% u( O7 m. ?  G
    4 }  f/ W9 T$ M; Y
    堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的
    8 K0 l8 j( y' j% o" k' T7 x  c9 p
    $ @/ L! V) h) a: G3 K. M+ P, W用数组构建一个堆
    / M) q$ W' ]1 e6 E7 \) B3 X8 O9 S! f
    因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储
    3 h7 f: G/ g8 a% q对于用数组存储的二叉树,我们可以用如下方法来定义:7 s% o/ @2 P( D+ k6 T
    假设当前节点的下标为 n2 }& f1 M' J+ a$ }, x" a8 l/ M, b
    $ j) j  ]9 ]) C% H$ M( H) A
    1、那么他的左子节点的下标 2*n + 1
    3 s9 S, k# }# S# l2、那么他的右子节点的下标 2*n + 28 z! Y+ W. R2 x& c3 K
    3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-11 }" f# e1 Z$ O' n0 J& b
    4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断" x3 o2 V7 H5 W. M2 {" _% z
    那么有了上面四条性质,我们就可以开始动手了/ @( i; y8 m- X/ z9 m

    ' d8 x. F9 ]/ q* u! U1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层/ n# J! G4 u. R, k, v9 _
    2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了
    & d& R2 w  O. s2 b% y3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆8 R' `0 j1 X$ f. a
    / p" H- e6 W4 b4 K5 K6 W1 J. w3 W9 i
    堆排序的性质/ c$ Z" y: t1 T' G, q! F

    ! A( I% v9 P! }7 ~: W; x中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性* v- X  V$ s* j1 c# b
    堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定- X0 p/ U4 T/ \  W) P
    上代码
    4 @- i0 D4 h& O0 X1 g0 s' u6 z. k. N2 y( h0 y
    /**% G! q  {+ c: Q% l
    * 交换第n和m个元素$ l) O- w. S1 g- f4 m4 p( D4 X
    */' T1 E5 _4 K7 T4 V& k
    private static void swap(int arr[], int n, int m){
    * t; m2 q# X! _! E! \1 ~    int temp = arr[n];
    * C1 R1 u1 ^9 l4 z9 l8 n! W    arr[n] = arr[m];: W1 I! ?, x  b* x/ ?# o
        arr[m] = temp;
    # C* E7 e% u2 G$ K0 K2 Z& C}7 L/ k8 Q! {# W* z7 i: L$ v9 A0 K

    - l! S( G1 o* i! v; `$ G7 k/**5 X3 Q6 x! s+ _) m
    * 调整指定节点和其子节点! d1 g' _1 p: a" D( n8 O3 P
    * @param tree 整棵树
    ( ]% L" [  `2 d, ^: e/ ^ * @param n 数组长度,树的元素个数1 {- w2 s% b' D  ?# x+ q0 j
    * @param i 要调整的节点的下标0 g7 u  I' U+ x2 i. h
    */8 _$ k* R$ _7 I7 M$ w% a6 x
    private static void heapIfy(int tree[], int n, int i){
    " Q8 e, f6 y! K    if(i >= n){
    : @$ f  i$ L2 z. q7 a        return;  P. Z% V- s+ ^9 M! `; D% k) G6 P$ Y
        }
    7 s( c3 M- S# R( @# J! @    int c1 = 2 * i + 1;//左子节点的下标( Z* X3 P0 P7 T
        int c2 = 2 * i + 2;//右子节点的下标
    % n; \- ]# z9 @7 L& j! K+ E    int max = i;//假设父节点是最大的$ j$ F* q8 j( d2 l9 t
        //找出最大值的下下标
    & ]4 t) y0 `) \) R9 M    if(c1 < n && tree[c1] > tree[max]){
    ' I; p( G6 M  @8 P        max = c1;
    8 ]5 i& o- L! J    }7 Z1 d( ~, K  ?) n9 g4 g
        if(c2 < n && tree[c2] > tree[max]){
    ' p& u  s% R0 i; D/ w$ P        max = c2;! o2 i+ p, h! @4 G, R
        }
    - J* ~/ y4 A* o4 m% s    if(max != i){//如果最大值不是父节点,需要做换位置操作
    2 h- P) ]% q$ p6 F" V8 ~        swap(tree, max, i);
    ! {. \$ X+ V, H1 b6 V        //此时,i节点被换成最大值了,符合大顶堆的性质* u+ G* L( ^: r, d. R
            //但是换到下面的节点不能保证比他的两个子节点都要大; Z& X+ @% b6 F% ]/ o
            //所以被换位置的节点继续调整
    9 b! T; R' o3 l/ J/ X' O        heapIfy(tree, n, max);) u" ?* e+ h& M. |" W5 b
        }
    ' j' H: ^+ U' ]* N" J  i}6 R9 ]+ V$ S5 w- f' [7 X% R

    6 V  \5 ^* J9 M/**
    $ ~! y& ?0 @5 j5 T* f  s6 k0 ~8 k * 完整构建大顶堆; M, U4 i' ^" i( E
    * @param arr 用于构建堆的数组
    * h6 t$ `3 }" o" y  E, ^/ z * @param n 堆的最后一个节点的下标& ]4 u' o3 h: X; t  U- @
    */
    - M# g( [) M, m2 d1 y$ {& t0 W# f# tprivate static void buildHeap(int arr[],int n){
    9 M% B: X( Q6 q' Y5 |    int lastNode = n - 1;
    ( f& ]4 v3 E2 Q6 i) \    int parent = (lastNode - 1) / 2;5 k  K) I9 S" |) Z6 i# k8 i
        for (int i = parent; i >= 0; i--){7 _$ m' Z, e: w. n- K
            heapIfy(arr, n, i);& W" Z: `" Z4 ?% `' q' \9 [  S4 i: g3 K* v; O
        }
    6 q+ P) n7 ^% \3 W% H+ U}  k0 p) N9 A/ m0 q$ a  i

    $ T% Y9 g( V1 _5 `: ^/**
    ; W8 C, a6 \" y% F, G& T5 x4 h/ A * 堆排序
    $ y( q' m/ ]# P# g9 ^& r * @param arr 待排数组% T* Y8 c) G/ Y1 b/ R
    */% |% Q6 {% E% V$ i
    public static void sort(int arr[]){
    7 t- _5 Z4 e1 p    buildHeap(arr, arr.length);//先构造大顶堆% q9 H3 I9 d7 _) b
        //每次构建堆后将根节点和最后一个节点进行交换$ |0 ^' O; Y( C- N5 j
        //然后砍断最后一个节点
    5 `) j9 Y4 a4 z+ W' R% |    //所以从最后一个节点向前循环$ ^7 q; j' Y8 ]
        for (int i = arr.length - 1; i > 0; i--){
    7 ]4 X+ K! u" Y! v$ F$ l( [4 e        swap(arr, 0, i);; X+ p' b8 I" ^! F" i9 l& r
            heapIfy(arr, i, 0);: U8 D0 t; \5 T3 O/ N$ l
        }
    & ^& t, M/ F1 u" M}, ^4 I% |! }$ @7 [
    ————————————————
    ; N% C- P; f  d- w) a  Q版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    4 n: v/ d5 m- z3 j  R- [# o' A5 P原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644" S5 S4 Z; S) n$ `2 q' g8 V4 q
    ( N( t) z( K% ?! E5 L

    3 q4 L, E8 G2 m7 x1 v. 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-6-9 20:30 , Processed in 0.413231 second(s), 51 queries .

    回顶部