QQ登录

只需要一步,快速开始

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

      K: m6 i: {2 j9 T3 x十大经典排序算法之堆排序(Java语言)
      c2 ?; ~9 D# v) v3 p( ?/ u! k6 P文章目录8 |, |4 R% x+ s# \$ O. T

    , K. U& K" e& {9 _7 p8 Q什么是堆0 J; d' s8 N' U- T9 @
    如何进行堆排序呢
    ( @8 b" P3 I( h2 W# v用数组构建一个堆
    9 m) O" Z1 s# P$ u上代码0 b/ N% G2 q; U$ e( u3 @
    什么是堆3 V$ C& Y! u  s, J8 r, O( x! S

    6 T! Z4 x4 x; ~在了解什么是堆之前一定要先了解什么是完全二叉树& m- G7 f/ \& m: }
    看一下百度百科的介绍
    9 J. I" v' }+ B4 \  @* G
    ( x+ K5 B! S- b, C- i! Y$ o2 e若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
    . n! H: z) y" l百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    ; S* B  `' D% r! u) M9 m4 `" L' `6 y% ^" e2 v' s
    完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    9 o. F' w  @% S1 i2 Z(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    ! M2 a1 E) Y  P  o) Q, k(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。1 `+ S6 U7 D0 }
    一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。0 W4 b! `9 m7 r
    那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    / v5 ~* f5 j3 b; K! F. ?6 f堆有以下两个性质; G- M, q/ z" o/ \6 d5 ^; V; E. B

    % s1 ^1 f. d1 C8 n1 _; r1 堆中某个节点的值总是不大于或不小于其父节点的值;
    - p; @% `, M& \7 C, g+ x2 堆总是一棵完全二叉树。- E+ q+ R/ m+ F- T9 A* P) _
    其中堆顶就对应二叉树的根
    2 p6 u7 P- @, [; R% t' K
    1 X: X: \, u& {: m堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分5 M5 X! J, G: O; z2 r$ L
    * [: G% |: v' [7 k0 `" X
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆3 q- a9 }+ v! G5 u5 }, s9 @
    如何进行堆排序呢
    7 v% K+ M" k2 [1 i& u$ `
    % Z$ e( N) c8 D, Y1 j9 P堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的4 B; h, M0 i0 h. u- w, E: q, z1 h

    * w4 d+ c, |6 z1 G- l5 m" h  m用数组构建一个堆
    " P! S* Q9 }) O; }3 v$ @- Y* A  f$ P
    因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储
    6 R; V. [! v: c2 m) ~( b对于用数组存储的二叉树,我们可以用如下方法来定义:
    ) D  o9 i8 q+ |7 T, q; S' G% G假设当前节点的下标为 n& Z- H  Z$ m9 B& W4 h% b* K$ U7 ?

    $ e. t% R" o; D; y1、那么他的左子节点的下标 2*n + 1* P+ _9 e* C1 H7 R: x4 Q  q, T3 s6 V
    2、那么他的右子节点的下标 2*n + 2( |. u* o+ {+ U% t
    3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1
    6 w0 l5 j0 _( x/ Z$ n; d4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断% e) W: z4 O2 R- X- I
    那么有了上面四条性质,我们就可以开始动手了% [5 H/ \( R" v0 p6 W9 S: a9 n
      z: J% i% v; M) R$ P, u
    1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层) {. ]/ x' K  O. ^" Q
    2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了
    . F' C+ I% \4 E" w2 ]  L3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆
    ! L; p9 O% p* [, j, k/ z- a" ?3 A5 b" p3 K+ E! v0 n4 H  P" B
    堆排序的性质
    4 F% F" j2 X4 B- U% E0 {# z
    - W; ?0 r/ d! ]. Q( v5 t0 x3 P中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性7 [& u' v+ E% |- h8 j7 P9 _
    堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定8 |* K2 @- v1 U2 Y9 `7 j& |" E
    上代码
    7 d/ e+ [4 d+ B& E, A3 F& J# t/ S: u3 T  D7 U0 r
    /**
    4 R2 u# i4 F- ]. C * 交换第n和m个元素8 v2 h7 b5 ?( K6 S
    */4 q( L/ K. M2 r0 p" x3 ?
    private static void swap(int arr[], int n, int m){4 ~- ?) D  h' G" Y# \2 o3 Q+ E9 k9 V
        int temp = arr[n];4 b, n7 t8 W0 S( ~: L  }
        arr[n] = arr[m];" n4 |5 z& \( w
        arr[m] = temp;4 V$ W$ y) ?1 A
    }: c" E/ u: b$ Q& g# i: q& _
      E' e9 T0 k# R) z
    /**3 B  E5 k- \. I3 t+ ]% g4 i
    * 调整指定节点和其子节点
    ; B; G) {: D, r8 [0 y9 W * @param tree 整棵树
    $ E) O; X9 p1 T5 z8 u9 C/ C * @param n 数组长度,树的元素个数2 }8 F3 O9 \! c9 V4 I
    * @param i 要调整的节点的下标. m. V6 t/ ]; O- G5 y
    */
    - D( m' P( U4 I; Hprivate static void heapIfy(int tree[], int n, int i){
    ! d: E6 W, E' h' {    if(i >= n){' ?) O, R3 U, @1 J$ N; g# e
            return;
    & [8 w$ A9 H$ r. H    }8 Z; r6 u) ^8 W
        int c1 = 2 * i + 1;//左子节点的下标
    0 t; X( a/ b* Z7 o    int c2 = 2 * i + 2;//右子节点的下标
    0 `% O" y$ B3 p0 V    int max = i;//假设父节点是最大的
    8 U! C7 E( C% Q6 z    //找出最大值的下下标: v! L& t+ I% O" ]3 `# k. k4 g
        if(c1 < n && tree[c1] > tree[max]){8 d! |+ s1 k; e/ a( c
            max = c1;1 G0 K- x' h2 U" |7 t% s7 q. J# T9 p. P
        }
    4 }4 p1 J9 C+ H% u+ M7 F9 B    if(c2 < n && tree[c2] > tree[max]){
    4 H1 `+ G/ s3 C' o        max = c2;
    4 Z. t) r& q* O0 p' _    }
    : k8 ]4 L$ @$ M4 ?! {* F% U5 v& w    if(max != i){//如果最大值不是父节点,需要做换位置操作
    : P1 ]1 \2 g9 W+ Z0 a. N0 x' `        swap(tree, max, i);
    $ A/ M. f) l/ Z. o" H5 a" G        //此时,i节点被换成最大值了,符合大顶堆的性质* @5 K% |1 n2 k/ Q0 @
            //但是换到下面的节点不能保证比他的两个子节点都要大3 b0 @2 c9 h) N
            //所以被换位置的节点继续调整
    6 j* X% F2 ^5 u+ r7 C8 B0 p        heapIfy(tree, n, max);
    ! d7 w, b0 _% x% e. p6 R    }% V! R5 o! ]2 n6 R
    }5 ], m% Q/ c1 K, q* p$ X+ j% @9 R

    % a% ]6 U- E/ k* ~& Z% `  s4 o/**
    , }2 ?$ F- B+ X1 P * 完整构建大顶堆: ^5 j4 {' ^0 i: _, o
    * @param arr 用于构建堆的数组6 F* a1 M% {3 \6 ]" A# W4 t+ i
    * @param n 堆的最后一个节点的下标
    , Q% B& e- O- V3 N+ J */
    0 s' C. w0 v+ L6 l, l  K7 ?% tprivate static void buildHeap(int arr[],int n){) [4 W. V: x2 x$ \8 D/ d1 z- q- B: C. g
        int lastNode = n - 1;
    * ]3 m3 o' o9 b! t+ K! y    int parent = (lastNode - 1) / 2;- N# U# a) ]( N- M7 l
        for (int i = parent; i >= 0; i--){, U2 z0 _1 \/ s
            heapIfy(arr, n, i);- I8 |9 X. d& n$ H% L
        }
    ) ^) `5 k' |( T5 c7 d}
    5 o% B4 J0 G* G- _5 z: F$ Z* \3 d* I( P8 N5 Q
    /**
    6 E9 ?( s# y' i$ V% q) b. @4 L5 w. } * 堆排序
    8 W" o( e7 y" \5 _% l  X' R& d9 D * @param arr 待排数组
    0 I) U; {& s) I- O */, S+ D, y9 Z2 R+ _/ f2 p
    public static void sort(int arr[]){
    ; a# N! Z1 k, G5 m  c/ o    buildHeap(arr, arr.length);//先构造大顶堆
    8 }4 w: }2 ^$ G* g% }: i    //每次构建堆后将根节点和最后一个节点进行交换1 @3 m& v/ d6 f) V) a" s
        //然后砍断最后一个节点% l/ L' T! [4 P8 l
        //所以从最后一个节点向前循环
    6 M* x, A7 y6 B    for (int i = arr.length - 1; i > 0; i--){
    ! |, ?" @5 @4 c" \# g; D. [        swap(arr, 0, i);4 z8 S5 A+ o5 }' P
            heapIfy(arr, i, 0);
    8 M* [+ y: {, W& \    }
    1 x. d6 X, ]+ Z; j  A}2 I: V7 a: j6 U6 @8 p
    ————————————————
      s" h/ v4 I6 U1 a# Q+ D版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    / }+ ]% U) z% f5 Y原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644+ T3 i" J; F$ ]% X6 H9 W8 b

    # [9 u: i  P& q# |
    $ z2 P& W5 m3 C5 d9 _6 a, u6 _" B
    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-27 03:27 , Processed in 0.280349 second(s), 50 queries .

    回顶部