QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1448|回复: 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
    / W) C7 f/ f) |2 t: d) W( p
    十大经典排序算法之堆排序(Java语言)5 f* }4 D4 x1 W
    文章目录+ L# m' N. K& n; o6 i

    5 y1 q3 W, n. h5 x1 ~% X7 ]" @什么是堆# ~! _( q/ p) N, I4 M$ u$ N
    如何进行堆排序呢
    ; E* O% i" n$ @. x$ e/ x$ {2 c4 T用数组构建一个堆
    / `3 R# O( ]$ p, E+ @7 ?上代码
    : ]  ^7 v/ M% X# x) B什么是堆/ D/ I# J% P4 n/ z

    + G) [# s# F4 o0 {4 x3 K, e在了解什么是堆之前一定要先了解什么是完全二叉树, k" U4 H$ j) _
    看一下百度百科的介绍$ O6 V# t9 v( q# w3 n/ t3 I

    & k. S6 E8 ^' F) R1 |若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。3 O3 Z# D1 d( b, x5 }
    百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    % N; F, h: s4 q7 z4 U+ _, y+ V$ T. Z, H
    完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    2 |$ Y: P- N2 p(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)1 F1 S6 B0 M7 D
    (2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。  g0 h+ L$ Y; M, B8 n9 p+ u
    一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
    8 w6 D$ I$ g6 C. Q那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    ; i7 K* h  W7 g6 X) v, h# ^8 c堆有以下两个性质
    / r5 d- u/ j* X7 H/ W& A. O$ w$ {' e6 n. h
    1 堆中某个节点的值总是不大于或不小于其父节点的值;
    4 J/ i: U  P2 N7 R! ^0 e3 I2 堆总是一棵完全二叉树。
    ' B2 h! }4 |  T9 ^* l8 U其中堆顶就对应二叉树的根
    ) _* M: s) e' J2 B5 ?& T% Y4 \; h; [
    堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分
    0 i. X: i: C+ @, x/ l$ K2 j) g& P: S' D* C) K
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆* T& f7 [* ]0 R# c
    如何进行堆排序呢9 R8 f+ j; X5 B7 W" i# x

    - E, G2 U: S2 D+ M堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的8 c/ m! e1 [% U

    * R" L" S) e$ C+ v7 e用数组构建一个堆
    ; b  x+ p) p% I; _; J, i) W  K1 u# |( H" i& Q+ s1 {
    因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储
    6 a6 H/ ^7 n, _' N( K* y& t对于用数组存储的二叉树,我们可以用如下方法来定义:
    4 W6 D' Z/ Q. P( a! U假设当前节点的下标为 n3 I5 ]) g) y  G. u' `+ k& o

    # ]+ h( n- u3 ]' u7 N+ ~1 i! M1、那么他的左子节点的下标 2*n + 1% Y' b: ^/ y& ]% W/ _6 Y
    2、那么他的右子节点的下标 2*n + 2
    " `' h( L9 v2 s1 |4 g: `3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1
    1 K: A8 P6 [6 y! ]0 T6 W4 u$ q4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断* N% g4 t9 P6 r0 @
    那么有了上面四条性质,我们就可以开始动手了
    ; m+ R9 R8 M1 M3 e" S8 k/ n$ a3 A: a+ N4 Y. ]
    1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层
    & ]6 k/ ^+ F/ ?/ Z4 e5 t. ]" s2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了; M2 a( W6 @8 t2 X
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆1 T  ~) M- C3 b/ E- |% B* c) m
    3 c8 ?/ o& p$ ^6 i
    堆排序的性质
    8 u, @) B+ }1 W4 V1 c- M. r) B% t5 ?6 U8 e" Q6 u+ C8 j
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性0 r* l- S* n# ?
    堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定
    ! a& O# i1 \% R0 A8 J1 u, r0 U) t! X上代码
    2 r8 C1 Y# L& w5 ], Y) P1 C/ f7 i0 i/ b* Y
    /**
    1 ]# S* {& h" a) o * 交换第n和m个元素* j1 f( `+ ~8 n' \8 a  e+ U
    */8 v/ H! V6 ?9 i3 ?$ |0 \: X* i# N4 X
    private static void swap(int arr[], int n, int m){
    0 a3 E- o0 e' @, m$ B4 N& e    int temp = arr[n];
    $ L7 E+ {, G  r7 M2 p7 {- x  l    arr[n] = arr[m];& {2 z0 V8 y* b, i5 h2 K7 q' c% I
        arr[m] = temp;
    / N* |8 @# Y  n/ e5 H1 \}& W1 e. q$ Q; y2 |- T3 T

    1 p8 |2 ?- B# |5 Y- d8 U  G/ L/**8 `: B7 m6 E. U! P& ]
    * 调整指定节点和其子节点" S9 C3 }: a' o/ e+ z; Z2 z; l2 Y
    * @param tree 整棵树
    # f" h! S0 i4 i6 d0 Y/ F% U! t * @param n 数组长度,树的元素个数' S' y2 O2 X" Q( `
    * @param i 要调整的节点的下标
    7 i) ~9 i+ d) v */4 e, \9 w" W, Z  X
    private static void heapIfy(int tree[], int n, int i){6 V. L! r8 w7 B) Y, N" m8 U
        if(i >= n){
    0 C5 ~- S# T" c0 o; x% H0 J% m8 F        return;
    , L6 Z) Y9 m' i6 k    }
    1 o& F# ]$ [! `& F/ ]. B7 N8 J    int c1 = 2 * i + 1;//左子节点的下标
    # p, x% `: T: Q- L    int c2 = 2 * i + 2;//右子节点的下标. c% f1 L- R& H4 a- v$ }
        int max = i;//假设父节点是最大的" P0 ~# z" _6 J: }( U
        //找出最大值的下下标
    0 z7 q, ~. y! G8 X    if(c1 < n && tree[c1] > tree[max]){% o! D% ?8 i. L( [3 ]# c2 U$ T
            max = c1;9 R. V  C( d4 @1 M) W6 k5 c* B# l
        }" N  G* g2 I$ [
        if(c2 < n && tree[c2] > tree[max]){( x' a4 c: h& e3 K! a
            max = c2;
    ' p" X. f9 @+ [; z$ Z$ D    }+ R+ e7 M& E* V  x" W7 u7 u* M
        if(max != i){//如果最大值不是父节点,需要做换位置操作1 p6 t9 L: `. K8 V+ I) _
            swap(tree, max, i);: L# @% o' Z! k- O. m
            //此时,i节点被换成最大值了,符合大顶堆的性质# d6 g& |; M" S
            //但是换到下面的节点不能保证比他的两个子节点都要大
    9 I  S7 P+ k1 ]$ Y& Z        //所以被换位置的节点继续调整5 P( b2 t0 l0 G
            heapIfy(tree, n, max);; Q$ U1 G( u- x! F8 p
        }3 |* w% d1 V& U/ ~. j/ n+ o
    }
    . Q' h* c  q- K  f  ]( |
    & x1 c8 I  M8 S- [! G1 b7 f( Q/**: D/ J' L2 x% A9 o. M  {
    * 完整构建大顶堆
    & b' g8 ?( C+ }+ P2 c4 H3 N2 O * @param arr 用于构建堆的数组
    . C% S8 _. J: X, Q0 [ * @param n 堆的最后一个节点的下标; C/ Y, v  ^1 l1 D( I8 e* b
    */! @3 A% p) {, V1 W! l. q
    private static void buildHeap(int arr[],int n){
    - R1 I" g$ ?$ R' E, D* i, J    int lastNode = n - 1;
    7 o2 A' _+ |4 N) G. P/ ^% U$ R    int parent = (lastNode - 1) / 2;
    0 I- {. R3 {" _0 i/ c2 a; o  b4 n    for (int i = parent; i >= 0; i--){
    ; H* b% L, v0 i( T) B        heapIfy(arr, n, i);5 V8 o" Q1 _) Y4 b( D1 `
        }
    * W5 n8 ], w7 l}
    0 Q: A* I6 q3 g& H2 @8 M
    2 N+ i$ n0 r, X4 B/**. K! Q7 g2 B- F
    * 堆排序
    ; X4 c$ {4 w4 p* z * @param arr 待排数组/ u8 R1 @" A7 \  {
    */# d+ F5 n# o/ b+ v6 ^' R( o
    public static void sort(int arr[]){& E2 G/ p0 m6 G1 g4 V0 g
        buildHeap(arr, arr.length);//先构造大顶堆* w8 z) ~; [0 i2 y6 g) d0 |- `& D
        //每次构建堆后将根节点和最后一个节点进行交换) |7 v9 B( [. j% O3 N! n* |' U& e
        //然后砍断最后一个节点4 ^: [  w% F8 g; p8 I) ]& P! b
        //所以从最后一个节点向前循环
    * a* N/ R# p9 i8 h5 X    for (int i = arr.length - 1; i > 0; i--){
    + T. u: {; N4 r: Z' F        swap(arr, 0, i);4 ^$ T8 r# Z* W, h1 S# C) k
            heapIfy(arr, i, 0);
    / n; ^+ s6 \1 ^  x2 o" S4 z    }
    & @! F- {; o; M, z5 Z4 G: e}
    7 @, S8 U- `1 R6 U& ]————————————————7 R* Z! l; H* |% N7 A) G' a# f
    版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    : u% e  W( _6 q原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644
    ( i" y% s: N8 T
      _( M0 F6 \8 C
    # V  [  L" R- B, J$ h! H
    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-4-21 22:49 , Processed in 0.463007 second(s), 51 queries .

    回顶部