QQ登录

只需要一步,快速开始

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

    : ]9 ^+ O% [5 \0 G6 n+ N十大经典排序算法之堆排序(Java语言)1 r$ j) h4 e) K& q- y% B7 [6 K. t
    文章目录" Z( ]" @( J0 J$ b# i* E

    5 }  R7 K1 E; w什么是堆6 w' U! R% a+ o
    如何进行堆排序呢9 d* `# b& Y* N$ E" h' o" S
    用数组构建一个堆- }% p  C5 b$ u& U% J2 D0 H
    上代码+ ]0 p. F: X+ ~% F/ K8 X% e
    什么是堆: X1 }* s, {# ~; j5 l! I- }- V

    * w8 M- N- C5 D0 Z4 g5 @; q在了解什么是堆之前一定要先了解什么是完全二叉树
    $ V& `  R% k$ B$ w! j看一下百度百科的介绍3 S+ x& t4 U+ C

    7 x; W5 }) v' b3 F5 o: u6 r! L" ~若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
    % C8 ^& R, j+ e$ I2 a6 ?4 w- L百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下! A0 t7 {) e0 q4 f1 {

    % u  h; T, `" a% O( p完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    % u5 j8 H/ j1 l: e(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    . m( E9 T0 ^6 B% ~(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。5 N' f$ }, m4 e! H' |) ~4 t9 H$ X
    一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
    7 ~. L% g4 X4 u那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    1 T# X  }1 x8 l" X( D堆有以下两个性质' x5 X( l5 T$ K7 X
    6 T6 [# ~" |4 r7 u5 ?
    1 堆中某个节点的值总是不大于或不小于其父节点的值;
    , V8 f4 ^4 n/ w5 T2 堆总是一棵完全二叉树。1 t% p# }. E  o2 d2 ~- c- L' q) H4 |
    其中堆顶就对应二叉树的根
    # {! A9 D& h8 h% c, I% |1 ?& P( S& [+ I
    # D2 {6 ?) m2 S$ S堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分
    % ^2 [" x: z& a- E( y8 C2 @) u6 _6 J
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
    ( c" W1 n6 N/ M6 D- f; N5 {如何进行堆排序呢1 U5 R8 J: X; R# x% Q% G6 W
    $ `' d( Z" s$ w  ~; l
    堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的; Q1 H2 J6 g, K4 R8 S0 d& ^
    , W8 w, m7 x5 ]( Q5 k% }
    用数组构建一个堆
    1 _( U" R+ F! X# h
    & h' b0 X4 C/ _" J) D因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储7 ]) d% \! J- h% d2 [" g  b
    对于用数组存储的二叉树,我们可以用如下方法来定义:
    % J" K6 j6 p* |' t/ ]' K1 f1 ]' l假设当前节点的下标为 n& b/ @" a: l3 l8 K

      t, r. z/ a2 j1、那么他的左子节点的下标 2*n + 1
    / v. w  Y& d1 O( _2、那么他的右子节点的下标 2*n + 2
    7 S" Z2 ]7 L! R! c- @3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1
    & @2 g  M5 u& A# J9 ^4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断
    6 {: L2 y/ P2 |! L0 d  L那么有了上面四条性质,我们就可以开始动手了& n( g$ `! l$ F: m, N. ^/ e' x
    # i' U0 e5 Y) b+ m  w. i! M. M
    1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层
    ) u& j5 M+ T) ~) h( @, b9 B$ d& _* J2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了( F9 m) @$ ]. T5 Y* E7 W
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆
    # q4 o% I2 q) N' G/ @, A  c9 [% K, O2 i8 \
    堆排序的性质
    3 B+ g0 [* T5 Z4 o; s$ M7 C. U  m( k% O+ N" j6 e
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性/ E. @* Z( U8 b' O- l3 z
    堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定
    5 B$ p# T4 @+ j+ U8 V1 j上代码7 R, [6 n; \. y* ^1 j. c9 B
    3 \0 c& a, L' O  e" R  d
    /**
    6 U( Y0 O$ S0 |4 ]1 R$ W) [ * 交换第n和m个元素
    ! l, I3 a6 v4 V */3 Q$ L6 ^' N  s5 e' [
    private static void swap(int arr[], int n, int m){( ?2 z4 ^9 }, o( k- `% y: @
        int temp = arr[n];
    4 @3 g9 ]% C! \5 a4 ~/ [+ Q5 a    arr[n] = arr[m];- O7 U* c2 M( Z( e, j
        arr[m] = temp;
    0 L! ~/ l" L# v7 ^: }/ |}
    ! r, Z3 U8 Y: y' y) ]5 U, S* r
    . B: h# Z7 R# p. o/**: K+ z! J1 f( R, }1 g
    * 调整指定节点和其子节点/ ~! `1 l( T+ U! P* r( k& f
    * @param tree 整棵树6 t7 V, y( }" a0 {4 v
    * @param n 数组长度,树的元素个数
    $ r- |- X2 B. x2 D4 Y" O- b * @param i 要调整的节点的下标
    - o' K# Q, _, X  G */
    * V+ _9 C, l& c2 O" G& Y) H  q- eprivate static void heapIfy(int tree[], int n, int i){
    ( C1 N  B4 I) p    if(i >= n){
    / i$ D% [. e) p: I! H        return;
      G: T% M3 x! ]1 N    }
    5 X, Y. M( l8 }! F7 ~9 @    int c1 = 2 * i + 1;//左子节点的下标
    & `, n/ M6 s( \* c$ ~5 f    int c2 = 2 * i + 2;//右子节点的下标& J+ S9 |6 ]2 [
        int max = i;//假设父节点是最大的/ a, N1 ]4 c' R* h8 I
        //找出最大值的下下标
      n* K  V5 F4 i" \) C) y. Q& j    if(c1 < n && tree[c1] > tree[max]){1 F$ ]- y+ W2 u4 U1 c+ o
            max = c1;- j% E/ u  F6 N# A! w
        }( a* z4 }8 r! I" T
        if(c2 < n && tree[c2] > tree[max]){
    3 e- g" [) @6 D7 \$ \        max = c2;* q) ^2 K3 h9 e( u4 D# j; b
        }$ A* x1 x* L( |0 w% D/ r
        if(max != i){//如果最大值不是父节点,需要做换位置操作
    1 K* u* ~8 w8 w1 Z5 e$ \, n/ J- T        swap(tree, max, i);1 V2 F7 r3 U) u9 s" w
            //此时,i节点被换成最大值了,符合大顶堆的性质, K; U, ^7 x1 I/ M# I
            //但是换到下面的节点不能保证比他的两个子节点都要大$ Q. E4 c. t2 Q9 V$ ~
            //所以被换位置的节点继续调整
    ! ~- ?) ?& t5 {        heapIfy(tree, n, max);
    1 c  C7 j) X. a1 T0 d    }' G" O; s5 S' d# A! L1 A  I2 s
    }
    % [. j+ ?2 a; N. b
    & `8 e( ^  k9 \# S& @/**1 M+ p, M  r1 g; M/ j1 j
    * 完整构建大顶堆. h; {9 X- _" z
    * @param arr 用于构建堆的数组
    0 \8 W- c4 |; {  C, P * @param n 堆的最后一个节点的下标+ k* C6 H0 b. F- c8 l/ ?
    */" C+ C5 N" ~1 V, G
    private static void buildHeap(int arr[],int n){
    " E8 h* j# E; x) L1 ]; K2 H8 ~; f    int lastNode = n - 1;  I- n+ P, m/ C/ v2 z! z
        int parent = (lastNode - 1) / 2;
    . D0 P1 j* I, _5 @! @    for (int i = parent; i >= 0; i--){6 n1 L) N) s; i- V% T
            heapIfy(arr, n, i);- w% r* `* v# Q! X. i1 [; V
        }
    ( q- W) Q6 m2 B2 d  h}
    7 U" b2 [: @/ i0 t8 Y: K9 Y+ f+ F/ w. C
    /**. E$ Y& R- K1 L; m  C
    * 堆排序
    & ~7 \9 B6 ~+ o- l/ z * @param arr 待排数组/ h' _' ]8 R. B
    */
    # i  x9 N/ g; V* b8 Ppublic static void sort(int arr[]){
    . F8 F; H9 l1 N+ C    buildHeap(arr, arr.length);//先构造大顶堆
    . U4 J2 c7 n2 L7 `& `2 v- T9 Y    //每次构建堆后将根节点和最后一个节点进行交换3 S4 |1 w/ U; l
        //然后砍断最后一个节点
    . u9 I6 `( H. s% p# I. v0 T, A    //所以从最后一个节点向前循环
    : q  y- m  ?) X    for (int i = arr.length - 1; i > 0; i--){9 V8 H4 v! d: D: Y7 Z: q
            swap(arr, 0, i);& S: x4 y- O2 U; h, V3 C: [
            heapIfy(arr, i, 0);7 i& a1 `& w. A0 w. s1 Q- [6 A2 p
        }
    ; U% ?& \' j9 e}/ j5 p0 W0 }; x1 f% Q
    ————————————————
    4 u; e% k8 T* W& {版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。- O4 }% o! O+ w- y& F3 q
    原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644- a  {1 f2 U) `1 X  z( W. l% D

    / K! E' a9 O/ b' L/ W$ i' E) p) m- f  B9 Y, ^8 X
    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 02:24 , Processed in 0.362296 second(s), 50 queries .

    回顶部