QQ登录

只需要一步,快速开始

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

    . D; G5 u% \  o7 `5 ^十大经典排序算法之堆排序(Java语言)! |! Z, L/ W( C3 n* q
    文章目录
    , g' o7 m$ A' K0 T' f& I  s
    " ?0 ^4 T( ]( L) [1 L  n什么是堆  P* A1 X* \& N. n; ~$ m
    如何进行堆排序呢7 Z/ Z6 C6 k) G+ C' G' g
    用数组构建一个堆0 ]/ H+ u) n0 n& _# \
    上代码
    ; v$ h/ V( ~3 `: ~! _什么是堆
    , U  K- }9 S. \! p% k. i2 ^
    # r0 D' y# c3 [在了解什么是堆之前一定要先了解什么是完全二叉树$ m& b7 P9 q5 z9 e8 ~0 g# a
    看一下百度百科的介绍/ b( d# n. Z" O" W# G8 u/ x

    * a1 g& C* F+ Y2 y& M% w, t( m1 E若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
    ; h' ?9 V+ `; f5 j; I百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下" }& U7 \: w+ y0 U; y0 o- s1 s

    : H5 m. j" x+ U1 ]/ E! E完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。& g+ j# c( A/ `
    (1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    4 v9 x+ c- f3 ]7 M% C(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
    9 K- [8 V0 k. G/ B; \一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
    ! K) H; D7 c8 {/ L( W5 k那么在了解到什么是完全二叉树之后,我们再来看什么是堆5 B" J- e7 P) R4 O
    堆有以下两个性质  Y" ?, i$ @! y# X' [' h5 E

    : x9 E: T- A$ @1 N6 Q6 ^1 堆中某个节点的值总是不大于或不小于其父节点的值;
    1 T; J3 l' R2 g: v2 堆总是一棵完全二叉树。; M$ O; q' e1 u1 U; X; ~7 ^
    其中堆顶就对应二叉树的根9 \! y/ B7 x0 U1 g# [0 Q9 w/ l5 s
    ' I* |6 M4 d# K" Q
    堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分# R# I+ M, y/ b
    # V) ~+ o' [" r$ C2 |
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
      C  s8 {3 e/ v2 k, P如何进行堆排序呢
      C) q9 Q. A" u' ^) K- f# y. g/ t1 x( U4 O
    堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的
    " s1 {! l* N1 v0 A9 c9 A, q8 R( F6 {( R) N0 R8 G( V% y
    用数组构建一个堆
    * H8 c% L( {: }
    1 y+ V; r6 ~3 W因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储
    " P, m6 ~" ]0 L对于用数组存储的二叉树,我们可以用如下方法来定义:
    4 H# x/ h( L9 Q! C' N假设当前节点的下标为 n) {, X5 l. V! Y3 m2 b

    - T8 o, o' c1 ~- n! A1、那么他的左子节点的下标 2*n + 1
    ; h; g5 e5 S9 _4 L2、那么他的右子节点的下标 2*n + 27 h  a/ [% c2 R/ J, w6 v
    3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1
    ; A$ r" Y$ X0 B6 t4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断
    ! K: W$ F2 R3 `: g那么有了上面四条性质,我们就可以开始动手了
    ' c% v5 Z  F4 E  z$ {; _* |# P% y0 c  z0 {  P
    1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层0 X+ v- C- u' d+ n0 G0 q+ M
    2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了+ C3 E; }' P3 J/ H9 X, N
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆
    6 G; l4 f0 J4 O3 R
    - ^1 ]- O/ p. G2 O0 o" w堆排序的性质. `2 T: C9 S( v( j0 s% Z2 e
    ( A  E$ E8 h' D; b. ]' ^
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性
    + b2 d/ s* E4 }堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定3 F# `( J2 u4 K- o
    上代码
    7 d7 c" z$ h6 r- i. X8 Z8 w
    ! V: j  H- x- a/**
    2 a3 T" J: d3 t  r! I5 p1 z2 W * 交换第n和m个元素0 }2 R* h$ l  Y' p
    */
    7 y" J+ c8 S5 M6 X0 p+ X- gprivate static void swap(int arr[], int n, int m){& N, N6 m4 b9 M. w. Y' W; J3 r
        int temp = arr[n];* H; w: ]( l& \. H4 c7 x: d
        arr[n] = arr[m];! M/ L$ l9 y8 x$ Y8 o
        arr[m] = temp;5 d+ `' \) U7 N# H) E  J/ G0 V
    }% e# ^& k+ S, v* C6 M" M. B4 }

    1 b) w/ f5 O- Y" Q5 t/**
    $ v$ t  B$ E4 P * 调整指定节点和其子节点
    3 B# q( L0 @* J1 v# ^1 b7 J( M * @param tree 整棵树
    # S8 [0 a3 X6 @$ [' G( j* O * @param n 数组长度,树的元素个数
    + e* i: ~! C: H1 B9 b$ W * @param i 要调整的节点的下标! p6 U. A% \' ~+ V
    */
    ! U6 u3 X9 J( p" E, E2 V& q: Z5 Pprivate static void heapIfy(int tree[], int n, int i){
    : H( z' A; T! S9 P1 R' h8 p! ]    if(i >= n){
    , U  O" ]' [  D8 q  U' S+ ~        return;
    ; t$ `/ ?! D$ z5 {: h- T4 s    }
    ; L+ e# v2 q2 U6 P; A    int c1 = 2 * i + 1;//左子节点的下标
    ' g/ @; ~6 A1 n% N    int c2 = 2 * i + 2;//右子节点的下标; H: j  l# V0 L/ |8 J+ E- z
        int max = i;//假设父节点是最大的
    9 Y9 B  V; r2 m    //找出最大值的下下标4 j1 h% |& F1 }( I2 ]4 B3 U
        if(c1 < n && tree[c1] > tree[max]){
    2 Q0 A3 U) G+ n. x0 M7 s        max = c1;4 ~) b1 V* g/ t$ U7 e. W
        }
    $ r: \  |8 _3 j6 W. h! k  K9 e    if(c2 < n && tree[c2] > tree[max]){9 y4 W* N: [+ a" X2 O1 h; o& n
            max = c2;0 ~% S/ h; o& |6 X/ T
        }+ B" [, M4 L: f! e$ `* P3 v
        if(max != i){//如果最大值不是父节点,需要做换位置操作" H& Z) o/ ^+ d" h/ X: M& M
            swap(tree, max, i);7 @' k' E: a' |) g2 Z. C; A
            //此时,i节点被换成最大值了,符合大顶堆的性质% Z& b5 p. K( B
            //但是换到下面的节点不能保证比他的两个子节点都要大
    7 \7 ?+ t3 k7 A, q        //所以被换位置的节点继续调整9 p' u  F4 W' t- s
            heapIfy(tree, n, max);
    - r/ Q4 }8 Z3 q9 B: o1 P7 e/ h& e! a    }) s/ h: w$ p5 h9 N) j2 s" X/ J
    }4 J% I+ X" Z# E8 Q& G( ^
    - Y! [) r2 O" G5 y% r
    /**( K7 }, {$ N. p
    * 完整构建大顶堆/ F2 I& i: A6 g, Y$ u$ G% u
    * @param arr 用于构建堆的数组
    : {6 p) S5 }. L& Y; _% C * @param n 堆的最后一个节点的下标
    ; L* {& P5 z; I0 n: B */1 J5 s( W0 H% A9 \% D3 P
    private static void buildHeap(int arr[],int n){
    $ x) k3 Y. o4 t; d  {    int lastNode = n - 1;. X) \$ Q" }5 o' ]2 y0 H0 v
        int parent = (lastNode - 1) / 2;
    8 }" v2 C( r' G2 c  I8 {    for (int i = parent; i >= 0; i--){6 M8 v3 }3 y1 I# q8 K/ ?" \' j! r
            heapIfy(arr, n, i);6 R9 j4 V5 H2 R
        }
    * d5 ^. k) d5 R& {7 r8 U}
    6 m; o  l/ Z7 N
    " D8 U5 B- M, T1 M4 x/**2 i/ i/ G2 T  H0 \' |: K
    * 堆排序
    # ^- @9 O. T  Y3 g * @param arr 待排数组
    2 O4 a% w. b) S# B) a */
    3 I$ K0 ~1 M8 U$ H- vpublic static void sort(int arr[]){
    , O( h; a; G& b3 E3 b7 t' n    buildHeap(arr, arr.length);//先构造大顶堆/ J1 [" w9 X) k9 S
        //每次构建堆后将根节点和最后一个节点进行交换
    $ M1 H8 ~3 {) H% i: K    //然后砍断最后一个节点
    2 o+ s' D# d2 X6 @& x: l    //所以从最后一个节点向前循环! O; s8 g6 {, u
        for (int i = arr.length - 1; i > 0; i--){
    , q2 y- s6 ^* ?5 n- J( i# A        swap(arr, 0, i);
    . _+ U4 q; F/ `        heapIfy(arr, i, 0);
    0 m" W) V( }/ q; H/ ^    }2 ]) A, u7 N+ W' t
    }
    4 Z/ @7 F" E# z3 |# x  }5 P————————————————" P$ C+ n, m1 m* ~$ j6 e9 r9 o
    版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。1 u2 O: n! Z! Y! z8 h- P
    原文链接:https://blog.csdn.net/qq_34912889/article/details/1056906445 l" W6 N2 R% n9 w( D. R: C

    . n0 x' [, @5 Y& u' C( y, Q
    : N3 Q  k$ r9 m# m
    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 21:02 , Processed in 0.389857 second(s), 51 queries .

    回顶部