QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2893|回复: 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的排序算法】归并排序) Z& _1 G* ?0 W; b; ^, Y

    2 {9 H; p0 k8 x# c' \) T前言' ]: G, n' i/ Z
    本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。# F/ D6 s* t6 U& i
    + s% I+ L/ R6 M' ^! ]
    归并排序9 u5 j( m- g5 T
    基本思想
    : i5 j1 E! \! i) d6 j' K/ B​ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。' S. r6 d% G. L) W
    + h5 P. c& l1 i: f3 [0 V
    ' y5 c1 o' q8 u% D
    , K1 }/ e$ m/ e0 P8 J9 Y
    ​ 合并的思想其实和有道题目的思想如出一辙:  `# w% k6 S% u. A( u

    6 C. S) T5 I$ v+ Y/ q! Q5 w5 |9 C* s7 [2 Q
    6 V8 v  A& S2 W1 L! y
    ​ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
    ( k* ~* \' k  o) r8 m% Y
    ( D3 m. {5 [" y# p8 v# F1 ^[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
    2 h) q8 z3 B  A; F$ m/ S4 \7 _
    5 {" s& x. e4 e* ~  lint* merge(int* nums1, int m, int* nums2, int n)
    , l4 T9 U  y2 G& ]{
    # s; }4 D  h3 n- X  F! z# a        int* arr = (int*)malloc((m + n));
    + Q+ ]( M+ h+ v! j5 S# ^    if(arr == NULL)% @; Z  y+ n1 X' I& o$ Z
        {
    - K! k' B4 i; W! h0 k        perror("malloc fail");
    * K5 k( m7 ?2 z- r; c8 q5 u        return;1 B$ b9 S. ~* ~) N! s
        }( @* k2 N7 U8 Y- y- m

    1 P+ x1 [1 Z1 i6 Q8 p; E. j    int p1 = 0;3 B% }- W1 Q& Q3 M0 o8 ?4 M
        int p2 = 0;7 `" G/ @7 I5 a% \6 o0 a
        int cnt = 0;: }5 O9 F' |& P1 s
        while(p1 < m && p2 < n)
    5 m7 `) v2 y) B+ x0 \% ^$ o    {, D7 M3 f3 ?- q5 J' x
            if(nums1[p1] < nums2[p2])
    " i! i2 ?8 s9 l/ n4 I8 ?; Q        {
    ; U5 x9 P( T, n4 C            arr[cnt++] = nums1[p1++];
    1 w4 y; n5 [- E7 i2 Y2 Y7 s        }/ X6 C% y: O7 j! y0 O
            else
    1 N( ?6 r; G# u, k. C; Z  i! d0 H4 o0 A        {
    . A0 P1 Z1 J- @8 Y6 w3 F3 B0 b            arr[cnt++] = nums2[p2++];
    4 O* u, s& m" s- r" F- e& i        }! N  U  F  E* F) f2 ~
        }& e1 G; _% t% M8 M1 ?( J6 y8 U$ D
        while(p1 < m)- r! x3 }$ a( h9 o# l
            arr[cnt++] = nums1[p1++];
    # p; [& I' b8 Z& ?. I5 v! i. W& W. m( f0 e, ?* d4 _$ H7 |* |
        while(p2 < n): w7 l$ B" Z0 V% d4 |
            arr[cnt++] = nums2[p2++];
    , e5 P) U! D' k4 v3 j$ W7 ]8 H1 {6 ]( J' q: p3 X0 p  X
        return arr;8 {( r, n2 _1 u& y. @: P0 B$ A, Z
    }1 {8 u; ~5 o  Q% N
    ; w' n/ R9 _9 N; Y
    1
    # W7 D! a4 a( d, L2
    / u  Z# d( w$ o3
    / t, C% J4 K( D: j- l/ j0 s' M+ {& c4
    " g! n- `1 N" ~6 j3 c( Z4 j# J8 G5
    % N- c8 I( w! R0 N0 k( s6% J7 @' N( j" _) d; ^" \$ D
    7. {2 i; X. y9 _
    8
    3 e9 B: Y  q4 H0 N' r- R# K0 v. W4 t" l9
    7 i2 U: i% y8 @1 X3 G10, W5 z3 j' Z( J5 o  E+ G# [" V- {
    110 u2 b4 H$ }3 D5 \2 K
    12) W  w! T/ d: Q+ R% m; J" o
    13
    4 `3 m* m5 k7 z, i4 k$ d14
    7 p  \% B' K& y9 \1 R" \  B7 U! b+ H2 _15
    # e9 f4 J4 B5 ]' U6 ~& S( m6 j3 A5 `16
    " ?0 \- K( ?( }4 @) V3 {/ P17
    7 y& W( l" R. t1 k* s7 U/ L+ p% z182 R( N9 D5 K* \- [: n
    192 D! ~' I; \1 N* d: z4 A
    204 d/ f5 S1 Q- i' j
    21" D4 E' K- D& R7 U
    22
    ) h4 N# H6 h6 x3 q5 J/ L239 d/ |2 x% R1 D: X
    246 _8 S* G: G5 q: }; r( t
    25
    ; z4 _2 _+ S( {# \; A/ ^! j4 p/ n26* Q9 _4 n8 j3 `; I( d* f. j" M
    27
    4 b0 D. N! O3 R1 Y$ P7 [9 Z28
    $ }" X  k* n0 E4 |" \. Q29
    8 i/ ~6 \: b  X3 T; @, V30% n$ c  H& A) M6 {$ E
    315 k0 \/ n6 F' c! `7 u
    ​ 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。6 a! z1 F" {5 y; i) p8 N4 c
    - Z! q1 y5 Q" d3 Y) X
    递归实现
    3 F6 k0 D8 L! W​ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。* O  v& P% E3 P. m# T5 I" z& g
    2 U9 S* w$ x/ U- B6 @

    # M1 T! O9 p2 d9 }7 a9 h+ S$ d/ o4 v7 u

    * r" k! M$ {5 f/ j1 N/ K& w9 z: }
    6 V$ _: |! k5 X% Hvoid _MergeSort(int* arr, int* tmp, int left, int right)$ `8 t9 f/ D  ~5 L
    {
    " n1 Q. v7 @9 k. w    assert(arr);
      j8 L$ ]5 s( |& b8 L# w6 U, m2 Y4 u$ H+ i
        if (left >= right)//递归结束条件不要漏了/ E/ J- q# P0 x
            return;: |& n/ j/ Y7 C9 E

    ! t4 p" ?& s$ O/ V5 y  Y. v- Z    int mid = (right - left) / 2 + left;
    % {% }1 X/ u# ]' @$ p3 u# J5 f1 ]' ?9 I$ k
        //划分左右子区间[left, mid]和[mid + 1, right]
    + R+ M! r" B( }$ Q) d1 ~    _MergeSort(arr, tmp, left, mid);# f9 T% @( x7 C6 u$ H3 n" |- q4 K+ w1 f
        _MergeSort(arr, tmp, mid + 1, right);1 A/ p3 l' U* f7 P0 s; Q2 u
    & e8 t- W- y: q' a$ W5 k
        //归并
      {$ w3 }. c, _    int begin1 = left, end1 = mid;
    - T) Q- U9 |3 N    int begin2 = mid + 1, end2 = right;4 \8 C$ L" \' L* t2 k  K% A6 K
        int i = left;
    % F' k: F# }- y  E0 r$ I3 c' b1 s* \    while (begin1 <= end1 && begin2 <= end2)
    + N' m9 t$ R8 q7 `# y    {
    * g, T) N8 A5 ~" g        if (arr[begin1] < arr[begin2])- E5 Z9 x. M4 V: S) Q$ u! X" c
                tmp[i++] = arr[begin1++];
    6 ~* y, V# u* E% D" y' m        else
    7 [* u" y7 u$ V( a' P            tmp[i++] = arr[begin2++];
    8 O/ b* O! I& d0 `( M" q: k    }/ E, ~7 b) r! w( q; \( s! g

    4 t3 N7 J) r$ B. w    while (begin1 <= end1)8 A  E2 D3 N. z5 T4 u: h
            tmp[i++] = arr[begin1++];
    - o6 g2 j' u/ H) }8 p    while (begin2 <= end2)
    ; F5 V! L0 l( s9 U        tmp[i++] = arr[begin2++];
    & M! o$ S6 Q% O# P( X9 h- G5 o7 e        ' l3 N2 n# ^5 Y9 _- C5 z
        //拷贝回原数组——归并哪部分就拷贝哪部分回去$ `. A  o  L% @, h  G: M$ _
        //而不是拷贝整个数组回去6 p! y' M3 r( B8 T! m
        memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
    # Y# M4 g, h8 O}
    7 d' F& P3 |( {" q% i/ ]5 w  W' h  a6 m# F& l
    void MergeSort(int* arr, int left, int right)7 v2 L6 }9 T9 }& ^* v  d- Z, K
    {
    * J. z! R9 h( v2 A0 h3 {    assert(arr);
    3 T# l+ P: |( W. A( e0 p  e& Q. N# M3 |$ Z
        int* tmp = (int*)malloc((right - left + 1) * sizeof(int));$ b" _0 n) L7 e$ X
        if (tmp == NULL)
    ! G; G! s9 B( p7 H' e    {5 e; S, [. D9 T0 l+ v% W  r
            perror("malloc fail");
    5 a8 D, p. O5 A- z" m8 Z        return;
    3 w! o1 {; z8 I9 F% N) O  c  B    }9 t! I9 @% i+ X+ }0 r
    # }6 `* O0 k& e5 }- f+ \
        _MergeSort(arr, tmp, left, right);
    4 t2 [9 W, q- N1 h9 O7 N8 [' J! y8 `- x7 R3 {, {$ }( h+ S
        free(tmp);; Q3 r- h5 ?. ]+ r, y
        tmp = NULL;2 H- R- W7 C4 x4 k% u% x- g
    }
    2 a0 B! F# {- s1 l5 B$ G# ~/ |& C2 v. Y
    1; P0 P9 M  y2 ^/ P3 ~
    2; |, J$ T( \1 F+ q6 y
    3
    ; g% I( c& }. R  N& Z4
    $ B+ F  O' ^' I7 T: M% W  j54 O4 G0 i' \$ P& e  F
    6
    4 Z. N( \2 B* i, g74 A, g( Z; q: b; _1 v. Q
    8
    5 I( h: r9 S; T4 C) X2 s95 ]1 Z- k/ m9 h* y
    10
    2 B' R" ]1 R) W1 h1 ?' \; f11& o/ N1 T. u. k0 O- v
    125 [8 v# y. d' F% i; ^6 \
    13
    . x! z" Q9 n0 H$ q. X+ v14
    / F' Y% @8 \5 X. M" P- Z' e% a1 s# t) }15
    ! G4 X/ \" m9 _1 y8 y16! Q. j8 ^8 Y, d. y! L- u
    170 K  `/ a. }! [  ~
    18
    1 @' G2 J: p0 e% d* ?19& h+ i' r' W2 f8 g5 Q
    20
    + Y9 {. j' j: y9 |6 t9 x. P; P21
    + e& @) |  Z$ z+ {22. o; |  w- z1 G1 D/ Z5 u
    23
    - j! ~+ H% I0 z244 _9 g, S2 Z7 _# D. L- C- l5 y
    25  d! v  m1 r  {
    26
    8 d6 }9 }# R9 F4 y. D1 ^27! y$ t( b" J5 @7 f) ~
    28
    8 i5 F6 W7 M! c% o. h) W29
    - P3 P' q3 ^, H5 i9 d; E: n30
    , ]/ B# D6 U9 ~( B/ c; L8 h31
    ' P1 }" q- p& M4 D; A0 D32
    ; k2 @' @7 O- G5 u* T( m0 U, W' f: C33  D* n; |% J" d$ u2 v& \8 K9 l
    34! q! J' k# ?1 \3 @4 l3 d0 o
    35: k3 c- |) l/ e6 }7 x
    36( K3 ^. A. B, @
    37
    4 R9 m. R% }  v. Q$ _8 S38
    - A3 X% a0 w5 y) s0 i. S) E39* P/ ]- X' W0 x" {, K: Q/ D, U- X
    400 @; z% U, i: m  Y
    41
    : _; f9 U7 _2 _; X42
    . P: ^1 F9 ]( y) h7 J' s+ u- K43: U; ~2 j8 X* y" t5 i9 {
    44
    1 ]; S! t3 Q$ A5 h0 e0 l, q* t45
    % n1 g2 w2 }, H, D* k7 x6 l& {46# A, G  S& S& a) @" Q/ X# E
    47" o0 j: T  a+ S# c0 P* p
    48
    " D9 w+ z3 y+ R0 G1 c& G49
    0 D5 n* ?2 T' ]9 a50: l+ G' E2 _  p- t$ P0 }, I( V8 J. _
    51
    7 X0 b- @# a3 G' h. v$ I, [非递归实现$ Q: ^3 O  f* |( f, A! }! t
    ​ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
    % W: x2 k+ I2 L  ^+ S( I- w
    7 K" S" M7 O& \' B+ d( X, S- L
    2 s0 V- g1 E, s. X1 x' k
    $ N! I" z. D  y$ O3 h​ 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
    % s  ^$ A1 z7 W' g" u% L7 @4 y' C' a6 s. g8 B
    ​ 还要注意区间的取值,每个区间就是一组,就有gap个元素。) [" u; u. ?" K5 b/ G8 e. b
    6 L9 g7 K' M7 ^% F+ F" @! \
    ​ 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
    5 G$ R* T( ~7 |9 w+ P8 C/ z6 c- x8 z! H5 V6 w0 e  _. a, s
    代码实现. G5 X6 f5 h% z& f) _

    . L+ ^2 V  U& U2 U3 P! ^void MergeSortNonR(int* arr, int sz)
    , T- w: n7 ~4 w+ @; J{
    2 Y4 P' t& ~4 O9 o4 a3 M9 X    assert(arr);! S! _% B* y* w* n2 ]& p3 h7 z; d

    : l: P5 J! ^: k& ?# T) U) Q1 Y' {. p    int* tmp = (int*)malloc(sz * sizeof(int));6 E* ^( a5 |/ Q! @" U' S
        if (tmp == NULL)
    0 f4 H  G6 R, A9 ]" f    {
    3 |/ F. J6 |9 l" U        perror("malloc fail");, o% M) T, i2 H7 c! _/ E' c
            return;
    ! y) {0 o" y0 @    }
    6 i8 B+ o! v9 \; N. f" J) a6 h8 }5 n4 M
        int gap = 1;" }: S5 S; X, e: b7 Q9 `4 D) b
        while (gap < sz)
    ! j) @. z5 `; J/ l- u    {/ J: Y5 d# L: A8 q9 N
            for (int i = 0; i < sz; i += 2 * gap)
      S5 Y& O% E; m        {- |5 F' P* R; q% A2 K
                int begin1 = i, end1 = begin1 + gap - 1;
    8 \" d& e( a" ?1 C. A  F" R1 p            int begin2 = end1 + 1, end2 = begin2 + gap - 1;
    " o  y/ v, D6 u! _# r            int j = begin1;
    ( n1 o* [) [4 N; o5 T5 K8 J  l, r: t) `5 c8 D1 ~2 c# s/ n8 g% o8 u
                //归并
    # ?+ m1 Z" ^) M: m4 Y) U            while (begin1 <= end1 && begin2 <= end2)
    ( j1 R% V5 J. ]; d0 y            {
    + t, d* z5 A! L& m# z  c$ {                if (arr[begin1] < arr[begin2])
    . ^! m" g6 J' Q' u7 [# a                    tmp[j++] = arr[begin1++];4 r  W7 m/ _/ c; a$ T# G+ E. o
                    else     + A: D, M) W7 [6 J7 E1 x3 ]; d  S
                        tmp[j++] = arr[begin2++];3 g( L2 \4 Z8 r$ H: P6 V7 J4 w3 x3 i
                }3 `0 y# C, f  v  K5 d
    + I1 n: {* y# y
                while (begin1 <= end1)
    # U/ |8 n! N) I% a  C  q                tmp[j++] = arr[begin1++];2 H: G- G, ]3 Y% _2 W. P7 G3 ]
                while (begin2 <= end2)
    - j$ ]0 @" V/ B$ W4 ?3 w' _. N                tmp[j++] = arr[begin2++];
    7 G" Y& R& ]& C2 X* j: }
    % ]- `6 M* k" |2 U7 `            //拷贝回原数组——归并哪部分就拷贝哪部分回去8 c8 W6 @" ~9 g" ~' x
                memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));) A4 n" T. c$ Y$ W+ [  t2 F
            }
    ( m& }+ w. J: K1 ^& R7 S/ \0 K        gap *= 2;
    - ^7 ^5 i# h% ~2 U( p    }
    3 C; [9 X' N& ]# j5 m1 X* G4 ^* p6 B" w' u
    }) W- d& L1 _) o! V- r2 l

    8 T4 n, y# [$ V+ P0 K; S( X* e- Q18 r3 Q6 w" ?' e. a% D# E
    2
    " M+ [2 W% W: o' m& x/ `38 w8 C: @- [8 ~& ]( e
    43 h) z8 s' a! X& w$ l
    55 X* x* W) p( G5 ]( x( e
    6
    / @0 B" x8 \# A( s3 D/ v! d7
    ( l7 F+ s1 o  Y1 n8
    9 H6 Y: H* A; |9 h! k! i# h+ k9
    ( G" A0 A" Q! \- `( j10
    ! p% M! [0 l2 }; M* o7 u2 S% P1 j11/ `7 ^6 R$ F+ i! O2 }1 F
    12
    / g, c3 F% |; M13- O" {! _7 U4 V  ]' A% H
    14
    ) T& f4 Q0 D0 A( u8 E& z0 _15
    ; x- J. @+ i( W4 n& q/ _- @6 V16
    $ M; m# c8 k# U- ]0 D6 f17) P4 k2 T9 i  ^; _
    18
    ) w0 g& Y+ j8 P( |# z0 h4 p19
    , P8 g1 L3 n: S8 P20# X" H# X8 R* }6 d5 P9 }
    215 @& D; `( r& n/ H# q1 Y
    22
    / J& ]$ G; O$ I6 V$ A234 B4 c. W: m2 q* d/ Q  O" E
    24
    3 H  z$ ]4 `4 i8 D25
    6 f5 `' s* d3 |26
    ; B  r6 b4 a+ P2 p0 ~* Y+ r27
    9 E3 Y5 X5 s' `% Q4 N+ x4 ~28$ p( Z9 k/ S4 s. m0 H
    29
    2 }- F, j4 }6 P/ l1 |; J4 k0 o30
    $ R; j- t5 b; ~! y* k8 f' ]4 }9 l31
    6 r* M, U4 s1 P2 c0 L32
      @8 N* D! q5 y# C- X2 l7 M+ m33
    * E' L) S( e$ `34
    5 s" Q+ }+ j0 j$ ?& f. X7 Z35
    9 s& i6 I+ K7 a5 h$ Q: R36
    . A1 J8 ], W% ?& j! B- ]+ _37) p  }$ l# ]  [
    384 L( m6 f$ L. N+ D  M4 n- x9 R
    39- O0 Q/ [; ]; `0 Q3 r/ z5 [. A
    40" q& b* v" Q8 B0 i0 b" Z4 v; f, q
    41
    ; h% ]% g! b, d+ a边界问题3 A$ C) m& m7 K$ G% v. e7 R
    ​ 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
    % Z. _0 F% p: Z8 A( ]5 ^+ o$ r9 l8 |5 r4 b
    举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:8 [; d$ f$ m7 O1 m# @: }) W
    2 t# C! t  n* s& W! ~$ h
    + E  a  t  i) [3 _% f- t
    6 a. C+ ]9 c" m; c
    由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)- d' h) w3 N& o" j+ {( _, r  L2 V! W5 ~
    , r) Y" Y$ y3 ~  ]" I* m3 j7 E' s
    第一组越界(即end1越界)
    2 X2 y. T, s) ^: ]" s5 i
    ) ?/ @# N1 b* ^, v1 L应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
    ! @' S1 Y; ?' [
    . g. u& c% a2 h2 B4 k9 n第二组全部越界(即begin2和end2越界)- U: m9 k  T) l- ]
    6 A* [4 _) {6 i2 d: w, W( N* }
    应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
    - v/ ~) F- Q  u5 o9 L% b4 |8 o! Y4 f: m' O( u9 C5 o3 l/ \
    第二组部分越界(即end2越界)9 W  I/ m" \3 T0 t1 G

    ; S; h$ m: p) S& |( p% \* Y1 p3 j应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
    5 I5 u+ Z  ?& K9 I3 ]0 A3 Z
    & {" y" k2 ?9 Q* n% \​ 其实第一种情况和第二种情况可以合并为一种情况,原因:
    5 M; ~) |* C+ c! g* M1 n" v+ ~3 P: _
    # ?0 n! C6 n0 u0 ~6 T+ Q​ end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。4 S3 h$ v/ d+ W% Q, v2 y" k" }
    1 K5 S) c$ J5 b- G; k+ P
    ​ 拿两个数组试一下:( q" ~# G9 ^( n$ w$ [
    $ d* Y2 ~4 S. ?
    / x5 E9 R+ {6 n6 Z; h
    ! @# I+ P+ _% n: k

    5 Z7 x% B0 E$ R+ R5 A) x$ W" L6 m1 Y$ {$ e
    代码实现
    7 p0 L* o. R5 V, j, n6 [+ @1 ~/ k9 F: ]" V, c/ O: x
    void MergeSortNonR(int* arr, int sz)
    3 J4 b" _# j/ |9 B{9 z8 t, }- }7 {7 c
        assert(arr);
    ; S: m- _5 I5 F6 _* ~! \  ~
    1 }+ ^  f- {7 J; s1 p    int* tmp = (int*)malloc(sz * sizeof(int));- h! q( c$ Q. C  Y- _1 n
        if (tmp == NULL)
    . A: z; P4 U, l! d4 \3 K- g    {
    0 o! N+ E( p& J5 ]5 X        perror("malloc fail");
    3 X1 o2 A$ w4 `) |        return;
    . d( f4 |: [$ c! f/ Z, I7 m  k- B    }) q* J  N, I8 k. z7 y. Y

    2 x- Y7 f' l) o+ d# s: e. K    int gap = 1;
      L0 L1 a8 o* f4 B0 Q% L    while (gap < sz)
    + _5 R' }9 ~! f    {/ u& u& E! \3 ~* Q. R2 Y; [: l
            for (int i = 0; i < sz; i += 2 * gap)
    5 v& @; }$ N, g% I3 y4 W        {
    ) _8 k. R. T8 [% _: m            int begin1 = i, end1 = begin1 + gap - 1;
    ) ?! y+ y' n' f7 s( ^1 O0 d            int begin2 = end1 + 1, end2 = begin2 + gap - 1;, n6 z. J2 {! w% |* ?( k- k
                int j = begin1;
    0 `1 g* I1 t( C  q- w- e                        //越界检测
    : e4 [7 ~7 R( B6 @# ?  z% S            if (begin2 >= sz && end2 >= sz)
    5 U5 r& [2 g+ p                break;6 d9 U, F1 @; o, q
                if (end2 >= sz)
    # @- Q3 C0 Q. j2 j8 k6 u                end2 = sz - 1;& l4 N  I: {' n6 Z$ a4 S# }: W
                //归并/ D3 H( J0 p; u* U
                while (begin1 <= end1 && begin2 <= end2)
    " D9 q1 R& q8 M            {% Z: r2 b7 x8 T
                    if (arr[begin1] < arr[begin2])
    ' q6 I; o! a; _                    tmp[j++] = arr[begin1++];: B$ y& W  x, i. K
                    else     % h* H/ P  q& V  `1 t
                        tmp[j++] = arr[begin2++];
    4 ^, `3 Z9 K9 d" {3 @            }
    ( W0 e+ r' @) H( {. c" b
    + d4 o# n4 o. h3 x9 L& M$ w            while (begin1 <= end1)
    . w& x$ u7 S4 G5 b" g: ^. R. N                tmp[j++] = arr[begin1++];
    / k! P0 F6 `8 p3 }+ {( M            while (begin2 <= end2)
    5 ~5 Y" e8 ^3 y/ T# [                tmp[j++] = arr[begin2++];
    , m, J" N2 d: _* L( I4 m) f
    ( M: f) V3 f6 h" d            //拷贝回原数组——归并哪部分就拷贝哪部分回去! w( H* J8 I' c$ ?7 p4 g
                memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
    6 d: y6 V( L  V, O1 N        }9 B% d, V3 N# u. w9 ~9 X+ B9 }
            gap *= 2;
    # X% {+ U* K5 P/ Q    }
    3 v! ~/ L. B- c- V& F3 r% s8 n
    9 d+ g$ M0 V8 `& w, g9 z9 S}  n4 s, a/ h" e

    " ~2 x* w4 b, m. [$ e1; y6 \, |5 ?! h: E1 ]
    24 S( W$ @' R! @
    3
    ; ~4 ^4 P8 g& J' S! ?* x# L4- O2 k0 M( r! o
    5
    " z7 N# t, B- x7 r1 g# y6
    + u$ o. u, a6 k0 @7
    , F" ~4 W5 x- N8 s! b0 l8/ w' i1 I. O+ l9 Z% n# m, C
    9
    - m7 l) A9 z' g4 ?4 b! y0 V10, F& u% I3 P3 `
    117 @5 W  Q4 y7 F/ i
    122 s- v( x0 M' W4 K$ Z; w- U
    13+ ]  q* e9 U+ U/ y- x8 V8 R
    14" P. H  w- r; A6 u& k1 {  u1 \: K
    15
    ! n! ]+ J$ l1 Y6 |  F16) `2 \& D. U/ j$ Q/ y8 r! x; N
    17& c' G' _/ ?; }5 v; k  W! T
    18
    ! x/ {1 S' i8 O9 k/ @19
    . c9 ^2 p7 U1 |" U20( q( R) q# G5 e" H
    21+ E0 A) {1 k6 S9 ]9 a( i- V
    22
    4 t& Q3 @0 ?7 m& c) |23) x( ~8 Z! V  q1 x7 x+ `$ F
    24% [* C  o5 t- @  A4 [0 Y6 o
    25( L2 X+ ~. w( G  p$ M, q
    26
    ) u  Q$ ?  Y8 I277 ^, ]5 i4 ]; J2 N; v3 t6 m
    28& x+ t/ s4 @5 ~% [9 h. Q* v; \9 p' {
    296 N# m% N% y5 f' m: q# A8 ]
    30; d) o2 t- K. [- h! Z  ]4 Q
    31
    , L" D/ [$ r" b/ Z32; q; Q8 x+ F4 [1 _  m
    33
    $ E% A+ c  o# T34
      [) ~. G) S; O6 ]5 X4 e35
    1 n& {3 P! |: Y7 Z+ b+ _7 U& f% B36
    ) r( b/ o) g  Y* U/ }378 |/ P# }* p8 m8 R4 d1 Y
    38( {: [4 ?, L  R+ f8 C
    39( Z5 B2 @4 E+ u0 d; @% W
    403 }/ N$ v4 u1 N# a
    41- q1 h0 S! j2 A) }) M8 D
    42
    , d7 b3 g' K8 ?; a3 |43
    + v' l6 X" z1 }( [4 V44
    0 T! N# H  C) f( v! q45/ L- l0 M, }: ]( \" |
    归并排序的特性总结:
    1 Q% N& X9 w& f0 i+ |. k
    ' w3 _7 x" f9 p9 j7 m归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
    , e5 z5 z- P& R% l时间复杂度:O(N*logN)
    3 v$ {6 k& k  X$ g3 W0 |( N% R6 e空间复杂度:O(N)5 Z1 x5 M+ ^. U3 ~8 b
    稳定性:稳定7 W% p* c. U4 N* J

    0 p3 D8 h* T) E1 }. N, y# T————————————————
    ' g% @. F  X' q( r4 e4 B6 U' d版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    % w3 Y, s6 C* O3 ?原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
    $ j1 G+ v1 R1 @) R' s( Z  E8 {# Z6 a7 |) H' J

    * E  ~* M+ U# @
    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-11-8 08:23 , Processed in 0.501944 second(s), 50 queries .

    回顶部