QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1526|回复: 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
    4 i! R7 F4 t2 l' S" |
    十大经典排序算法之堆排序(Java语言)0 L; W: r/ U1 M/ K2 A$ f
    文章目录
    7 l/ Y0 Z& W% ^/ x9 x. k, V. C& }3 g+ g3 R: b4 x0 ?# `+ h. ]
    什么是堆
    2 v# R2 X. e3 g3 a1 f7 @+ C如何进行堆排序呢
    0 V8 f5 L. G) _2 t0 W, I用数组构建一个堆
    . R& Q- B6 ?8 y上代码
    , L2 \. F( J$ m$ ]1 |2 U什么是堆
    " X7 w6 }1 O% H  f0 s8 d% k
    - z# w) p0 B; U9 i+ z! c在了解什么是堆之前一定要先了解什么是完全二叉树1 [7 a0 E; ?. i
    看一下百度百科的介绍
    1 c: r& V6 d5 ], u4 ?8 [0 D
    : M) U9 n' I: x; f/ K若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。
    ( X8 g- B& x3 R- o* w( y1 |4 B百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    ! }5 U+ }2 D% z. Z" x; m; u* L/ t3 k# I& r" H1 ~
    完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。% e8 }! A& R7 m! {2 t, T) S2 V
    (1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)1 V2 u- {1 u5 g* u" z
    (2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。- c4 G7 ]+ k  G# e0 ^
    一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。3 I" v9 Z+ l' e7 r# r8 o
    那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    2 k4 S) q" B1 n3 Z堆有以下两个性质
    $ @( r( h. W0 r& b# v( e
    " Y* U; I% Q0 I9 q5 T! n1 堆中某个节点的值总是不大于或不小于其父节点的值;, @* Z6 E6 J% U  I! A1 L4 d
    2 堆总是一棵完全二叉树。
    1 G- L) x2 S3 U9 _2 X! m2 }8 y其中堆顶就对应二叉树的根; A# G8 r2 Q8 ?8 _) Z
    ' J& x1 _. C9 p3 Z0 g& Q0 ^4 O0 X3 w! p
    堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分) B& V% u0 A& A

    / ?8 Y* x: t0 I6 c6 T$ x当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆, ]2 N$ L! h1 k3 U) ]
    如何进行堆排序呢( H6 u: H- _) W; ?* T

    3 l2 {3 g, `5 _) T7 Q: Y: H0 r堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的0 K) a3 V1 n$ i

    ) ^, G8 Z  k5 r* }! {用数组构建一个堆
    " o! B: f. J% X1 j% e& j4 i. g' V4 _7 K+ @
    因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储
      q% i# t* r/ h- Y对于用数组存储的二叉树,我们可以用如下方法来定义:: c4 i% k0 D* L& O, |- l* G) m( V
    假设当前节点的下标为 n$ H7 V- b8 L" w, o* s0 P5 C5 ~
    - q- ~' F0 ~! T3 ~/ ?1 k- r) B
    1、那么他的左子节点的下标 2*n + 15 S( H; i1 U5 @$ i* m4 w
    2、那么他的右子节点的下标 2*n + 2
    4 Y: _  d, L& a: ^3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1$ m3 I, t; O9 Y8 W7 j" i
    4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断# ^& k( F% D% K5 Q$ D! m0 n# d- u
    那么有了上面四条性质,我们就可以开始动手了- ?2 g2 w3 X; H  w0 B9 o! p

      _1 B3 c& j( L1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层8 @. W2 U0 X, j& N4 U
    2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了2 A, n7 {  u9 J8 ]- x
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆
    * ?- f0 z/ @8 c) B9 k/ E+ d: I* [3 x7 @& y+ E
    堆排序的性质
    3 ?5 e% g+ T9 l3 \4 b0 {. ~" e7 q3 X4 W+ O
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性
    7 \2 ^" l7 K& {6 w: j% r, G堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定4 p# g0 I0 q3 @- r" S* `9 L
    上代码0 _( \6 d$ |- Z" S8 H1 Y

    " @, }3 W7 Q, S  b5 f3 }/**" q8 G8 k1 j0 L2 Q8 [6 U- q
    * 交换第n和m个元素
    * _( f7 U2 i3 `1 y) r- ` */
    5 i. q$ @0 e2 E/ G0 iprivate static void swap(int arr[], int n, int m){2 f5 p8 w* [: y- |+ R& e( o
        int temp = arr[n];
    0 |+ T. z9 V$ l* o& C$ a4 I3 k/ v    arr[n] = arr[m];2 @7 F2 |5 z* e9 F0 K
        arr[m] = temp;
    " j# r* P$ S1 i7 \. M4 x}7 G; J, l. I9 Z$ _& K# J3 O' ~

    ; R  v& ^% H) N9 L: w+ r% D6 [. p( `/**
    % z* y  _6 D3 y! y" L * 调整指定节点和其子节点
    & N' |5 l8 D& H * @param tree 整棵树
    , j/ _! W  P- r7 X! \4 W) O * @param n 数组长度,树的元素个数) r+ S$ w2 p) d. A" T
    * @param i 要调整的节点的下标6 f, }$ g7 w6 c9 r
    */
    8 h) B* e% f# Pprivate static void heapIfy(int tree[], int n, int i){
    9 h# J) C0 v& a5 _( D    if(i >= n){
    1 J) J9 V; `4 i        return;
    8 L0 I2 C4 i( A9 V) X7 @: Z    }( U9 H2 _. f& H2 M
        int c1 = 2 * i + 1;//左子节点的下标( j( c9 b- C  I7 B+ t8 S* }& L4 t
        int c2 = 2 * i + 2;//右子节点的下标; Y: C; {; ~8 n7 K
        int max = i;//假设父节点是最大的8 l% _7 ^3 {2 w0 \# X; p# ?# ^
        //找出最大值的下下标, @# s) ?0 _% h" T6 e8 ^
        if(c1 < n && tree[c1] > tree[max]){
      P9 K6 U' Q. T        max = c1;
    ; h0 N5 w4 K: Y. Y    }& H1 ~1 x- k0 Q8 N- }; `% z
        if(c2 < n && tree[c2] > tree[max]){
    * n0 j% s/ v5 X8 X        max = c2;" B0 s; y# S+ m" |7 V' ~
        }% @5 o6 q4 s4 \% u" D  ^" _
        if(max != i){//如果最大值不是父节点,需要做换位置操作/ a7 J/ ~1 M% G$ w9 d7 M
            swap(tree, max, i);
    ! g4 }* t2 l6 f" P' a5 M$ j        //此时,i节点被换成最大值了,符合大顶堆的性质
    8 D" ]9 E8 X3 U9 I! K# W7 h% A        //但是换到下面的节点不能保证比他的两个子节点都要大
    " J) A7 @5 ]2 k% r  e        //所以被换位置的节点继续调整
    $ s( i3 ?! f4 [) l6 \( g1 p+ s! b. k- ^        heapIfy(tree, n, max);
    / c( L$ X7 z6 u1 o6 J+ R    }* {9 ]  k7 N. E# m
    }
    5 R5 S) H' [7 [: l& q7 z
    , F2 l2 Z7 n, o$ i/**- \( D/ @9 g  l3 B
    * 完整构建大顶堆: J+ v# u0 o$ B3 I9 s  g
    * @param arr 用于构建堆的数组, K4 [6 L2 O" x* x+ W1 ~
    * @param n 堆的最后一个节点的下标7 I" p1 E) f: i& t  |
    */- O1 u; m  l' E3 L8 \2 u
    private static void buildHeap(int arr[],int n){
    ) ~$ w' _/ ^4 n/ o    int lastNode = n - 1;# c0 q! Q0 \: E( g" ?0 h! G9 S& ~
        int parent = (lastNode - 1) / 2;
    3 ]5 B/ ]8 H) Q: m    for (int i = parent; i >= 0; i--){7 H. s$ D* P. E# r
            heapIfy(arr, n, i);
    ' ^0 B7 N+ U; o! y: K7 S    }
    7 J+ ]) T4 g5 z}
    % A- b4 p# n7 ]% t0 Q& H, v! q7 B* h: ]4 N6 o: k' t
    /**0 B' R( {, ^, I7 ?; h$ c
    * 堆排序' H* P3 q" P0 _- A
    * @param arr 待排数组/ N% ^! [" V3 P% n3 S0 {6 R
    */
    0 h" }) S6 ~1 l( p/ B$ Lpublic static void sort(int arr[]){7 F' b( F( k. U, B! B$ ]
        buildHeap(arr, arr.length);//先构造大顶堆
    # z5 s8 G- E9 j, R" a2 L    //每次构建堆后将根节点和最后一个节点进行交换
    # N+ _9 ?% T: X2 ?. L! e    //然后砍断最后一个节点
    4 w- J  m' q" _$ [    //所以从最后一个节点向前循环% [% E8 ?& Q3 @* m# ]7 U
        for (int i = arr.length - 1; i > 0; i--){+ j- ?7 _2 Q" V$ {0 E$ w
            swap(arr, 0, i);
    " g- M* }) y0 _8 ]        heapIfy(arr, i, 0);
    ' J+ R6 |+ Q1 ~    }
      |- B, g8 ~- r: s0 [- }% v9 V6 g}
    ! `- D! q7 A' f3 X+ V) f————————————————4 c  ]7 X2 h: a3 j* P
    版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    0 c1 H- ^  G/ z! c( g0 W原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644; C: U/ \3 X* ^
    9 c, W# ~. R5 ^* h
    8 ^; B2 I- h" t  K: ~6 Y( \
    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-9-10 17:07 , Processed in 0.469667 second(s), 51 queries .

    回顶部