QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1440|回复: 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 @) T0 I% R, {. w" h# {3 Y2 U/ q十大经典排序算法之堆排序(Java语言)
    4 K9 `( [5 ?) [7 f- B) I文章目录: N& M5 I" H! k. g6 H8 d5 i: n. [

    1 }* {: J. V' q什么是堆4 w1 g# q2 j. H0 q4 W
    如何进行堆排序呢
    4 d: t5 V% V0 t* K% D9 Z8 z用数组构建一个堆
    8 c) v- m' W! n! i! {上代码6 U7 M6 \" ]1 y$ P9 {* H
    什么是堆
    8 W/ o  j/ ~# F2 s: k9 M; ~/ z$ K3 o/ l/ i. s8 S
    在了解什么是堆之前一定要先了解什么是完全二叉树4 X+ m, Q: {+ m
    看一下百度百科的介绍
    8 A! |# Y7 P0 C
      K# e# C0 t- }! s1 y若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。' E( ^% C. }4 v* I: f" x
    百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    ( R! {( e' m8 [3 I6 Q
    7 z6 g# {. D( l完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。
    4 f: e5 J5 y' E3 O0 j  y(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    7 G6 s8 U( v" v2 D& V(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
    " s0 r0 I/ K8 V; {' I& {! u一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
    4 q/ x- S& t" l5 ?0 n+ j1 b那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    . |1 d* m6 D8 `1 }0 n1 q  g* v( ?堆有以下两个性质
    * V$ B* u3 a8 o0 F' M8 b" |
    $ M  f# Y4 N+ I0 b# P7 x/ b1 堆中某个节点的值总是不大于或不小于其父节点的值;
    7 X0 Z5 v& p. v) j; F2 堆总是一棵完全二叉树。
    " V, m/ b  @: `其中堆顶就对应二叉树的根
    4 O# C) F) b- X- J( ^* T# S
    * H/ `) v+ j4 m# u1 _% f堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分
    8 O# O6 O: @! I* h5 b5 q! W% Q/ }! z+ }. C' h9 E7 o
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
    % |. y. B/ ^% M% G, v+ A如何进行堆排序呢
    ' G/ n8 H! g: ]; \- A$ I) I
    ( _9 z, {/ t# w# [堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的4 F) {0 c' M8 {# @! e: Y
    ! S0 {2 n& K( l1 ~
    用数组构建一个堆% `  k% W# f# v7 }' e

    ( m! E/ {. \% G( R  l因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储
    2 l+ b& J$ w" @4 C对于用数组存储的二叉树,我们可以用如下方法来定义:
    5 n0 i1 F4 A8 r! l. n* J9 |! N假设当前节点的下标为 n
    * @9 C: H5 y, U; y* [- }# R
    + i, y$ H! b* \1、那么他的左子节点的下标 2*n + 1
    & ?% w2 [* j" e4 d) o2、那么他的右子节点的下标 2*n + 2' v2 @7 C! d5 y& o
    3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1" G: G( F$ @, N$ b8 y
    4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断
    6 ?% q% s- K9 G+ O( O/ I. m! Q那么有了上面四条性质,我们就可以开始动手了
    / X+ h2 p$ K9 M& q* J7 M
    & v( z# G' ?& X& ^  g( T- W1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层' O/ \, y  ^# D0 Q) I
    2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了* B; ?! G% D" R
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆8 w5 h& e9 `6 u, G6 G1 q+ i! K/ O, W

    2 q; \- w! o" [' s堆排序的性质7 L2 T; K5 h  H
    0 j( v: d, `' U3 k  f/ V
    中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性
    / Y( b  \+ @# E9 |4 t/ s/ y/ J+ \3 M堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定; C6 m2 y" O, o; B  n0 x
    上代码
    0 b) g+ l* q3 X4 Z! P' j6 g
    0 W  g, }0 [" h" d/**
    ( W' S0 V& @+ j! b+ x- O * 交换第n和m个元素/ n; Z! G0 M& L9 t
    */
    $ t) \! i  ^4 L, f/ Eprivate static void swap(int arr[], int n, int m){
    / y! f# t, b* D9 A    int temp = arr[n];
    ) a3 @5 x9 Q, B. s7 W9 u) Y. O    arr[n] = arr[m];
    ) Q% z; g: a4 @# v1 V) y2 `# O$ V    arr[m] = temp;9 P5 a' I6 n$ _) z+ E7 X
    }( i6 Z3 w6 ?2 y, R
    5 ?8 ~3 Q. b8 y
    /**8 l# e/ q" s9 y
    * 调整指定节点和其子节点
    , c0 w# |8 T3 q+ ^; l * @param tree 整棵树2 P0 ~/ a9 W: Z
    * @param n 数组长度,树的元素个数
    4 g4 C. k/ A+ p: J3 O * @param i 要调整的节点的下标
    , }/ }9 l  L! x0 }. | */
    0 R6 o6 E  ]7 {$ y6 d- j; a$ {# B4 yprivate static void heapIfy(int tree[], int n, int i){
    $ F- W! p' }6 W5 q, T    if(i >= n){
    * g7 f( f  ?. }8 ]1 Y, u        return;
    3 j- ?% ^  ]5 E, Z( A    }
    8 b, L; X! u% q7 A) A) J" @& K& B    int c1 = 2 * i + 1;//左子节点的下标
    " R8 t" e( G1 m    int c2 = 2 * i + 2;//右子节点的下标, @. t8 e3 f/ i" }$ ]$ |$ s
        int max = i;//假设父节点是最大的  o% _3 {" _) K" C# ]/ y' R; E
        //找出最大值的下下标0 D" U' g$ x; _) U3 C3 Z! P5 D  Y/ b
        if(c1 < n && tree[c1] > tree[max]){" l% V. s2 J; X/ H9 n; l7 B9 c
            max = c1;
    ( c, L- A, B: E0 W& k1 v, V- n    }/ i. o. {# @' F' q5 q
        if(c2 < n && tree[c2] > tree[max]){
    " o. K1 T/ }) l! H        max = c2;6 D8 E4 O( Q+ V8 k
        }- S/ q5 Z8 q8 a0 W$ X+ U
        if(max != i){//如果最大值不是父节点,需要做换位置操作
    ) c# S9 u* h. @/ K  F' W" j        swap(tree, max, i);
    # R, W' }* V' h( [        //此时,i节点被换成最大值了,符合大顶堆的性质( g: ^  E) S9 ]' z! Z6 g
            //但是换到下面的节点不能保证比他的两个子节点都要大) I4 P5 g; ^* M! Y1 m$ d
            //所以被换位置的节点继续调整, W  \" M. F1 m1 d% c
            heapIfy(tree, n, max);
    & n, k3 ^+ |" ]+ D/ h8 U! Z1 A* @' {    }
    + w+ C" {6 N, K* M  y}+ [) d, v: X5 A4 x( b

    8 K* K( M/ ?" S( F9 U2 r# i/**
    1 p8 m2 Z* f/ j0 y0 v * 完整构建大顶堆
    $ k  b( h- y- d7 r; H7 M, T" A * @param arr 用于构建堆的数组
    : W: m3 b" P$ g$ [/ ?/ ] * @param n 堆的最后一个节点的下标
    - X) ~& @! |' T. @: c% b% a( U- \2 K */
    * S+ P, c+ D* aprivate static void buildHeap(int arr[],int n){, G+ F4 P) q  ~' }
        int lastNode = n - 1;
    7 M* O% O2 [2 @) W    int parent = (lastNode - 1) / 2;+ ^2 z# d# t# ]2 i
        for (int i = parent; i >= 0; i--){
    - s% e9 T5 |# g5 z        heapIfy(arr, n, i);3 b8 }6 G2 m" P6 P
        }, |9 o7 f1 t  v; m9 i
    }
    * i7 P( a6 ]% o  N# Z1 W1 h( V  E. M& |# i' r8 P1 U' t
    /**
    9 S+ k; l2 P/ n0 |5 V; q * 堆排序
    5 Q, B7 e; \3 H0 ] * @param arr 待排数组& ?" _+ v! P3 \; r4 A
    */8 v4 P1 E; ]' Y
    public static void sort(int arr[]){
    3 S3 X! u, i1 u4 J: C    buildHeap(arr, arr.length);//先构造大顶堆
    2 H4 p- E7 z4 |% t" _  |    //每次构建堆后将根节点和最后一个节点进行交换; f  M9 M; x' r! x, x! l7 Z: ?  b% S! ?
        //然后砍断最后一个节点/ R/ B. z& e& [; B7 S' ]7 @
        //所以从最后一个节点向前循环2 P2 J' @. Y% t1 ~+ n3 X% N
        for (int i = arr.length - 1; i > 0; i--){
    ; u% M0 N$ G/ ?        swap(arr, 0, i);
    6 [$ {# I! T+ |; I3 F/ E5 Z8 a1 p1 d7 z        heapIfy(arr, i, 0);# b! u# I( s% J3 t$ V" d, C
        }3 F$ k0 v" o3 W
    }" d& A) G# {  y# R9 f$ e! b, n. U
    ————————————————7 n6 A( U- ?& h" u. v) X
    版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。  T; G6 L% _5 v# D
    原文链接:https://blog.csdn.net/qq_34912889/article/details/1056906449 i" W$ e, v$ {( l9 T7 ], d% r
    % F" m8 [8 V8 G& P

    - G) Q) [  h* b. |7 d
    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 13:32 , Processed in 0.390330 second(s), 51 queries .

    回顶部