QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 3311|回复: 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的排序算法】归并排序
    # |1 d/ E( w9 M! J, {8 Q) R4 D2 p1 h1 J/ \
    前言
    9 V$ V4 @) S1 @本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。# L/ X: ]: D7 E, b: y5 G2 e

    * g3 m/ m0 W9 b9 H: Y; ]! @归并排序
    , r* q/ }( u# F7 [+ ]( I$ z, e基本思想3 P) r. y4 Y: @. L7 S* y
    ​ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。) q/ `6 Y# g5 t5 m

    9 v% N4 K/ A* ]9 G; ^; j6 l/ u! S# m8 i% F- a& |* V
    1 o' s4 J8 N1 D  `& Q
    ​ 合并的思想其实和有道题目的思想如出一辙:3 L' a4 a5 ^5 i/ K: S3 `) T/ P! S4 B

    ( Z( P: t2 t3 E" u, Y% {1 K' g+ A. c4 G6 A' ~5 _, \
    ( I4 ~1 P: f6 n; H3 @; Z
    ​ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。  D9 h; t" s' l/ P, D
    # K4 N* n1 N8 Q. z  z! M5 q
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]7 B8 m+ P2 i9 e
    4 i/ O, g6 F* \/ `3 F  }! y
    int* merge(int* nums1, int m, int* nums2, int n)
    & m2 b( x' M: |- H8 g" i$ ^4 d2 V0 J{
    ( M% j( }5 {6 f        int* arr = (int*)malloc((m + n));
    2 E) E7 _( P* g: |/ E    if(arr == NULL)$ y5 k) B- f: [' w* e: c: V
        {) O' A; P( T6 j5 y2 `" o1 F/ v
            perror("malloc fail");: ~* _- ^6 W) d& O
            return;7 f' y: o6 A0 a- a
        }
    / [% L9 R. i2 K% Y- i, S( C) h5 A! h( h& s
        int p1 = 0;
    & o, p, {! `( V1 A9 g3 G3 _, U    int p2 = 0;
    ( M9 I, I% ~4 _) x    int cnt = 0;6 G$ J' m  |, D% o' _
        while(p1 < m && p2 < n)/ o- c. f1 C( [: J& H3 Z( y
        {
    4 p) w- e- X: {2 }/ t: ~) c4 g        if(nums1[p1] < nums2[p2])
    1 Y- e9 d, }. m- }7 ^2 x) z' y        {
    0 N1 v6 \# v0 f+ r3 R# }            arr[cnt++] = nums1[p1++];2 d8 X+ V$ k! E' d9 b4 R
            }
    4 [: G8 j; P0 w1 U" F! x. ]% Z        else
    : M1 \2 A2 ?& ?7 B8 E6 _7 b        {
    * e' Q: G3 c% d' M0 v6 N            arr[cnt++] = nums2[p2++];
    ( e, @1 G' ?7 A6 u4 k# @5 E6 K        }5 e0 l5 y4 ^; I, c8 b& U
        }
    1 l4 n2 |1 c+ x. X" U7 c    while(p1 < m); Z$ h" E1 ?+ I" y
            arr[cnt++] = nums1[p1++];1 Q7 l( G. W6 \+ Y- b

    $ P" u- Y' P2 g    while(p2 < n)
    7 X, ]! K+ u5 @        arr[cnt++] = nums2[p2++];% b% w/ Z- D' c
    1 v4 d& }' U/ j( p4 M6 w# i6 |
        return arr;
    9 h) J0 a$ I0 Y1 ]/ L* H4 X/ a+ g0 a}
    / z. E) u0 J+ g% ^) G) I: F9 K& w5 G! E+ D9 D# u6 u
    1
    * q  o  n% E8 D2 M; I/ T, n2
    4 N- b6 [% _/ s5 k9 K/ p( t! q3
    ' \2 I1 e, Z" ]) D4 W: \4
    + M. Q/ F. o8 o5
      d! N4 U( p( ^8 {7 x* c9 l6
    ! z, L. T& ]8 B1 w5 d7  e7 O; R2 J- g  R! G+ b
    8+ f  ?, c5 E% v9 G8 B8 y
    93 m8 C* `/ l+ b: Z
    10
    & v+ \; U' L) y3 u  }- c2 {+ K11
    , C6 Y  O# F6 [( c3 F! e0 H& d12+ K* {. T9 B9 H" Y3 Y
    13
    % ?% @1 C; M* ?5 h( f14
    5 P) p+ C: @+ u' K: Y3 w+ X15
    $ S0 y" j+ m4 V7 y/ S16
    7 k: d; {' c+ [) R! W6 G17
    ! l% y0 U$ V' u" P1 g3 {1 p% P7 h18* t2 B8 K# m# o3 E
    19
    & R6 D3 T2 I" O* U8 r& G" h* m20
    2 _; A* n, S8 p21
    . P( x& {/ @# H- x, X# S22, W; e- h$ |. U5 E, N  b
    23
    2 K/ j% R! Q' i* |, w24/ h! ~) O5 s- b1 A: H" u
    25
    * V( }- g8 u) c! P& p  t) V264 W+ A2 w8 J4 Q5 h+ q
    27
    1 Q* ~% {# u, [/ h0 a- q28. N, T3 K: {& k. P- E
    29* V$ A7 E! l3 E7 l9 F( I: [
    30( K" f% R: P- ^* j' F
    312 j' k# J0 d" `# U- S
    ​ 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
    3 D% G" o4 p8 d: b, p: Z6 T0 ?! O* Z$ k- i) A+ d
    递归实现
    5 t; v0 \! O5 U% J9 O  O​ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
    0 q9 U3 e9 Z5 ^: A& W8 @4 Q( V; w( n8 V  q( I& b  b0 L5 g
    1 i0 o' ~9 d/ H$ @/ z- y1 \, v8 v! C

    ' N) G* m; h( w) j" s1 Q
    . O% t/ p+ E6 F" C) x- N; U0 L5 w4 Y/ x# g# _) p2 n
    void _MergeSort(int* arr, int* tmp, int left, int right)
      h- X9 F( H6 c2 \( g1 W: i{
    " p- \/ B2 Q& }- u3 F    assert(arr);
    6 U4 n7 _7 F) F& c
    # a$ w0 N0 _; f7 e- [. W  l* h9 b    if (left >= right)//递归结束条件不要漏了( S. l$ f- o. Q2 Y
            return;6 U1 [3 j( w: N5 @% l6 M5 b$ Q

    : t4 s  D( R. k. p# g5 T. b% U. f    int mid = (right - left) / 2 + left;" _, ?4 c* s  N; G+ E9 v3 w' X4 y( o
    5 i$ ~/ {. T, m+ K1 x0 G
        //划分左右子区间[left, mid]和[mid + 1, right]
    + m: Y  J. s# [( E: E) B4 }$ B    _MergeSort(arr, tmp, left, mid);% ^: C3 s/ X0 y1 n( j, s+ _
        _MergeSort(arr, tmp, mid + 1, right);
    ( M. P5 |7 v' |6 C4 z2 P1 o* r) X1 S4 C3 ^; S
        //归并7 V6 F7 D3 X8 D/ ]& y$ C; T
        int begin1 = left, end1 = mid;
    4 a4 Z5 v. K# a; X3 {    int begin2 = mid + 1, end2 = right;8 W2 t! f6 D8 K$ b
        int i = left;( G9 h& L* b) T/ T) r8 _
        while (begin1 <= end1 && begin2 <= end2)
    % D! k. _& r6 t4 c/ ?/ U% @6 K" T    {
    " d6 e- q5 ]+ [3 _: X  y, c        if (arr[begin1] < arr[begin2])3 h2 y3 d1 F7 u% h* p' Y2 [
                tmp[i++] = arr[begin1++];
    # w6 ?& l/ S3 S9 C, u        else
    + U+ e$ T0 W6 T8 ]3 i! A            tmp[i++] = arr[begin2++];
    " X  h, O: T! d: C' b; s3 e4 ]    }- ]# P! z) _) D  ]/ C

    ' L: I3 X3 V! y4 l    while (begin1 <= end1), J2 _  L" c9 d* i4 x2 a
            tmp[i++] = arr[begin1++];
    ! p+ p3 m+ D$ Q/ }4 {" e  c    while (begin2 <= end2)
    6 a& u. U1 p) }8 o! s. @        tmp[i++] = arr[begin2++];
    ( E1 |9 ]3 }- Z2 @$ S        . I- u2 W! W, P6 F9 L
        //拷贝回原数组——归并哪部分就拷贝哪部分回去
    ! m2 b* V( o; a/ s$ Q% o    //而不是拷贝整个数组回去  |/ _8 u+ {! r' u4 _! i
        memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
    & b' u- J! I8 G9 X5 u7 A9 ]+ ~}" V+ K- n5 P2 Q7 C% s
    + v/ Q$ h+ ^* X; G2 y  S, }
    void MergeSort(int* arr, int left, int right)
    8 `3 t% E' X! M  c{- C1 U5 S4 R* \4 k
        assert(arr);
    2 M6 P6 W, h) n; o0 y$ G' d" a
    * G. L4 E; v: `2 E% x* e    int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
    # x+ l/ q! L, ~, B: j% B2 k5 M    if (tmp == NULL)6 ^- b% s- X' v2 M5 a. ]
        {
    1 }. i& i4 k  G$ Z% K" ]        perror("malloc fail");1 M8 u$ R6 w, [5 Y- ?  j
            return;
    ' v. p" E$ [7 e    }/ r" W& I' X% l# j$ Z" ^) P& A7 a

    ; @$ f4 C- R- d" L9 [* L    _MergeSort(arr, tmp, left, right);: [/ j0 S2 Q! ~2 K, C

    . y( c4 x$ X( ~3 A! d1 B( u8 M    free(tmp);4 x! z  Q- D, I9 L1 N
        tmp = NULL;
    + h$ v! L  M! G% f}
    & ~; M1 v& t( s& o
    5 K+ {- t' e; p1 U0 {$ Z1- a. T# O; H% z
    2
    6 I- ?) P! y* h# c8 U7 c  E* R3
    - a6 q* q: o2 ^. @4$ p$ ]2 z9 `+ c
    5# X+ y) ^8 |- W8 |+ B2 n- E
    6
    6 U  g% ]1 X- L! N) Q; N7
    / r1 V* q/ e, e" p" B! p8
    * i- _# N; ~0 Y  i# T; ^$ A9& H0 x$ Q7 A+ N" b
    10
    2 G5 ^: G- {, i11) W# r# X% V0 G, g) S; y, C7 Q
    12
    5 C  h& K( s3 e. P7 H9 f6 O/ H% r13
    7 s4 ]4 S  d7 ?1 _14
    3 a  B% ~2 c1 J! u" X" }15  v. y: P) V3 T. q
    16
    " v! G' u" x! y6 h; m1 W3 R17
      W) P- A4 P  M7 }1 c) u187 [* Y3 i$ s& Z' Y4 ]# b7 b2 ]
    19, d# f5 ]4 t+ E( V
    20' p8 f, n0 e* N7 _
    21
    ; y1 b  A" j: X0 C, R* H, ?# U22
    5 X$ N; N( F. k/ C6 j+ V* @( X4 K6 B23
    3 \" _1 p- Q; I9 W24  A! a  D3 S( [  R% `- Z/ _
    25
    0 j$ r4 i+ h4 _26
    , X, u% e! ]3 }# t1 K5 v27& s$ q, C( X8 U8 E4 T9 R
    28/ @4 f, w. h$ N7 r  ~& x
    299 ~6 l0 F( V  E! \" q- o$ L
    30
    0 A2 a  q* `5 k: n31
    0 r+ p1 E1 H% S' H$ j32
    $ d" W1 p! T$ K/ V9 f- u% |33/ C" Y' G" c% P1 ]4 z6 p0 R' N: U
    34
    # k7 H( J  N3 ?6 g/ L7 {35
    . b* K! N! Q$ a+ k36
    + D: R. w0 i/ v4 T37
    # m3 E% x4 ]4 S: w38- E) t3 M) s# A
    392 p% d- X* K& B$ g; H6 w
    40
    1 w1 ]: N; c7 u! s41/ g9 q7 w/ i& ~" Q2 G7 c
    42% T/ |/ c% l0 G! M9 E! }
    43. b' h( }% l# l6 I& m8 \. y
    44# T" @2 A1 Z7 f2 T6 V- @
    45
    5 e7 }% [1 J9 h2 p4 R; j46; D  _5 C, k2 E3 J2 a
    47
    2 u% \3 B5 m2 x9 T48
    - s& v( G3 |( W3 E( }& t7 z49) r% O$ I; D- P5 J
    506 [2 B6 w" ~! M% T: O8 Z
    518 n1 g, h; k* o9 F6 V% i
    非递归实现
    4 e, Z2 Y9 |0 s4 q​ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。" |! k- U8 E- N! _9 n) @" m3 q

    * P7 u6 r+ e# E
    9 z+ h, L4 K- M& @$ T5 d% E6 P3 I3 c; A, A/ V' x+ b" f
    ​ 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
    ( X) f6 F3 Q/ H( n' A, ?. G
    " f; N: ^& w# _! |. u+ m7 D' g​ 还要注意区间的取值,每个区间就是一组,就有gap个元素。9 F& e6 r# ^" V6 z
    . i* M& P, H7 v& Z
    ​ 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。* [5 {: t: D- p9 v1 I2 C5 ]
    , ]% N% s( o. f5 t1 m" r# {8 r6 F
    代码实现
    " s5 R' e, g0 k! P) |* X5 |: m2 a/ _* ]& Q
    void MergeSortNonR(int* arr, int sz)! K* s; l  q$ Y& a: K6 w  F  s
    {$ p7 K5 o( s' Y; k) Z5 K2 ^
        assert(arr);
    - G7 B2 D" W; x& |  u. O/ Y6 ^, R/ z0 o" r. _
        int* tmp = (int*)malloc(sz * sizeof(int));
    & I' N* S$ C$ m    if (tmp == NULL)
    ( C+ _% W# Z$ x    {" H' p: p7 T# h7 s# `! Q) b
            perror("malloc fail");# l, {: V: l' z- q
            return;
    , s  }& R7 {5 s! O, A4 K    }5 ?" n% B2 e5 a; ]0 r% Z

    % T- ~  U6 K0 |; @    int gap = 1;
    0 T" v( `- k. j+ L$ X: J9 R$ ?  P    while (gap < sz)2 ]1 b: r) e! {( N/ f& d- d& a
        {
    , ]$ M! R& x" D" {+ [# S/ @        for (int i = 0; i < sz; i += 2 * gap)
    : T* {5 c. b& a1 ]- G4 v        {9 s! v# N+ Y! L! p  q/ ], u
                int begin1 = i, end1 = begin1 + gap - 1;3 `. }* Y3 P4 P
                int begin2 = end1 + 1, end2 = begin2 + gap - 1;8 S* G& }" t. C0 b/ m
                int j = begin1;
    ; Y5 W9 b5 G4 S) b+ ]# E9 S" d3 b  R" T* m% }# o% Z
                //归并
    7 E6 c6 B" h0 A            while (begin1 <= end1 && begin2 <= end2)
    8 V) z: x  h) \9 A% ]$ L4 W/ H            {3 F% Z" p0 Q$ k& }1 u) h) P; a
                    if (arr[begin1] < arr[begin2])
    $ U# J" s4 [4 D, t3 x  m7 c                    tmp[j++] = arr[begin1++];
    0 g9 F1 Q' `9 a( T' Y( o$ U                else     
    / j& l/ F4 M( R+ x/ z6 f                    tmp[j++] = arr[begin2++];2 d( z. W! _2 b5 p. j
                }6 c, T" J: S/ H/ a- W
    4 j$ v+ Z: e$ P+ x% _
                while (begin1 <= end1)6 P. h# f" a2 ?
                    tmp[j++] = arr[begin1++];% h/ q' ?' ^# `! n( O7 s
                while (begin2 <= end2)6 f( ^7 C2 h& E2 j
                    tmp[j++] = arr[begin2++];  i8 R& G: ?+ \! W; y) w

    3 d( `/ d& a; F9 c* Z7 a" ]8 Q8 B            //拷贝回原数组——归并哪部分就拷贝哪部分回去4 q# F. C6 m. G) V0 w
                memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));+ j( `, J* V  ^' P
            }, ?# {' J+ K$ Y! A7 k/ M3 m
            gap *= 2;6 @: F+ N; J/ {0 ~" `
        }" j" ]' m8 ?  G4 q1 r4 `
    7 A+ }  M  M9 _
    }
    ; D, Y! X' J9 K- G
    4 k. N! ?# \8 e: ^1 j1' {. C+ Z' s7 r: r
    2
    . g: S5 S5 K$ B* O2 L6 @3 |3
    * M! e0 c4 S' K) ]4, {% V6 k+ U( q0 \5 [5 Y
    5+ l4 K/ Q% G1 k
    69 n0 T( D+ C' J/ K( }6 H
    74 Z( O7 u  g% H# i  o$ M; q
    8+ i- T' k. }0 m& Q  S; ~$ m
    97 S& |% R/ x. c- t. v9 n+ D9 T
    10. {6 J+ ]7 N) B
    11) p' o. q1 G% e
    12
    # O# R* ~% E4 z+ g6 o& N  N13
    ( D2 F& L* J% u- |4 h0 J+ e14
    9 a+ ~; K, |- W4 `' r8 _7 v. Y15
    + H3 c' N: q. j2 o; |5 M) H16; K5 E$ Y- E" \& F7 H
    17
    % f6 P. `) n1 L+ i, v, {' t3 m18% r) Q* s. O0 N* J/ I5 E3 O
    19( x  W  a. z. x. G0 ~1 r
    20
    ) k1 N5 E8 l8 m0 A0 X. z! U21
    0 R8 b0 x4 M  k8 {22
    7 S( K7 g  s& M6 Q/ J23* {+ p! @$ a+ I( G
    24
    . E8 [2 Z" X; Q25
    . j. O: m+ y) w' s26. |3 ]$ F" H( a# \) y& x$ B) _6 ~
    27
    5 j5 d2 p5 ~; d0 @/ G9 a  B7 Q28% S; Q% W+ x) C
    29- Q6 e. q+ k' }% U8 |
    30
    1 u2 l" Y; @+ E, N318 H. ~: A* n& x$ L
    32
    , O8 h# G) _# L/ n! S33/ g4 v, }. \9 `4 n9 D9 P& R' H" r+ W
    34
    ! C4 }# J5 B5 \, \( G35# W4 L  ]7 S$ C, \1 }+ t: O
    36
    6 c6 K* z: a% H+ l373 k1 A1 a+ {3 t6 B
    384 y  |1 n8 P' E3 i
    39
    + U! M2 l' b( E7 `( r40
    3 c- z8 R3 v) N# [41
    # U& p9 X2 n$ a; h. R% E边界问题6 b9 k/ e4 F0 ^
    ​ 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
    : J: y, P. l% x6 f2 d) D/ ?# U
    , R% C/ b: k2 v" Y+ b1 `- n& A举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
    4 Q" C$ _9 f7 u0 q) T4 ^  D8 T
    : o; v" ]( y; g- a
    6 ^2 `3 J% n& Y8 T3 e8 ~: m0 o; F' L$ Z# B: M
    由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
    9 K4 Z) F6 F4 L7 C; Y) O
    ! q& R" W+ r; m9 G9 K0 q第一组越界(即end1越界)9 G9 f. B& M4 n  \, B

    $ y. p4 ^  k) Y( _" f4 ~) j% Y应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。( ^9 q5 g9 s, O7 [
    6 M9 F9 _& r7 o/ f! {8 G
    第二组全部越界(即begin2和end2越界)& V7 D  {8 S* ]9 ]( r5 N' Q

    ( L" g6 d2 t% S, @' G7 ?应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。- H7 \! ]- @9 J, F
    % m1 F) Z+ y  E5 H
    第二组部分越界(即end2越界)
    % R" g' ]6 S% G
    : c/ ^  e' H; }" r3 D/ l; f6 z+ A! d应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
    4 c3 B- n, e4 x5 t1 o  E& u; Z- }" T* ^8 p4 z
    ​ 其实第一种情况和第二种情况可以合并为一种情况,原因:* {: Z( _' X6 g% A8 J. \( p1 |
      a/ }! o) r" z* j0 v
    ​ end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
    . S' R  b1 W. ^8 u! E
    ! y8 K  G2 N$ ?0 f6 F9 i​ 拿两个数组试一下:
    2 n% |# E3 y' e4 u3 [2 W+ o/ E( Q2 k6 H& L) y1 j: W8 ?- r" F8 M  E+ d) ~

    " {+ N. F- ]' z' h- d# r) s8 {8 V* [8 Z# h* K: z+ X4 s+ R
    , S! c% j2 P: r6 q

    2 }! d7 Y) _$ C. B代码实现- r) t3 ~" L4 b$ w

    : Y$ D, `. H9 X! F1 ?void MergeSortNonR(int* arr, int sz)
    ' n7 n! Q* c& E1 R5 E{
    * W3 S0 P$ n$ H" t+ p/ t7 w+ {/ d8 D    assert(arr);
    3 ^" Y6 I% i- s% z
    $ C- c0 P* x. H) r$ @, L8 T    int* tmp = (int*)malloc(sz * sizeof(int));
    / X4 K, h* H- g' d5 I    if (tmp == NULL). G/ n- Z+ J0 t4 B
        {. g+ c+ k+ c' ^- R2 P% q
            perror("malloc fail");8 ]8 G9 i% r% A; ]& H
            return;
    * l. n3 Y3 I3 \2 ^# I. k    }
    1 }. G5 Z$ l, s' n, @' ~' V& y' N0 \8 K0 j+ c9 }; |
        int gap = 1;
    $ J$ j3 o6 I5 q1 U6 q. e! m/ O    while (gap < sz)
    2 J6 }8 R( l* n1 `+ }. C    {
    $ r9 ^2 M; f7 C; L; R+ e. v        for (int i = 0; i < sz; i += 2 * gap)
    0 F9 C6 s. k/ n" G; V        {
    ' Q" P3 i+ k# k# j- K% p            int begin1 = i, end1 = begin1 + gap - 1;
    1 H4 r( l# n) P; m            int begin2 = end1 + 1, end2 = begin2 + gap - 1;
    : e9 s& O2 h- L) R$ |            int j = begin1;
    ' V* i$ `5 |9 A8 b+ f  N) `& ^                        //越界检测6 t3 q: k6 I. ~+ q; t
                if (begin2 >= sz && end2 >= sz)
    ( c, r/ E( h7 J% ]. U                break;
    - F. d- Z; G- j! A# r. E            if (end2 >= sz)
      z: [1 `  K$ y7 c" b                end2 = sz - 1;
    2 u$ _- u1 @* N2 J            //归并
    , l1 E& R& o3 R. G1 V4 H0 Z            while (begin1 <= end1 && begin2 <= end2)
    / m/ r; h' m" r! B- n            {
    ( r2 i( H* X) J6 C  y                if (arr[begin1] < arr[begin2])
    % F) ]9 q. W$ ^, c. F0 G, K                    tmp[j++] = arr[begin1++];
    4 D& A  e9 k; A                else     
    . G0 p0 S+ O% k7 G2 @                    tmp[j++] = arr[begin2++];- C2 O- d6 g/ Z3 x& Z+ H
                }
      Y, R: u; ?/ P3 q" K
    - y8 N- O9 v7 O            while (begin1 <= end1)9 P% C( g: s0 z5 L8 l8 p) w
                    tmp[j++] = arr[begin1++];
    & ^5 |( s+ \7 z5 q4 Y  F% `            while (begin2 <= end2). B2 o! r, M4 e2 |& z( l. _1 Z
                    tmp[j++] = arr[begin2++];
    ! y9 s/ T8 N3 \. A5 Z& i' r, y" q2 k
                //拷贝回原数组——归并哪部分就拷贝哪部分回去2 K. s# G8 D4 z7 E3 X* d2 Y+ O" o2 o
                memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));1 A' Y; M8 w! w- ~3 T* w9 v
            }
    5 f/ i% I' y# }, E3 U        gap *= 2;5 H8 c. x0 Y( H, ^' v$ l
        }
    " _) b3 \% _  L4 t+ u! l# Z1 G7 ]0 W: t; n) T- X# T
    }
    ' ~9 @6 G0 H" D) f% U
    3 G: j! B  j! V  ~' F- \1 t1
    & }- j8 G( t+ u( ^/ H: p7 a6 I+ \2
    8 l: n5 O' C1 b! s" Y. a4 `33 T6 p* W7 f9 |
    43 T; a% k2 I, O) O; J5 |, z
    5" n3 p  ]4 t' U, K9 ~
    6
    2 E7 }: H! d0 ?1 ~! G$ ^7
    / n% l0 r* i9 j: `& c7 Y3 o8  j2 [6 l1 L9 \. ^, k9 i
    9
    : C) S, ?" P+ z101 @& o7 |+ \5 {8 ^* T- a, T* o
    11; p1 w7 u' O7 p3 O' |+ z* k9 _
    12& N( j: y+ X, R
    13: {2 Y& r  e* e" k. T
    14
    $ o# f8 b! F, K15
    ' J/ [, p" Y& }( b' q8 L16
      g# F7 _% A# F) b/ p# `17
    2 i) n4 I8 x! s18+ d* t, q! I9 p2 g) e
    19+ Q2 Y' o/ {4 ^- L  Z* }: h
    20& N6 Q: S3 a4 m4 z9 A. `
    21& ^1 v& n5 X" x! }" c0 s1 S& ^2 w( j
    22
    & k4 g  `- A, x, q23
    + A3 @; u- M& }7 |; ]6 ]0 P' r- f24
    * S, M& O* z- R- Y25
    ! Q6 E/ g# x8 Y) e+ Y: K26/ O! e% d7 a) b) x8 h% D( ~
    27
    4 n3 y$ Q" k, i+ g3 Z28
    : m4 ]2 n9 K) Y29
    0 K$ C' ~9 z7 B* M/ Z# _$ V30
    2 J% d5 f6 h, J: E7 r3 i$ N1 T31
      ^- S3 Q  e/ D32
    / X, T/ N/ M* R& E2 @( c  h33' V7 [. [/ {' y7 b: ]
    34
    2 `8 T& J: p) N: P1 S35! C1 w2 }# \3 z# H4 V2 ?* E2 J
    369 x5 s# f, F, C9 x! n
    37
    3 q. T$ O9 l6 z& [% r$ V, b38$ I% M! i; N$ w: `
    39
    ! L9 R& o: @* j. {40
    6 [4 j- h9 k% P- S* X9 A, X41
    4 O5 J2 r7 q; Y; \42) f. \8 a4 V% m8 u9 N1 E, h
    43; ]* R) a$ d8 [& h! K
    44+ ]7 l, W8 i5 q/ v
    45
    7 `/ F! Z, q1 P& K7 ]) ~4 c! q6 |" e归并排序的特性总结:
    ) d" ?1 T* S0 h; r; L# Y0 Z+ r* Y# i- r$ S! t- h
    归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。' B* s) o6 _! b2 F+ d7 Q5 F! U: l
    时间复杂度:O(N*logN)
    ! d8 S0 K( [+ j( h空间复杂度:O(N)
    * u0 n* K5 A/ A  w- F, `! h8 f稳定性:稳定
    2 a( ]7 s$ Z/ v( n
    5 P4 z! z5 x# j( K. ~————————————————! l; \$ P) [3 }: I$ s! T$ j
    版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    $ ?. o# L; p% O. _7 z原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657+ Z( r) ~8 L0 A4 |: e, |
    7 s, m0 E+ h0 E6 \" m( D0 V5 |( Q

    : U& u6 h$ w8 G' g! {, J
    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-6-15 11:22 , Processed in 0.465627 second(s), 51 queries .

    回顶部