QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 1229|回复: 0
打印 上一主题 下一主题

十大经典排序算法之堆排序(Java语言)

[复制链接]
字体大小: 正常 放大
杨利霞        

5273

主题

81

听众

17万

积分

  • TA的每日心情
    开心
    2021-8-11 17:59
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    网络挑战赛参赛者

    网络挑战赛参赛者

    自我介绍
    本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。

    群组2018美赛大象算法课程

    群组2018美赛护航培训课程

    群组2019年 数学中国站长建

    群组2019年数据分析师课程

    群组2018年大象老师国赛优

    跳转到指定楼层
    1#
    发表于 2020-4-23 15:00 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    / B* t1 Y. [# B# Z; @  t: L
    十大经典排序算法之堆排序(Java语言)
    4 A' A$ q# [- X3 ^5 u" _- O) `文章目录
    ! [3 j, q9 e/ x6 A# b7 `) Q3 W! i) o; M+ |3 Y
    什么是堆
    + K" q2 \" E5 B: Z- w如何进行堆排序呢, Z$ C9 u; d% J5 i% _) b% O
    用数组构建一个堆. I- z. q8 J' P" z1 |2 b' v
    上代码/ R3 B2 C2 t' z$ h9 ~2 o; N5 ]
    什么是堆  a' v4 G3 Q, V3 ^

    / H; t3 J8 K# \0 h* T在了解什么是堆之前一定要先了解什么是完全二叉树* ^: P" V$ V9 w2 O8 f
    看一下百度百科的介绍- Z+ W/ [- d' O2 {- t! L3 C1 c! G

    % L2 A, m+ u- i  l; V/ M若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。$ V# s& g( c1 g2 m" M
    百度百科拗口版性质介绍,能看懂上面的就行,下面的大概看下
    : F" {- W" w. w5 n( L% z; ]
    . f, A* g- v+ {6 |; o0 z3 d完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。- T9 a8 T  _+ C+ C5 ~6 b
    (1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)
    $ ^$ Z) _8 u$ N(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。
    - g; [! o8 |3 b( ?4 J一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。
    2 v5 F  p7 Q, z) j+ |那么在了解到什么是完全二叉树之后,我们再来看什么是堆
    ! K2 c5 E. L7 W7 t7 @堆有以下两个性质; I/ }: U* H+ x2 L0 ]1 y( l2 q

    8 C6 M0 Q% x2 L  H7 j) t$ ]1 堆中某个节点的值总是不大于或不小于其父节点的值;" g/ Q% J" _5 Q% b% T
    2 堆总是一棵完全二叉树。
    / g8 ?9 |( n3 P: J9 r其中堆顶就对应二叉树的根( Y9 i3 V0 V  L# {. Y9 p1 Q% a8 _

    8 e1 O( W. R- A, n: K6 `5 V堆又分为大顶堆和小顶堆,根据堆的第一个性质来进行区分! J! I- R8 w5 Z& J5 q: K9 \) s
    + D6 @) W! D5 o$ i; h" k7 S  |4 h  q
    当堆中某个节点的值总是大于它的子节点的时候这个堆为大顶堆,反之为小顶堆
      p. H6 b7 P& n4 c1 G& B& e) ?3 h如何进行堆排序呢7 Z  E) M5 Z( N$ j

    , \; c( D- R  O2 I堆排序,其实就是每次构造出一个大顶堆或者小顶堆,然后取出堆顶的值,再将剩下的值重新构造成大顶堆或者小顶堆,最终到堆里的值全部取出来,取出来的数就是排好序的
    $ H! T2 _1 y, T% K
    9 G- p7 ^1 p* Z# H( M- W& }用数组构建一个堆
    & O5 r5 ^8 F; a4 t% V9 H
    / Y0 S4 A7 n* i' e7 t因为堆是一颗完全二叉树,所以我们可以用数组来对其进行存储
    ' k9 H3 E3 f+ Q$ n9 M对于用数组存储的二叉树,我们可以用如下方法来定义:
    2 K2 d$ r7 U! ?3 t8 b" x! m假设当前节点的下标为 n5 |) H  q4 D) ~3 }# X
    0 E( D; w5 e' e; G5 Y6 _, }
    1、那么他的左子节点的下标 2*n + 1
    . |& J' y( [) I; R2、那么他的右子节点的下标 2*n + 2
    $ T; _9 ]6 K6 P$ @3、他左边的节点是 n-1,如果当前节点是第 h 层的最左节点,那么第h-1层的最右节点的下标就是 n-1
      ^+ a- F4 J( ]8 U0 k6 J( c7 P4、根据1、2可以推出来n节点的父节点是 (n-1)/2,不管当前节点是父节点的左子节点还是右子节点,都用 (n-1)/2就行了,因为整型数字相除小数点后面的会被截断
    * E5 @; C4 ]% h6 V5 W那么有了上面四条性质,我们就可以开始动手了/ V! c" S# e6 L- V( u, _0 [2 c( }

    8 U7 o3 ]# D- F1 E1、假设我们要构建的堆是大顶堆,那么根据大顶堆的性质,任意节点都比它的左右子节点要大,所以我们肯定有个heapify方法,该方法调整指定节点和其子节点的位置,并且继续调整被调整的子节点和孙子节点的关系,直到没有调整或者到数的最底层" B- n1 T7 ?" e# a
    2、然后我们要有构造大顶堆的方法,构造大顶堆就是从最后一个节点的父节点开始调整,接设最后一个节点的父节点是n,那么我们就将n,n-1,n-2 ··· ··· 0,这些节点逐次,从大到小调用heapify方法,这些节点都调整完成后,大顶堆就构造完成了9 v0 x) `$ O' V* e( R+ c' E; w1 }
    3、接下来就开始将堆顶和堆尾互换,并砍断堆尾的操作了,由于互换之前,这是一个符合条件的大顶堆,但是换完只有只有一个堆顶这里不满足了,那么我们重新调整一下堆顶的三个元素就可以,还是调用heapify方法,这个方法会自上而下的重新调整堆,使其成为一个大顶堆, H  [. s3 z3 E, \6 o
    & C/ d" S+ z5 V7 ]8 k7 E4 C( S
    堆排序的性质
    1 _" l5 a/ d4 l5 h. e
    " \" Z& b" M* v中文名称        英文名称        平均时间复杂度        最坏时间复杂度        最好时间复杂度        空间复杂度        稳定性. K/ s+ N2 `$ [# p" T
    堆排序        Heap        n*logn        n*logn        n*logn        1        不稳定
    ( o/ v) B! _- D/ x8 c上代码2 S1 F8 `  y: C8 s

      Q6 ^4 t6 f* f/**  ]: I' _; U# i  U( E0 T- a2 C: }
    * 交换第n和m个元素
    , E" a# l: s7 M3 {. p) w */- ~- @; G) {* t+ o7 I
    private static void swap(int arr[], int n, int m){% ^; `# K- b4 [/ A
        int temp = arr[n];
      ?) _, g/ ?( P9 v1 c    arr[n] = arr[m];) ]8 H, p* }7 l( w* K7 a
        arr[m] = temp;) r4 W3 _+ }3 D( H2 [
    }
    * g* v* t# G. N+ \: u8 C$ b  H& ~1 P9 {
    /**
    9 G% o9 U" [- G" I( p * 调整指定节点和其子节点
    ( Q* u! w3 ]* \# Y& V# i3 `9 V5 J; L+ | * @param tree 整棵树
    ( X7 ]' P; z7 E5 \5 ~. ]. M3 P * @param n 数组长度,树的元素个数: ?: @; G1 P/ J  [1 S* U+ ]
    * @param i 要调整的节点的下标# v8 V1 g; H9 a: h
    */
    1 Y! O) w$ q: Q3 ]" a  t: mprivate static void heapIfy(int tree[], int n, int i){7 z2 E2 N+ C  S' H; N2 A2 n* z/ d" L
        if(i >= n){4 L1 D  D  u' ~# ]( `2 u
            return;% v* V) i& h: x( e  ?) p
        }& A  n8 w3 O* m2 v% q6 ]7 S1 f. f% ?
        int c1 = 2 * i + 1;//左子节点的下标
    : x& Y4 A( ~) P* C- i& u    int c2 = 2 * i + 2;//右子节点的下标! t6 M; f: `* I' b! _
        int max = i;//假设父节点是最大的
    $ @% x- ]! g+ D  [    //找出最大值的下下标
    ' Y$ |, e5 c; O" ]4 ^% F    if(c1 < n && tree[c1] > tree[max]){1 w% B3 K) |( E. M, q  i
            max = c1;6 o5 R! J* K8 i8 C- ^
        }( J& o5 d& ^4 ]$ T: K) d! l1 y, g
        if(c2 < n && tree[c2] > tree[max]){
    8 y( O3 D' Y$ p" h: p        max = c2;2 H: ]% L% f- f+ l& |4 R
        }
    7 e$ }$ B5 {6 T2 M3 T) v    if(max != i){//如果最大值不是父节点,需要做换位置操作- H7 @4 }9 t9 Z- l4 P( Q4 o. H4 f
            swap(tree, max, i);2 P' v5 ^9 }- l$ D$ q: D
            //此时,i节点被换成最大值了,符合大顶堆的性质4 W, r+ Y. {4 R0 p
            //但是换到下面的节点不能保证比他的两个子节点都要大, {1 [8 V" {2 J8 F+ ~; P" K
            //所以被换位置的节点继续调整
    # t/ x* D$ A% c, e2 o/ D0 o3 g. i        heapIfy(tree, n, max);
      W' ]& f$ p  X$ n1 U    }
    - P( h# H+ O$ l$ c% c}
    ' w( o4 i3 F' E4 ]6 c" v2 O! R
    ' M' `2 X& ?" W+ K) ^7 b9 w/**
    5 v4 B6 m) |6 | * 完整构建大顶堆
    ; p1 C# ?: K) p$ x * @param arr 用于构建堆的数组" w5 ^2 K1 M( J2 ^( F8 l) L
    * @param n 堆的最后一个节点的下标7 B6 N2 o- l; \5 p  [1 ^" {7 o% q, K
    */
    ; _3 b) _& ?3 ~: H) t' [+ Hprivate static void buildHeap(int arr[],int n){
    6 Q6 D8 q; v9 Q% X0 r    int lastNode = n - 1;& j/ u. D7 ~5 p7 e1 {+ B
        int parent = (lastNode - 1) / 2;
    1 _$ b4 P4 ^6 }: S! z    for (int i = parent; i >= 0; i--){
    , [3 c3 ?4 S" A+ \" T) W5 Q- b        heapIfy(arr, n, i);
    0 A8 a. l7 i, x# R  \- |    }
    , j+ E6 j. Y% N}2 s! ]- @+ _% C
    5 @! ~6 J! l6 D: c" O4 N1 R5 r$ H
    /**+ U, X* {$ t! U8 m
    * 堆排序
    6 i! |5 z8 X0 c/ N * @param arr 待排数组
    : \, Z% ?2 n4 `7 i5 M& W# p */
    7 G" y5 h6 M1 w9 u+ Q6 p8 kpublic static void sort(int arr[]){
    ' W! s7 B. C8 m: l1 w# N5 I5 G    buildHeap(arr, arr.length);//先构造大顶堆
    - Z) j7 u& @4 w' a4 F, ~    //每次构建堆后将根节点和最后一个节点进行交换
    % G$ X, K1 P+ W! H7 d- h( Q' X. A    //然后砍断最后一个节点& Q: s* e6 _, x8 q( M* S9 ^6 a/ z
        //所以从最后一个节点向前循环
    9 L, k0 K( W7 K& z, J0 o, g    for (int i = arr.length - 1; i > 0; i--){
    3 V! `& m! K& r7 M        swap(arr, 0, i);
    2 ?5 c# @4 f. U        heapIfy(arr, i, 0);
    # u8 h- Q3 l2 t5 i, \+ e    }1 c% j$ k5 ]1 b9 r& W# T
    }, R! i. q) G  d$ L9 G4 P& A
    ————————————————' O# e) Q! |4 I( H- J
    版权声明:本文为CSDN博主「qq_34912889」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    8 H8 |6 U, |& O2 r) {4 I9 c6 S原文链接:https://blog.csdn.net/qq_34912889/article/details/105690644
    6 ]; R7 w7 l, V' L7 a5 E4 t) o$ N+ o" `
    ) I8 R1 k. y7 |, Y, @! b3 I
    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, 2025-5-16 21:58 , Processed in 0.361372 second(s), 50 queries .

    回顶部