QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1441|回复: 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
    7 x5 g2 _% ~& e2 m2 C! K& \+ b
    十大经典排序算法之堆排序(Java语言). G) E; V& v# r6 @! Y: c
    文章目录$ y6 s! Y5 }  _+ C1 {' B, S

    ; u/ k- l0 ?- I! w' O0 n什么是堆5 i& ?4 Z" ^4 P0 ^; C# T
    如何进行堆排序呢
    : S+ \3 j$ }+ F! w) N用数组构建一个堆0 j* [* a  C8 t) A7 U# G
    上代码! }5 u" v" i! n) q
    什么是堆1 t/ b9 G% W+ V' ]
    * @# O% X2 d- z, i: T
    在了解什么是堆之前一定要先了解什么是完全二叉树- _9 O) C& }  F* ~3 _9 E7 t6 V! a
    看一下百度百科的介绍
    3 P1 @/ P, Y6 q5 Q' K) b4 b- A% c$ n# }% ?9 d: {
    若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
    + K- A5 @2 ]$ L8 I, v+ k9 Z百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下4 W+ f) p* Z9 y9 O: d
    ) |4 x* ~6 B; M1 h9 ]' x" E* U  X9 e
    完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    4 z, ?. Z6 Y2 b( C(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)) b2 s: S& W/ D  ?7 v8 L# \) ~' H
    (2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
    / ^+ }& H# R  [, n$ }) p7 V2 w一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
    ( t. A$ d+ Q- P9 G% k那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    ( l" z+ Y2 V$ g9 n( X. U堆有以下两个性质6 |5 O$ T4 O6 @" d6 `
    6 N" T6 H0 t% r5 w5 ~
    1 堆中某个节点的值总是不大于或不小于其父节点的值;/ V# T+ G: o# ?: o8 c) }
    2 堆总是一棵完全二叉树。- W$ B7 M5 F) Y6 E% v1 C" ?) a
    其中堆顶就对应二叉树的根) d& d% X5 f, q4 ^7 T
    2 N% f' r" \$ P. {
    堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分; _7 }- A1 U) H7 j4 `8 d
    , V1 P0 b- H9 W+ H& R' w3 c9 ?8 F8 u
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆8 _- p" A8 m- @
    如何进行堆排序呢4 D5 J# b. W1 |& ]7 n& e7 F
    : v) q- r7 E+ J5 {& Z
    堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的3 t  |9 s4 [$ W% C

    5 U( Y0 V0 `! \$ o, @3 M0 d2 H用数组构建一个堆6 Y5 {' a( f  \8 V1 o0 W

    + P3 C. m* N2 Q9 S1 c' ?. R因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储
    5 Z$ A) p) i& ?+ W" N" [1 z对于用数组存储的二叉树,我们可以用如下方法来定义:6 f! E) J' M0 b2 }% g
    假设当前节点的下标为 n
    " e3 Z" m/ Z: C6 T3 A5 z, K
      c/ Y1 W  u' ?* X1 B# x2 b* B) C1、那么他的左子节点的下标 2*n + 1" N& e& E: }& W
    2、那么他的右子节点的下标 2*n + 2
    1 f) ?! g! F3 w! R: V& M1 f3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1, V% |6 f* E/ A; E+ J. c
    4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断4 {) G6 B; b) k' n7 F0 V
    那么有了上面四条性质,我们就可以开始动手了2 I6 t- a  {! |" T
    8 T7 b4 a- c, ~/ s
    1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层
    ) Z" {: I2 j  k) p( j- K8 k2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了
    ' Q+ z- D' R" a+ N3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆
      y9 {; Z8 P& o% i. f( v  Q8 x9 @; W3 j( Z
    堆排序的性质+ k4 n" Q$ N9 P: _: j- S7 m# g( h* D
    + U- L. L2 n- m3 y0 m% o# o- Y
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性
    * K' r  j9 \; _' _" P' F# h堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定+ B$ f7 V+ B3 w
    上代码. G6 ^. B  u& d+ ?
    . e* s$ `% ]* D- p  ?* V
    /**
    8 K( l" Y# q/ B/ C/ q; \' l * 交换第n和m个元素
    3 [& e0 \$ W+ h */; u7 H9 q  a4 l: p1 H/ @
    private static void swap(int arr[], int n, int m){
    1 R8 W  b5 x; a    int temp = arr[n];- W6 ^3 a" T/ c& ?/ a* W, n8 h
        arr[n] = arr[m];
    # S- N, ?3 R* G! W4 x+ j* F. M& C    arr[m] = temp;
    % ~; u' @, A. Z' p/ q" J}
    ( t% K, b& v, r- A9 d! X, Z9 T4 [/ {
    " a) S) ]6 c4 b: K' p6 X8 S/**7 W6 _+ F- @& X
    * 调整指定节点和其子节点
    * n% B: k( J% i1 _2 x0 P) k( H2 Q# | * @param tree 整棵树
    + {7 P; C5 e+ y8 f" s9 p * @param n 数组长度,树的元素个数
    2 H4 P7 E& A! G: D2 m" Z3 e * @param i 要调整的节点的下标
    3 [! K% p& F/ I+ u */
    5 s7 |4 R7 B' \" g+ R: Cprivate static void heapIfy(int tree[], int n, int i){$ `  p! o. `  t9 `2 u
        if(i >= n){
    ! q, Y5 O. t# p9 q, t/ M- W- X1 }        return;- `; c) h, s( Q  E/ N9 P
        }
    0 g1 `; R1 x$ b, n2 F    int c1 = 2 * i + 1;//左子节点的下标
    : T5 H5 g* w! N$ ~2 w    int c2 = 2 * i + 2;//右子节点的下标
    * ]. S+ [3 m/ Y) \) Y, H* P    int max = i;//假设父节点是最大的9 `/ ~. {$ m" W' n( p
        //找出最大值的下下标6 K& |9 B2 q" r( h# s
        if(c1 < n && tree[c1] > tree[max]){
    0 i+ s& ]5 G3 J1 U) l        max = c1;
    8 ?, z  {9 `6 c3 k1 X" d, S    }
    , M, l4 i! L6 H( o    if(c2 < n && tree[c2] > tree[max]){( V  {# U1 Z8 b8 O7 {/ b/ f
            max = c2;6 M4 r+ ]6 Z- n1 i
        }& H& K' p$ m  V! m2 l
        if(max != i){//如果最大值不是父节点,需要做换位置操作
    * P  L+ Y# d% i* o        swap(tree, max, i);
    3 N+ A* n0 @) |/ ~        //此时,i节点被换成最大值了,符合大顶堆的性质& @( o3 [+ A" z$ s& {; o
            //但是换到下面的节点不能保证比他的两个子节点都要大0 @/ u- ^! A5 Y& j) A
            //所以被换位置的节点继续调整( M% t0 I& P9 ^/ G1 O; t* g" e
            heapIfy(tree, n, max);7 Y, |$ ]9 y! e- t
        }
    $ I5 z; c5 c" t0 _" R( m* e0 o}/ d, R4 X/ G, O# X. p

    3 v8 v. t! a/ |+ j/**4 T1 Z0 B# J- v$ e6 q
    * 完整构建大顶堆+ S, w5 a# h2 X3 S5 {! A
    * @param arr 用于构建堆的数组
    5 U. p7 u; y; K * @param n 堆的最后一个节点的下标
    : n6 F+ v2 j6 u0 {7 Z! z/ E */" g, `5 ^( A2 z% \% S4 p3 Z
    private static void buildHeap(int arr[],int n){  \' Q2 {& a9 C9 g% g- v
        int lastNode = n - 1;; H1 \0 }" x, l
        int parent = (lastNode - 1) / 2;* w8 m! _; i8 Z
        for (int i = parent; i >= 0; i--){
    * |# V! v6 W$ D8 k* \8 F! w        heapIfy(arr, n, i);8 p$ g- t7 O! p4 F0 X
        }2 q0 `0 H5 l. k5 e
    }
    ( E7 o, D. n# p2 Q& z! j2 A; i2 B7 R# w
    /**& y) ^- B1 {  H1 M* b# J2 A  u/ j# X
    * 堆排序
    + U, n& A1 _- `( O * @param arr 待排数组3 _9 l; |9 N# [: Y* [% n: K* y
    */. v0 x* d+ I" |- @
    public static void sort(int arr[]){
    , _: f5 q3 P5 X, [8 j! ^    buildHeap(arr, arr.length);//先构造大顶堆
    9 d& ?% K2 C2 ?7 j# _- Z    //每次构建堆后将根节点和最后一个节点进行交换
    4 s1 m+ e. b1 H) P    //然后砍断最后一个节点- M" f$ a" J% @. e0 s. G' o
        //所以从最后一个节点向前循环6 P% m  s  h! M4 B. [; ^2 }; V5 J5 Q
        for (int i = arr.length - 1; i > 0; i--){' `2 M) d9 i4 M' r( _
            swap(arr, 0, i);
    ( r, Q7 X8 c: H% q9 r        heapIfy(arr, i, 0);
    2 Y. e* n# z1 d5 B    }/ m8 A# ?, \/ J) o+ @* T9 \
    }5 \% A% w. Q: H1 [
    ————————————————% F6 h4 J! g  j! r1 i1 V1 b
    版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    3 [1 @( w- ]5 J! y& T$ T原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644
    7 n$ ?% x. {8 U3 ?5 u/ W6 u% I4 H6 }- i( l  O. v2 q1 |& Z
    5 u2 J" P& H5 M2 T( W* ?, |- u  [
    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-20 15:50 , Processed in 0.355764 second(s), 50 queries .

    回顶部