QQ登录

只需要一步,快速开始

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

[其他资源] 【基于C的排序算法】归并排序

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

5273

主题

82

听众

17万

积分

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

    [LV.4]偶尔看看III

    网络挑战赛参赛者

    网络挑战赛参赛者

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

    群组: 2018美赛大象算法课程

    群组: 2018美赛护航培训课程

    群组: 2019年 数学中国站长建

    群组: 2019年数据分析师课程

    群组: 2018年大象老师国赛优

    跳转到指定楼层
    1#
    发表于 2022-9-14 16:22 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    【基于C的排序算法】归并排序. b  T  W( A' ]' T

    ' S. w2 u( V4 g前言
      i: ~9 x5 N8 o: x5 F8 a2 h本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。% W* V' l0 S) w  m# ?, r/ M' Y

    : S$ S$ T/ O# `归并排序1 N/ W: U9 P1 a  d
    基本思想
    ! n, l2 u" }4 z5 y  k​ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。, h( }1 ]  \- p* c% X1 q3 s4 P
    - z) c* H. Y, C. F& E5 `# E) L1 D

    ) I6 G1 i  |- S
    ( A" d* R3 |& n9 s- |; M# n5 e​ 合并的思想其实和有道题目的思想如出一辙:8 ]; K& U) _; P8 G0 A/ G
    ; m+ b7 v2 _) I' N+ R
    * I) c- b+ H- w
    6 |6 l( n- y4 ~2 e7 ]( b
    ​ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
    ' g; J5 R- K7 t
    # s1 z" Q1 {! N[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
    / [& b8 {* V& L$ f  e6 T- `+ E/ E% N( e; O# b# [
    int* merge(int* nums1, int m, int* nums2, int n)
    ) j! G, }1 H1 _{! P2 l. k! v$ r/ O2 h  `/ W
            int* arr = (int*)malloc((m + n));( \: O) h. I' n% ]& X% I% q: ]* o) M# n1 e: [
        if(arr == NULL)
    4 D8 x: V; C0 n7 I3 s    {
    6 s: N9 N$ L5 ^9 ]) s        perror("malloc fail");
    $ x6 n- }6 A. W9 H$ X        return;
    + d" @$ r1 r/ `% P1 P2 r( n    }7 k4 S/ \( g: ]  C4 H/ {" ^
    ! B' h5 A2 U. c8 O
        int p1 = 0;) Z1 j& L; V8 u9 I: }' c
        int p2 = 0;0 h1 I1 J% p( P& B
        int cnt = 0;
    1 L( n9 M" W6 [7 ]1 C' J% L/ m# n# Q    while(p1 < m && p2 < n)% M0 y2 R2 h3 D8 j" ]
        {; n8 C% S- q' n( p
            if(nums1[p1] < nums2[p2])
    + X  q3 F& ^; B3 @! m        {
    $ H- ]) x3 `- f% [% n: t! S5 e            arr[cnt++] = nums1[p1++];' }, I6 i' u7 {% m' q
            }* f; E) p" k! D4 N
            else! H7 T3 c+ g; E8 a' L
            {
      a# b5 v7 O* B( |  B            arr[cnt++] = nums2[p2++];4 m4 s* Y2 s2 n4 r
            }
    2 r- V  k+ [5 h9 [    }0 d; D) ?5 r, R1 V
        while(p1 < m)/ q+ y8 N4 m: n* n
            arr[cnt++] = nums1[p1++];
    4 H6 r4 M- W6 s
    7 f$ a8 {! a& Y( \" z/ m    while(p2 < n)  ~- E& Y' Z1 A( e
            arr[cnt++] = nums2[p2++];
    ; P" D0 `, _/ q/ G8 l/ B0 o2 l7 I# c4 e% _; g: o
        return arr;  ^$ a; m( r/ H6 }1 J
    }- i) ~$ L- `) B* D

    & _! M6 k* G8 e6 M; `7 d7 y. |1 ~1+ i5 ?/ N/ U! q+ c, p2 O
    2
    $ e$ x/ I+ M! G# y" i39 E$ I0 w& I4 e0 n) _) z
    4' a9 q+ m# E+ V) n. |( d$ J
    5
    8 \! Y# {2 L  N67 S) D9 F+ ~" f0 h- Q, }% v) F
    7/ f, r* _, r( w& p/ [
    84 l0 E0 m" q' `- U6 T
    9
    0 _3 z9 V( S% t2 T- c- i10% D8 u" a. J) K/ x
    11, `1 w  }8 u0 G- J/ Z6 D: L
    12! a5 X, x1 A) U7 {( Y5 Z3 }
    135 x, g0 t6 N6 h2 i3 p4 G
    14
    5 t/ P% f: C3 Z+ I8 M# {& Y15
      L/ H4 Q0 }& S) {- v% i& q16: w" E7 N- S3 V5 E# C1 B9 v
    17
    ( l5 m3 E3 U  [0 O; W3 v7 c18
    - Z" |2 D: r5 h; m; T( Z) u* J/ K% N3 h19$ o& H: e  ^7 D% z0 Y0 U
    20# D. W' H7 P- @( E( _
    219 W" a3 k' C6 b# W9 W6 z) I
    22$ N0 r% m+ `' x# a: W
    239 o0 h4 X. M0 h  d
    24
    ; J5 x6 _$ c* \8 i0 T1 ?$ Y  A3 I25
    0 B+ G+ p. E  F7 V0 v26! q, H6 q9 P3 I& B: p( D
    273 Z& T0 Y( B- B  V8 D" n
    28
    * `# G1 ~8 b6 H; R. m; B# r29
    0 }. d" q7 H$ b# Y2 x& ~30
      G, k6 P; _+ z* ]% r: B4 f% O31
    1 Z0 C2 i9 R: O2 p​ 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。$ d; y& `: d+ J% M9 d

    % ~; X6 w, h+ r! G& q/ @2 H递归实现- A, p  z' c" B2 Q- U0 x
    ​ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
    $ I# z3 [* L2 O, O1 V" y; N1 h7 u3 b  @: u5 F

    ' @: R$ C- Y0 G
    ) I- i& s3 D9 h) U9 C, @' Q& }/ e7 D9 @  ~7 j

    + n7 @+ X; x. ]5 W' ]: W' s/ Dvoid _MergeSort(int* arr, int* tmp, int left, int right)
    0 ?$ j4 K% ?- T{
    ! N/ o0 @: [  U& h- U    assert(arr);
    . H: R& h; ?( v6 _' D; u$ v+ _& g- c1 ]8 g# P0 L4 Y; _" S
        if (left >= right)//递归结束条件不要漏了
    ' ~8 @0 e6 T# p8 i2 l: X) o5 M        return;
    2 }; R% }& U' \7 Y/ p% u: l% N- K; K! l/ g
        int mid = (right - left) / 2 + left;
    1 T+ M$ c1 U' Z! N; _. }7 U7 U
    4 x5 D0 m: p7 E6 N1 I    //划分左右子区间[left, mid]和[mid + 1, right]1 X+ J: |7 p; l% T* z' T: j
        _MergeSort(arr, tmp, left, mid);3 l+ r& R% I$ A2 r" x% `
        _MergeSort(arr, tmp, mid + 1, right);
    * _& N; t9 r$ o* K7 U9 ^& y  R4 [) f4 ?1 a# ?+ _- S# T
        //归并! D# g' P) [0 N/ |5 F, e$ ^
        int begin1 = left, end1 = mid;
    3 V4 j( h& q, g  L/ Y! }" Q    int begin2 = mid + 1, end2 = right;( p  Y: m9 N6 a1 Q8 F% C' K1 B" H6 }( P
        int i = left;
    6 }( I+ r. p* s    while (begin1 <= end1 && begin2 <= end2)! Z+ ~( |6 e+ `, |$ ^$ K2 w
        {
    $ x: m9 N) s8 h" }        if (arr[begin1] < arr[begin2])
    - n3 C( L2 H5 `- ~7 z5 Q; _            tmp[i++] = arr[begin1++];# j0 x! u6 S) w( @" |
            else
    5 u$ L2 i( u2 [. G! w2 z            tmp[i++] = arr[begin2++];
    ' n5 B* T, }# V0 I+ @1 h; ~    }
    3 B2 p" b8 |" r) t4 A5 M7 Y( r& B9 t; j7 ?% N  k4 b
        while (begin1 <= end1)
    : b* ^( v5 Y7 e  y6 v, O/ z+ o: o! k        tmp[i++] = arr[begin1++];
      j( Y/ _8 e* b: x    while (begin2 <= end2)
    " P, T% y# e6 V7 }4 B$ k$ L        tmp[i++] = arr[begin2++];
    - n9 Q7 J8 [0 `- ]+ K4 o8 B( V: E        : y/ l7 k. E) t! s$ _( Y  u
        //拷贝回原数组——归并哪部分就拷贝哪部分回去
    3 K# R! z: r2 X8 ?! {    //而不是拷贝整个数组回去7 r. I& b) D5 S+ F9 O# q
        memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
    ; W3 P  g" O+ u( n$ [8 I' M7 |, C& h5 a}3 j7 B) ]8 k$ p
    2 u  s/ j! K' X. {" E$ o
    void MergeSort(int* arr, int left, int right)
    - X: H7 \* W+ s7 @{4 X) L) H3 ^" z+ ]. L+ Q* Q$ s
        assert(arr);
    ) U0 O* M; J  ~# Q& h  F
      z8 E# n* m: ?& u% e    int* tmp = (int*)malloc((right - left + 1) * sizeof(int));5 \: `1 C* _9 {) Q+ R, x( h
        if (tmp == NULL)
    4 _3 m8 ~$ X" f( w; Z    {! V) ]. k( M4 P$ P4 c) }
            perror("malloc fail");
    9 z5 H4 {: f" w) m* _) F        return;
    3 E* C7 p9 j, N! `" b4 v& `    }
    . {7 p  N7 b/ M& [+ ]3 P, s# g9 k
        _MergeSort(arr, tmp, left, right);" r- D1 r+ N! l+ [: _

    # Z& V* e) D# @  p- W. V    free(tmp);8 q) C8 k+ L) V
        tmp = NULL;
    . Q5 M3 U5 e% U8 Z* q' ]}" Z$ r* j. D7 n8 b

    3 T" K0 l; k7 y  k1( ^% u. ?. l9 a- [# R  s' I) `
    2
      ?! n" w. h* k6 `: r* y3 I$ a3
    $ ?; l" f4 u: f1 {3 y7 A4
    7 _, ]6 p/ z7 C7 O* P6 O& i% X, A5
      u' r6 R5 P1 J) y! w- h6
    # Z2 T( ~. A1 v# E/ V7 a# Q7
    4 {2 q( m- D% q% C" p: ~8
    1 L; `. j; k/ U+ x! z9) w  Y4 l' E0 u# N1 W
    10
    * C7 V$ k3 E. A: A  ^2 e11
    * _4 Q  _- V: ~  a! ~4 q12. D) W6 P9 R# p" d8 i# X/ l5 ?: W" E
    13* n) q5 V2 H. r% R0 v4 G; M
    14% i1 m" g# {, [0 q! N
    15  H( |$ P/ D  T* [  y2 t- o
    16
    ! ^% f6 T  y9 _6 T17
    9 Z' Q* ?. m% }9 M* \# U3 a; K+ y18* Q, b$ R( v9 B% \0 A. T6 C
    19
    # X; {( q) v+ A6 U- B: w: n, a20
      j" ?+ q. V( g+ p" T/ m8 C21# y: l- C: }, J' `
    22( C. k$ d: a& [6 e5 ]- a: S
    23
    ) k! u: Y$ b' d6 F24
    5 d) S# L1 z9 l( x! \* V+ A5 s9 Y25- e! A4 J, Y. j5 |! A1 j! q3 K
    268 t+ k$ P2 R- v- H: h$ f7 ]% C
    279 u/ s) C& n! L4 J4 r7 J- H: W
    28$ s& E' h: Y, y) p
    29% X: N* @3 D; A7 Z$ m: l5 Q! {" B2 f
    307 M& H: e( Z2 C9 M% C
    31
    5 L* h) s5 L# m, q9 o. N326 K0 ]+ s2 N2 H% M. g
    33: X5 s- y1 m2 ~+ n% E: _8 w8 _
    34
    " F; s# o: Q0 \' g5 J6 L$ V( y35
    % o' ~5 N$ y/ i$ p7 O7 V36" `6 _' }2 x' p: q4 [' |8 X
    37
    % r9 u) d2 D7 @: e- v( s- A6 {( g388 w" W9 {  ?3 d2 ~4 w
    39
    ) {+ ?) S+ A- |40+ C0 c. Q  m; a6 j& h4 H; m
    410 Z/ G: L1 c" ~. \4 O% [
    42! `8 Q1 P' J# B$ b$ U. Q: T) x
    43
      U" u% ~# o) B! M44
    / a! |* M% j8 |0 G; R2 N45% t5 B1 S7 L0 D( ^$ q
    46
    " p' s. V: x5 @/ ?! k) K- j47$ ^9 N. M5 K! J- ]+ [* O
    489 e8 k- s! ~& V9 [
    49
    ! r5 B/ ^6 h9 k' i$ M2 `50
    8 R" ]9 Q; W4 F! m$ U- I. \# o51
    4 C1 F3 T+ f. H3 }1 X非递归实现
    6 q3 K5 e9 J8 u( f! `4 A" t, H​ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
    . W% Z2 E4 F: a7 h2 P' M( @1 i; @2 H$ l/ Y

    9 t  R, k( T' X' t+ U% k8 j# }1 D. n
    ​ 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
    , `: O% ^. }9 Q$ n5 X/ y+ o5 X: U1 M5 {; b7 \8 @- S
    ​ 还要注意区间的取值,每个区间就是一组,就有gap个元素。6 c# D# i7 V% G( Q( A" a0 G) f' O
    0 ]8 i9 [0 a  b2 _" A2 N. O
    ​ 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
    / M, P( Q/ z4 A+ ^: J9 f) J
    + R: ?; Q0 I3 x& }代码实现; c% _8 _4 _1 k3 C% V! O

    5 a- V# `- E2 H/ `* u0 x1 `8 m# wvoid MergeSortNonR(int* arr, int sz)1 U7 R) X2 L9 e! r. v
    {- {1 H( {5 X" P
        assert(arr);
    - }8 t1 P$ d+ z' d( Y+ q! T1 K( t& |3 R; ~
        int* tmp = (int*)malloc(sz * sizeof(int));
    + V3 D9 S/ x1 m9 U0 a) e5 @1 }    if (tmp == NULL)4 Q6 p$ n8 ~: b% Z  I2 E! {
        {3 y9 M, |; F# r7 {
            perror("malloc fail");
    % \; ~1 d* g) t9 O        return;: H8 l3 a  r  s) @6 n  t( y
        }6 v3 d: n! F: [' S  y8 `0 F
    % g: ]( y) j) k+ {, g* X
        int gap = 1;
    / V' V' I; a1 U5 a0 R$ y6 u    while (gap < sz)
      `: E4 n7 Q0 ~! r    {5 _* c  O; l: Y+ E, A0 q" U
            for (int i = 0; i < sz; i += 2 * gap)
    * f2 M1 p, w/ ]4 b0 d        {
    ( u' t& t7 m. |$ V( w$ i6 K            int begin1 = i, end1 = begin1 + gap - 1;
    ! d! X- O3 }. S3 G, a* _            int begin2 = end1 + 1, end2 = begin2 + gap - 1;
    % M& _) d. i5 P! z) q2 w            int j = begin1;
    ! Q2 b$ [6 S% u- r% z- E/ @, X
    $ Q, x7 W, c' \3 r+ `            //归并
    8 {5 N! h* p0 i$ j% Z& p            while (begin1 <= end1 && begin2 <= end2); F8 Y: [8 @, x$ ]& {. w+ S) A* m' E
                {
    ! G- M% v  E  }; U                if (arr[begin1] < arr[begin2])
    * h8 S9 |" y8 L. O- y$ q5 {                    tmp[j++] = arr[begin1++];3 E3 C$ B9 F9 ~0 Z3 x$ V
                    else     ) I1 x' Y$ [1 |) g" a
                        tmp[j++] = arr[begin2++];
    8 X- h) r4 J& J  e0 c1 o            }& s4 I, _3 ~7 K+ _  `9 g5 V

    - Z9 ^$ X5 i+ v( l, x6 a            while (begin1 <= end1)
    ' a2 u) N! r: i8 b9 A: M; o                tmp[j++] = arr[begin1++];
    * k; T. J' U% `  p9 V            while (begin2 <= end2)
    % r0 ~% H3 c1 r0 d: ]' |1 g( r                tmp[j++] = arr[begin2++];! ~6 G* {, O  t( T" p( T1 \" p

    / {" k- B& B! @7 H            //拷贝回原数组——归并哪部分就拷贝哪部分回去% ^5 E3 d  e1 j& Z, P  v+ D
                memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));: e4 K" C2 x5 Z1 u  m
            }8 |7 I* a  [# f7 X1 M
            gap *= 2;, Q. P" ^$ f8 \; P3 F
        }( U! W0 W& O: Q- D# V" M
    5 T3 h% Q6 b* I, t0 N
    }/ O5 b6 p/ F9 e# v+ |( e3 f
    % B8 P+ }+ }: d3 \
    1
    & Q9 o$ N* K; a4 ~6 I" u5 Y23 W' v9 F+ E& z% \, H
    3
    7 J. g+ `& a+ @  N4: U. D, R' l; C9 X( W
    5. l+ e5 I3 m0 o* y
    6: s. J4 G3 m! x6 Y: I" Y
    7- \1 O5 }, o# C
    8
    $ N$ k( g7 P7 F. [0 ^) L9
    6 f- Q- M( D/ y" S9 L10, F9 P1 f0 q- Z2 }" i
    11+ T* k: y/ \! ^
    12) R: r# |* T+ E" U4 l! s
    13
    , j: P8 ~! |" @9 [3 d14# D" v* ]  g1 h* Z
    15
    5 i# v7 q- E* l5 y. s: e% ?3 r( K16
      X8 v& I% b: Z2 b& ]' W6 ~179 r0 g! G+ U# v4 B
    18* r' }2 {+ |; P6 {* z
    19
      X7 }' ~! e; a( Q' D" u! x0 P20! l  }6 L0 F! i- S$ k5 x* Z
    21- c, A6 y. f, l+ p# {, M' s
    22
    . P/ c. ^1 R! G23% J1 B* b1 P  J' g- Q
    24
    . ]- Z& j) [8 P# G. }% D2 l25
    & P7 Z- |& M3 G; U  n7 \2 H26
    7 z- ?3 o% X7 z" A2 S% h- L9 p1 n27% k, o2 L! H& l6 _; G
    28: \/ x, r* x/ Q" o/ V* j' ~
    299 a3 B0 \1 G; m# Y( o$ K" u
    30
    $ b* f0 r8 u$ z31
    & B/ @- {, a3 L( I4 u8 ^% h323 J0 z9 H0 V. s; @
    330 {3 ?- H& ?: [
    34
    9 [4 }3 m$ f5 p$ {5 |3 `359 i6 t# R' w/ r; l
    36
    + A  b  X) r& w2 W" P376 @% ]+ s1 q( Y- @9 q  z! u9 V) l
    38' K( I7 O  @3 G( C$ Y
    394 \+ e/ l0 J2 r; \- A
    40
    0 ?' s5 s. j7 D4 H3 ^1 Q412 t, H+ [3 E5 i: d) a; q+ T# e2 J9 j
    边界问题
      C) f* z; Y: {+ Q1 t* K​ 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
    2 c5 @( H  L2 w" B) \
    6 K. ~; Z' L3 E7 Z5 s* P2 k举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:# j7 y6 Q" ]4 `! }
    9 Z' p; Q& a' e

    , E9 ^$ O% T- r) }) g( q4 v9 G4 N4 x! {' Q2 V9 d3 U7 i0 x5 W
    由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
    * j; }/ w$ R0 V& w' l8 ^
    8 M( K" z2 g$ U* |! `3 o第一组越界(即end1越界)
    " A5 l* z2 S" \/ x. m2 D8 F5 K3 T7 S2 [$ x6 w
    应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。: ]  B5 W% m$ Y; n9 r: P) ~9 q

    & h9 H" h+ D+ |6 ]+ ~! c0 a第二组全部越界(即begin2和end2越界)
    8 d8 m+ U+ q  P: i8 V. D1 y" O$ D# V1 N# h, Z+ Z1 c. f
    应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。1 ~2 w6 N' x, K
    # o1 \  y: Y' Y; c
    第二组部分越界(即end2越界)* {+ |& h, Q- \9 Y9 l3 e4 F5 o) ~
    4 u5 R4 x1 l9 S' D( D' C6 K7 O8 ]
    应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
    ) d% Z! l' q; ]1 d) ~0 K  P5 ^) @: |
    ​ 其实第一种情况和第二种情况可以合并为一种情况,原因:- ~. S1 {( `" A; x- Q; |
    7 n8 M+ ^& l; `2 {) f3 z  d6 ^: p
    ​ end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
    : R) X: H1 ]% \$ n+ |/ _: h+ N3 ^  D4 I
    ​ 拿两个数组试一下:
    : `% q5 v& r# V  o8 P5 |2 h$ i9 x* L8 w5 B6 @$ P6 e, K
    & |4 h( t$ L8 P% ?7 [! B
    * ^& h- [& i3 J, B% {+ l

    ; I" @' e/ l# {/ a( y% F2 p1 @4 }( q4 C/ ~7 [
    代码实现
      `7 C$ a7 @1 j4 c- o, P" p- f$ `8 j/ F2 [- Q$ W( W* \
    void MergeSortNonR(int* arr, int sz)3 L2 v  w: G9 w- \
    {
    8 ^- ?! P. }3 ~2 j6 u8 X1 u" j$ L    assert(arr);8 W: J8 t* ]/ X1 ?1 X% ?
    * U+ y6 o# S2 @; h
        int* tmp = (int*)malloc(sz * sizeof(int));
    & a# M  C* H$ ?$ s7 ?( I3 L    if (tmp == NULL)$ T! C! F7 Q% Y' s  x) ~8 V, u* O
        {) [* f: N* H$ e: |
            perror("malloc fail");7 N# F5 M# j2 l: @' l
            return;
    $ \) c  `& F3 u# w, N% ?# ?1 A5 I( Y    }
    : h  R, i9 H* a: g$ M) }: A# X* H. `: m, @: G+ H
        int gap = 1;1 c7 X: l0 O% y. g& P* c
        while (gap < sz)
    - X. N3 J2 T! j2 z    {/ I; N$ M( z$ I. u
            for (int i = 0; i < sz; i += 2 * gap)
    ! x' S) y% S+ @$ S! Q% c, Y        {
    " @  |1 V9 ^9 o6 l+ X/ s, U7 g            int begin1 = i, end1 = begin1 + gap - 1;5 j0 N0 ]5 E- X2 g
                int begin2 = end1 + 1, end2 = begin2 + gap - 1;1 V  e  S2 J" H4 S* T. N# I
                int j = begin1;) D8 b: e% q8 `3 d
                            //越界检测$ O. F& `$ H. I' Z
                if (begin2 >= sz && end2 >= sz)# p4 W, b! k( W! L7 ]: ~2 m3 X
                    break;
    - c! j1 F& f# A            if (end2 >= sz)
    . F) B2 K# H/ y                end2 = sz - 1;
    8 M/ h3 l* u4 j) w' n            //归并7 }; x. o4 v7 V
                while (begin1 <= end1 && begin2 <= end2)9 b: c; \: X; J. \! i
                {9 a) j9 H! F" T8 W5 ]% x
                    if (arr[begin1] < arr[begin2]): p2 _: D1 n. Y5 u0 |) |9 A
                        tmp[j++] = arr[begin1++];, q  t" C# ?* f0 o3 U+ j4 O- H- V0 ?
                    else     
    ' e* C- Z9 C2 B6 x0 G                    tmp[j++] = arr[begin2++];
    7 }7 Y; [1 h0 q, W            }
    " d" k( r9 W1 u) |
    3 s! M" v9 f6 f# [4 Z            while (begin1 <= end1)/ z9 [+ j' g- {0 g. P
                    tmp[j++] = arr[begin1++];2 o$ ?8 G; B- i' u
                while (begin2 <= end2)
    1 |+ k5 G! H  E( k/ g0 Y                tmp[j++] = arr[begin2++];
    " s' W! N# V% O2 U. \; }
    # S9 i0 Y5 ]3 J" X6 f  r            //拷贝回原数组——归并哪部分就拷贝哪部分回去
    ! c$ }4 K  l# ~, d6 |( K            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
    1 G! E+ P" O1 m; \" o        }
    + q/ x& O' Y( t( c6 G        gap *= 2;4 O2 ^4 Q: F% G$ _" W0 ~5 L3 J
        }
    ; Q6 d  B: @# W4 F: d2 L6 n9 c$ ?5 u3 e' `
    }8 V2 ~/ T' X7 R- U

    1 b: q, Y8 \, l% f1
    8 D, R4 P. w: I22 F3 {/ w3 y& d
    31 d3 Y0 }! o  K4 ~. o& a
    4- ~* ?  m! c2 o% ^7 g
    5% n6 O2 e8 n! [1 c2 X' E2 S) Y
    6& @1 G3 p! r3 t  c' [) b7 T- ^. Q
    7! p) ~. D2 h  d! R. p9 d1 k& K5 V
    8- q: g, P9 H2 A3 }# J1 M. {+ O( {
    9
    ) k0 F) m4 J4 ~3 C+ k: g5 O; }% l109 C# E6 X' U  @# `+ N" K
    11' l: o1 V; f# T! t$ m
    12
    ' o( a( K  L; A/ Q6 D: |6 S135 M2 R# p6 O* G- }" }- Q
    14
    3 A4 H* O; S2 _15
    ' l7 W' `8 @- m( m7 R7 e16; L. [0 f3 q" Q  H( M7 ^' N2 J* D
    17
    0 f( }* P/ O  ?1 l18
    % e9 d8 O7 }- r- ]19
    0 _. w- G2 P6 P( s: m20
    ! e* ~' k9 F5 A. c# v8 b% S; Q" W5 _21
    " U7 |+ u  D- j% r4 Q220 k: b9 ?: k' D% Z: s. n
    23' {% H- J: Q2 x& M3 i
    24
    3 `# |  ?& J, N, [$ c+ _25
    ; A* T  ]2 Y2 g5 K2 w9 L6 z# Y26  P7 {: Q8 w! V0 Z5 T
    279 i: h0 F! o% H7 Z) }- n
    28! E; Y3 c. T* |" N- B) E* c% X% i7 I
    291 b3 R  E, F0 w5 {- ?* u0 M
    30( n; J( Q: ^/ [) j
    31
    8 D, Y4 Y" R$ r8 k8 |5 i& r' D32, a0 w8 U/ n# U% }' {$ a; o
    33; ]6 I' r# U$ s, j8 n$ S. g
    347 D' t# V0 @* W# q0 f7 E
    359 `% U$ v: @6 O% R, V
    36+ u+ j3 z- x  h+ s5 d
    37
    $ H, _5 a; \! D. }38
    : Z  ]* x. T& Z5 ]9 S" ]  [39$ J' D. `8 s8 d( i
    405 t7 j5 u# ]/ l5 ]% J
    41
    / z" X% G7 T( e$ P8 G42
    # b7 q1 J4 r* A! X% S43# }* R6 S! W" ~3 K9 H( q  K( ~
    441 u/ S, m4 _9 x
    45
    " @5 _3 t" n) [& ~* K归并排序的特性总结:9 B2 g2 U4 u2 j4 p7 `

    5 ]  h. W6 c. E9 x/ g2 d7 l归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
    ' K* v+ k3 P7 \! H" j时间复杂度:O(N*logN)3 ~% T' e" ^, s# n/ ]; s, w
    空间复杂度:O(N)
    2 `6 Z9 f1 F6 w) d% i5 Q稳定性:稳定
    : C9 u! _0 i7 r, M% A+ v
    ' N' I2 U5 ]# Y6 s————————————————2 E$ V- V' @+ B) Q( b& L3 E' X
    版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。7 s9 l. M$ C: r3 Q; u
    原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
    # m5 j3 e; O5 Y6 B
    ( [  Q. r; C( }+ [$ v) l$ ]$ B. p" Y: Z( Z7 R( G5 ~) [7 m
    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-10-8 06:30 , Processed in 2.586998 second(s), 50 queries .

    回顶部