QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1444|回复: 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
    ) }) J: Y- @) ?6 N
    十大经典排序算法之堆排序(Java语言)
    % ^" o! }/ q' W文章目录" r' ^! S  w6 [& R9 X( F" ~% h
    * S) }9 R1 I3 V
    什么是堆, c( ~& q  Q% L- @* o5 T+ p
    如何进行堆排序呢
    0 c8 n  P/ C' P% |0 R1 t* v. B用数组构建一个堆* K- Z( G1 F+ p9 P5 S
    上代码+ X, ~+ r" V6 H
    什么是堆
    5 J8 l% @. g  B& ~& }) x6 \4 s; H( N0 G5 g
    在了解什么是堆之前一定要先了解什么是完全二叉树( P# }3 T% L& J* E1 w( h/ R
    看一下百度百科的介绍0 g) ^2 w7 ]3 W) d

    7 m- [& h: l( b+ y若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。8 ~% U) {$ a4 g* ~/ [& G
    百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    ' N2 r$ N4 L1 H; E3 Q0 M7 Z9 d0 d1 G1 H$ H; I. {# _+ [6 w8 ~( s
    完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    0 G& K9 i0 {- c4 F( t9 P1 ~(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    8 b8 o5 z: u; B" q' a2 G8 j1 o(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。; u; M8 p; F5 X0 P( m: q
    一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
    # F0 j  `7 M1 y3 F0 P那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    % V6 u; h: v0 ~2 ~8 T& ~# u堆有以下两个性质, t( o1 ?/ T- O2 Z9 L. _; q

    - \' C2 h, t9 Y" o: G% T* N1 堆中某个节点的值总是不大于或不小于其父节点的值;2 w+ O4 Y* z& j" c1 L" o( t" u
    2 堆总是一棵完全二叉树。" S+ N! |! n# {$ Y
    其中堆顶就对应二叉树的根
    ( E& {; X, C" b0 Y2 G6 B- Z; R
    ' j1 e( H! J5 r2 {堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分
    4 p8 Y5 C6 K/ f# F  A* t7 m' F/ d9 j" J6 T6 e$ b! }' o! w, T4 R: O
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
    9 e0 N6 W5 y# D) s如何进行堆排序呢* H0 O7 [- O% c5 n3 n/ r
    8 m  t: ^, Q, Z" B5 ^
    堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的2 w" E7 @  \; r- d

    $ C6 y: @8 z# L2 A  `用数组构建一个堆
    2 w2 Q) [- n: Q  \5 |7 T3 x* y
    2 O& n- j, d. X0 O因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储' t; \% v, Q4 M9 w
    对于用数组存储的二叉树,我们可以用如下方法来定义:
    + x" `; s& m9 B6 [& c5 t5 S8 v6 D假设当前节点的下标为 n
    * `  @: c2 U9 M2 ]+ {! s5 J4 }* I" R. ]! \  M( [
    1、那么他的左子节点的下标 2*n + 1$ q/ e1 T8 z3 ?+ m
    2、那么他的右子节点的下标 2*n + 24 R, ^4 i" V7 s" R+ @2 K5 A
    3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1
    8 m$ m  s' |) O) G! j  n6 Z' ^5 W, b$ q4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断/ i! V. I0 M* u* S- E. W4 t
    那么有了上面四条性质,我们就可以开始动手了2 b- ~* M6 f% _+ P) J
    ' {8 _; s: v, F) P+ `3 }7 c
    1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层
    ' S( ~9 S! P- U2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了5 P0 v( I1 h! \, w+ c+ i
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆: O3 z1 B) M4 q; Z% Q  a5 h

    * Z4 {6 L7 J: w* C堆排序的性质
    * e# j  U. ]$ C" C
    7 b) L- o  b# \2 `中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性; p- n; h" i$ l- Q" e/ y7 q
    堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定
    ' f0 J$ M5 u' t5 w- Y! o上代码0 \, q* T5 H# @) K0 t

    : H! N6 B$ J  \7 ~: M/**# X9 E. E: h$ s/ b: c. v7 K- }! U
    * 交换第n和m个元素4 c6 v8 o6 ~# n0 M; g0 r
    */
    0 N: `' {4 D3 N* Nprivate static void swap(int arr[], int n, int m){1 q' S' y) E/ `
        int temp = arr[n];# C9 M) P, S( w1 o# m
        arr[n] = arr[m];
    2 ?, ]: o: J( N: G    arr[m] = temp;% G, `5 A5 A9 b4 R+ G
    }! ]" s& X4 ~8 a0 D$ Z: |

    ( E+ X; O# v2 Q( [( c/**
    ' p7 s2 Y, w% }% w, U6 O. V * 调整指定节点和其子节点0 G& i: @0 U6 v  X9 M) I2 m# o
    * @param tree 整棵树2 m2 Z% X# v. z, m5 d
    * @param n 数组长度,树的元素个数/ i6 u  X2 |, r$ A3 }4 d
    * @param i 要调整的节点的下标4 c1 i& ?" S) T
    */# {: D) Q+ R5 W! b
    private static void heapIfy(int tree[], int n, int i){9 D; R3 i. V- u6 ]+ d! G% a
        if(i >= n){
    7 w4 Q# T0 l& t) r& z8 n6 d6 U2 `( Q        return;
    ! ~* S" j7 o" ~% I    }5 i7 A( P" Z2 K
        int c1 = 2 * i + 1;//左子节点的下标
    ) i9 L  c' U& F9 R1 ^- z8 J    int c2 = 2 * i + 2;//右子节点的下标  r0 l" z: D; I% F* {
        int max = i;//假设父节点是最大的
    7 F2 T# x; r( @/ @( u7 D' W! z6 @2 \: r  M    //找出最大值的下下标
    , r! l* _/ `. W. V* \    if(c1 < n && tree[c1] > tree[max]){* v. V9 ]; Q2 z$ ?1 s1 e
            max = c1;9 n+ F: P" k7 P4 d/ s9 B8 M2 W/ g" y. D
        }" @4 Z! k0 B) o7 g* p
        if(c2 < n && tree[c2] > tree[max]){
    0 i2 X( E- g7 c  G  s        max = c2;& z/ A4 j, \% s  [6 W! O+ |
        }
    8 Q- h" t; W% ^! O% b& q    if(max != i){//如果最大值不是父节点,需要做换位置操作7 ?& U( P# M" |' x, ?# e/ `! X6 O9 u" b
            swap(tree, max, i);1 p) R: t# i0 j2 |; b  i
            //此时,i节点被换成最大值了,符合大顶堆的性质- N' u- q2 a0 f2 S' x
            //但是换到下面的节点不能保证比他的两个子节点都要大
    1 l# V9 i. m; ]7 h' `0 O        //所以被换位置的节点继续调整
    5 T0 B2 M" S/ D3 m7 e7 S7 ^6 q8 h        heapIfy(tree, n, max);
    2 a, W* c* _) e/ [8 ?, C9 T. M    }2 Q2 P! V5 z$ d! C5 _6 ^" B
    }) C& m7 `. c, y( o( A

    ' I- M9 N7 T% x0 P/**$ o1 C' ~$ M3 |* }( ?* Y
    * 完整构建大顶堆: ^6 U/ t! P' E6 e% k3 Q; z7 T
    * @param arr 用于构建堆的数组5 V8 \  T+ k; }9 B9 \" h4 T
    * @param n 堆的最后一个节点的下标
    + @. u* t, y. G) u% E6 \, d */$ w% X6 O1 y  U
    private static void buildHeap(int arr[],int n){" T/ B  v0 j, x  y- K
        int lastNode = n - 1;' i) `( t  Y. f9 |* e. Q
        int parent = (lastNode - 1) / 2;
    0 p# N/ ~/ k" F5 W    for (int i = parent; i >= 0; i--){0 d3 p, K( M+ P4 `& w
            heapIfy(arr, n, i);
    * ?" X1 H4 K4 H. @( I8 h$ @    }2 g5 p& Q; \$ O' V- i0 o$ U
    }4 S% m; n# ?1 J1 f& F6 G. Y& n9 x. O
    7 M& W- f7 p& c' G8 O
    /**
      z5 z, v9 ?6 C* u) q * 堆排序6 B  p  O. D/ U1 V! v9 l9 h5 f
    * @param arr 待排数组2 l8 S, K$ g6 j5 i$ `3 u
    *// L/ V2 `/ u( U& ]) r( x3 {4 R
    public static void sort(int arr[]){
    - k4 R' v/ J! s2 b    buildHeap(arr, arr.length);//先构造大顶堆9 J$ P9 F% U! V) T; a; j  r
        //每次构建堆后将根节点和最后一个节点进行交换( o% X9 o* S, l/ Y
        //然后砍断最后一个节点3 }/ f7 v9 v2 ~4 O- G1 j" b+ A
        //所以从最后一个节点向前循环
    3 e  n8 `* x6 Y9 ?7 a1 N7 _: `# O    for (int i = arr.length - 1; i > 0; i--){
    " _0 s4 v9 w: Q        swap(arr, 0, i);
    * z8 N4 T) C8 B: l# S: Q        heapIfy(arr, i, 0);
    ; R* o0 ]/ y- c) O- y    }
    , @1 y9 h4 c  w$ d: Q& P}
    4 o. J. X+ z3 y8 c8 W  N" ^: f! ?  j0 I3 a————————————————: A# N0 o0 j- i3 J1 M% m' F: p
    版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    7 i3 }( L3 }* A# ~( p原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644
    2 F2 O: ~& o8 x& n  L& X7 r7 X) a4 @# d5 Y- ^

    . |7 \) x( e6 `! X. B5 u# 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-4-21 04:19 , Processed in 0.407140 second(s), 51 queries .

    回顶部