QQ登录

只需要一步,快速开始

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

    2 i/ C1 V. U% s  M8 c2 ^十大经典排序算法之堆排序(Java语言)
    : A! W( O! R6 [  X% p4 A/ F6 q- {文章目录
    0 r! Y* y' c$ c# J0 I" K6 T# K. I; `3 `' _, p: r
    什么是堆. ]7 f, M( N7 X' \# q# Y
    如何进行堆排序呢
    1 u4 @: a. q! h3 f0 \4 `( x) B" C: u用数组构建一个堆
    , K! E( F0 z5 _5 A上代码
    : k, V2 B' x' l" |什么是堆
    : W3 `! X" W# Z" P( F  w
    . Y  k2 A; q4 c- K在了解什么是堆之前一定要先了解什么是完全二叉树
    ) ?3 U, V. C, e; F看一下百度百科的介绍/ G  d( R/ ^$ P( k7 Q( r

    7 O6 W0 ?/ U. [. H若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
    ( V! R& ~+ c0 H7 R百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    1 X+ Y7 i8 X. v
    ! f! n- y' S  s完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。' {5 I- d5 `& m
    (1)所有的叶结点都出现在第k层或k-l层(层次最大的两层); R, b. f/ R( m; m8 `& b
    (2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
    9 F: {8 I6 l8 e% ?& m2 F7 s一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。$ |: K! e* C) J& R+ A1 [, B( {
    那么在了解到什么是完全二叉树之后,我们再来看什么是堆* J$ x3 q* v* e+ u
    堆有以下两个性质
    " \' }& z. e, a! r8 t, w
    - }7 d( @- [* C0 H. U+ `8 a1 堆中某个节点的值总是不大于或不小于其父节点的值;
    ! R% |7 `+ K/ I) X  n2 堆总是一棵完全二叉树。
    8 y1 b# Z  d- `2 U其中堆顶就对应二叉树的根
    9 V' e# [! |& A2 m
    * j: c" s# v5 ]堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分
    7 r8 T0 U3 A- C3 n: Y: E8 v
    $ A6 x6 W( T9 G当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆. g, m; n0 O. b9 d
    如何进行堆排序呢* D- k, Y+ F. _
    ! S) u& @8 `: g3 H' V7 `5 L! O
    堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的
    * C) \2 \& }, e' g
    ! H9 g! E7 g2 Q- @# s9 r用数组构建一个堆1 x6 @1 N$ K% [3 t0 P
    , {. c/ H4 @1 F/ d3 W) g9 @) [( K( @3 w
    因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储
    % Y. n# E, a; K( d2 i) i$ d* e对于用数组存储的二叉树,我们可以用如下方法来定义:1 x6 E' {, s9 d. W8 u0 ?
    假设当前节点的下标为 n6 K8 s, Y; \  F. X. R
    * N. |3 e! h8 f' ~# u" U: _/ ~8 t
    1、那么他的左子节点的下标 2*n + 1
    8 n, a8 L3 Q1 J1 b2、那么他的右子节点的下标 2*n + 2
    ! k' e6 u5 @/ }. g+ l: N: m3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1: O8 a2 d6 R# V) Q0 U6 x
    4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断: g; @6 U9 k! O# M: k  v- V4 p
    那么有了上面四条性质,我们就可以开始动手了7 t: u0 g1 b8 P  o- m" L+ ~

    ( L; N7 j' b0 B) m1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层
    4 _3 u, N2 \+ Q1 v. H2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了2 Z3 W" v3 r; o/ _! `# T9 @
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆
    5 W! G/ }& y) r3 l0 u% P1 k* m3 r- l
    堆排序的性质
    , {5 Z+ d; y* c9 E# k( O4 M0 _* m  a# j+ b$ G: U6 n
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性
    & K/ ?" M4 l& e3 w堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定  l3 b- m' B0 L& h. u! l  ~# N
    上代码
    " F$ V- |' x+ ?" e4 i+ H# }# Z. d) B! h" i8 `( s
    /**# K* Z% D4 M9 O: W! b4 k6 X# V6 w
    * 交换第n和m个元素
    9 g5 O* L7 h1 X& G */3 O1 D3 H4 p& L- w
    private static void swap(int arr[], int n, int m){
    6 c% H$ e! @* H* s8 h* Y    int temp = arr[n];
    ! T$ w& f' _# Q0 E% C$ i1 U: E7 ?    arr[n] = arr[m];( s$ q' `* B3 a7 I( _
        arr[m] = temp;# V& t/ i  a: n
    }  E0 U2 n1 V" k7 {

    ( S3 e" R# v7 W, D" {/*** f/ _( f1 H7 [. w
    * 调整指定节点和其子节点
    5 U( F. g$ r& o/ J% L4 X * @param tree 整棵树0 c5 g. [. U: `
    * @param n 数组长度,树的元素个数
    : _, C+ [% R# N% S * @param i 要调整的节点的下标
      B8 b8 H' Q4 q. r& ] */4 Z$ B4 f: F6 f) p
    private static void heapIfy(int tree[], int n, int i){
    2 Q( i! c9 u5 X* W3 [5 ~    if(i >= n){$ V" U3 l( P4 C
            return;0 T; Z. d: b3 ~* h$ @. t
        }
    , I, W/ }& K8 D5 j/ O" r! C" ^    int c1 = 2 * i + 1;//左子节点的下标
    4 T$ t2 s8 z/ h+ S$ c; q' M! t" s. w    int c2 = 2 * i + 2;//右子节点的下标
    - k/ I$ G- k5 g8 H5 ~    int max = i;//假设父节点是最大的
    # n- v8 @1 H- ^    //找出最大值的下下标9 t' y+ v  u) B4 D7 N' n) a
        if(c1 < n && tree[c1] > tree[max]){
    ! F+ D  m* U4 _3 L        max = c1;! V6 c' r! V5 b! J8 X
        }9 O* i; w7 d' [. I
        if(c2 < n && tree[c2] > tree[max]){7 ~6 Z# [9 s6 K
            max = c2;
    , U' `8 v  ?& G7 j  A: d    }
    7 S6 C, ~5 f' T# V7 U; F/ m" i    if(max != i){//如果最大值不是父节点,需要做换位置操作0 |- Y# F5 t$ w* D
            swap(tree, max, i);
    5 p2 U% `. h& w( s( k8 J        //此时,i节点被换成最大值了,符合大顶堆的性质
    : D. m; ]* S( X7 u2 Z0 `1 J        //但是换到下面的节点不能保证比他的两个子节点都要大$ j4 G/ s8 h& E' m8 w# y
            //所以被换位置的节点继续调整, s; x4 U5 N; I3 A5 g! ^
            heapIfy(tree, n, max);" O! O9 \7 N/ `" b% T  R
        }
    : L, M- r  m; Z  @}
    8 s; U% H0 J6 ^: t; W9 E# O3 `# |2 d2 m; a  M9 q
    /**9 {: a9 g! Z' `, e6 e2 L: u& O( }+ n
    * 完整构建大顶堆
    1 Z" C0 H: x+ v6 U( S0 Q * @param arr 用于构建堆的数组
    " H( F' L0 H. Q* G% o7 x4 U* g * @param n 堆的最后一个节点的下标
      Y1 H) u+ q2 A6 p+ B0 x, n */
    # ~( |0 t, W7 J# Z$ |/ Wprivate static void buildHeap(int arr[],int n){
    ! Y6 @7 `" \# M) C# ]0 r8 v/ X    int lastNode = n - 1;. A( ?! {! F2 X
        int parent = (lastNode - 1) / 2;) H" S6 S( ]  d+ [* t
        for (int i = parent; i >= 0; i--){
    1 g  t- |% z/ |$ q        heapIfy(arr, n, i);
    ! e$ |2 b. p& {  ?8 M: G2 ~    }- V" @  U" {" r" J) Q3 Q3 ^7 O
    }
    9 b! |% \& {4 A: c
    4 X! P$ n7 |2 A" t7 R* i) B/**: z/ |$ [  e- E% o2 b
    * 堆排序9 Y- y* w6 Q- R! b4 K9 C. j
    * @param arr 待排数组
    ) ^2 f  k1 b6 f* l5 } */
    6 R+ p8 S! F7 ^4 lpublic static void sort(int arr[]){
    / W9 \3 I3 b1 c7 F3 e- m0 Q, y8 m( O    buildHeap(arr, arr.length);//先构造大顶堆
    : |; ?% `% t9 Q% _5 X% A. J9 I  y    //每次构建堆后将根节点和最后一个节点进行交换
    ' G7 X( O7 z% x* M- o    //然后砍断最后一个节点
    # X4 |/ P& c6 {3 Z    //所以从最后一个节点向前循环
    * U" x8 c, c/ I3 u9 c0 @    for (int i = arr.length - 1; i > 0; i--){
    2 Q' s% p. `  d2 Y3 c- i) M        swap(arr, 0, i);* s4 X/ o. `# f3 V8 b& B
            heapIfy(arr, i, 0);
    2 x) T/ f6 o- q/ Q% a    }
    & f1 o1 o+ f7 Z}( K7 i3 N, ^9 [
    ————————————————
      u; q* A% t, @# W  l+ |版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    0 F1 X( U+ `5 E, P$ t+ M1 f原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644
    ( }! @7 q8 e# ?! U  H9 Y( V! k) h. q: t" ~7 H9 ^) V

    4 n# u2 }2 k* Y% j
    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 22:38 , Processed in 0.420813 second(s), 51 queries .

    回顶部