数学建模社区-数学中国

标题: 【基于C的排序算法】归并排序 [打印本页]

作者: 杨利霞    时间: 2022-9-14 16:22
标题: 【基于C的排序算法】归并排序
【基于C的排序算法】归并排序" ]  Q: K) \2 ~. x5 \8 |, q
- j8 S5 Q& \- M& O" ?
前言) s) a- Y" Y( _) g8 y7 Z" I) n
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
5 \$ e& T8 Y) ?6 y
/ K0 o+ _2 N' q) n: k8 G6 e/ x. z归并排序/ Y2 q" \  h' y; C* t. B
基本思想
2 Y1 W% k& ?7 F6 c! K9 S! \+ L​ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。+ A- w4 [/ B8 n3 [# _

7 T. ^! f1 m) f1 }* i1 n3 K: o4 Z# @8 x% a
; J" l6 A1 T' V9 ~4 O
​ 合并的思想其实和有道题目的思想如出一辙:
+ v! }6 w. y! [; y8 n0 Q  J: o. x4 i1 o  T  D, f8 @0 @! P
* E$ U6 W1 ^. b1 l1 E) ]
. Y2 Z; C$ T$ l5 w0 O" ?
​ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
: h) C- R& W2 a" c# P# A" T
- j5 e$ ]. b: Q  P6 f, W1 |[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
$ `- I2 ^+ m: J7 y) S7 m9 W8 G% `9 j) ?
int* merge(int* nums1, int m, int* nums2, int n)
8 J/ s* L& E( U9 ?1 _, P{3 E7 r% m8 t& }* A
        int* arr = (int*)malloc((m + n));1 k! i4 L/ q" _! g: ]
    if(arr == NULL)
6 u% l, H7 U" w) }8 J    {7 D1 S' P& X# n7 Z, o
        perror("malloc fail");
5 t1 |  _9 }; `4 l" i# z9 O        return;
& X4 l! r( }2 K# ~# ]    }
8 V  G5 a  U8 c5 Z
0 Q- g7 S9 X& N9 A    int p1 = 0;
, }1 t% g( N5 q( D3 n7 n0 C* u    int p2 = 0;  t1 B3 @- {( z8 o: S2 D/ s! F
    int cnt = 0;0 u# T3 z( h0 L. L( z" Z0 G
    while(p1 < m && p2 < n)
* F! e( w- y9 M; N    {( V1 u  G7 h* B; [5 i
        if(nums1[p1] < nums2[p2]): Z- ~/ }0 G9 n! I
        {
8 _+ ~  h9 P8 u- K; ?4 C+ G8 R            arr[cnt++] = nums1[p1++];, c' O0 n6 Z. _
        }6 {' X: @& |6 o; f5 g
        else" w+ ~, E# A1 E! F# V( [
        {
! y% `) _- ?( R- }4 i3 \            arr[cnt++] = nums2[p2++];0 G" z2 v+ o, C8 V0 ~7 ]
        }
' z, I9 x5 |3 ^( ~    }8 s1 ~6 m8 I5 R+ j
    while(p1 < m)( x$ b  k, \6 q. Y7 n+ l
        arr[cnt++] = nums1[p1++];
% t) b: ^* p" Z* Y+ c$ l3 [" {; D  M
    while(p2 < n)! x+ L1 o/ ?3 L1 a% k7 R9 o5 X" ?
        arr[cnt++] = nums2[p2++];
7 q: j% T5 @+ e) U$ k+ q7 H2 m1 m5 z6 k/ W! C3 a
    return arr;5 S* X% e, z) a, S6 y
}
' t4 R; @4 O9 z- j' z  r. S( e# u( q+ u6 ^9 C1 R8 ?. T0 `$ ]# z
1
% Y8 K  f  e: s- c/ i+ |3 s2
# @3 ~* T. O. r+ A( f0 v. s3* ?/ T; Z7 N4 s' E% h8 X0 x6 b+ E& O
4
5 K1 a8 I5 U' ^4 Y; @5
: i# c: h( _: e6# h  {) @. J2 _5 b1 A- n
7, |6 W7 N" ^9 Z% T$ X: k6 }
8, J! H0 U: }; [" V" J4 Y7 A& [& w( d
90 e/ b  a# \+ W2 Q# \* K! n- b
10
: W' e# m' {4 h9 @" c/ f110 H9 n% X3 o/ z- L
12
$ Z' X1 r9 Z+ N3 P138 @' H! r9 R$ P7 N$ M
14( \( O) e3 ?9 P( ^4 O7 p2 \; V
151 _$ K6 l, F6 _3 e+ |* M5 ^
16
/ V0 s5 @+ s& @9 x17# i% R+ j, x' p4 E: [) t
18% X) _7 Q8 w% e* U: s
19) ?( W5 b5 }( ^/ f. v7 Z* ^8 y9 C% K
208 E8 G# J: w- r3 s
21
# x: ?! J) x% _22
! x% [7 B5 X8 c, S238 ~( w) h- L; ?/ j1 g
24
" q# E. }- m$ A* a3 j6 t+ k! G6 w25
8 e8 z1 @7 S- \2 E! |265 d( \* d9 {2 M" f, U
27) R# v- n- c  `2 m8 ~/ i6 q/ y
28
0 Z( o9 y  D" Z: F3 d29) l( U. E( U) d6 a6 u# s/ J
30
3 K6 d5 D2 H+ Q1 e7 p9 X& ~, o31
" @" W- Z. u& t9 l9 d. z4 K# W​ 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
% R9 }' L  @' s% x, T
4 L+ M" f( d/ x& ~! Z, [7 ]递归实现
$ V5 ?; |: H8 W​ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。/ C8 c) g  b6 s# K

/ k% j: y9 l% _( ~3 V$ U' h" H) s/ Z# |$ |' ?2 h# G
9 r3 e' M" ~2 E# B0 |

- ^) p+ Q9 @& G0 q' G: O8 j) v4 m( A1 ~6 W3 o* o6 _9 v4 D
void _MergeSort(int* arr, int* tmp, int left, int right)& c. E" C9 y: A* h
{
* z% b9 ^1 N6 m# ^    assert(arr);
2 h$ G* T0 h2 @  m. A0 W& _4 t  \3 G7 Z8 o$ @6 J7 ~5 _
    if (left >= right)//递归结束条件不要漏了4 E" A# {9 @2 W4 o2 f5 Z% _. F, k# H& A
        return;
% @( |# @4 P8 @0 `9 f% x1 u9 G7 I; F$ X# _& D
    int mid = (right - left) / 2 + left;' C' j# K* y: z0 M9 s

2 M$ o1 {$ L7 S* b) z5 I; w    //划分左右子区间[left, mid]和[mid + 1, right]
( g  S0 Z3 S8 ?    _MergeSort(arr, tmp, left, mid);
2 K  F: i( A4 S' U8 R3 z  }1 D+ B    _MergeSort(arr, tmp, mid + 1, right);9 }0 l2 B7 [' _* z5 Q" W+ m
0 O* z- c+ O) H3 I/ t6 y. S
    //归并
* Z4 J( j- k. X" m: ]$ y. R    int begin1 = left, end1 = mid;+ c( O( t. Y$ i$ y, y& K) @
    int begin2 = mid + 1, end2 = right;
; R2 a4 p' O7 Y  P    int i = left;
2 B! V, \9 m3 d* s    while (begin1 <= end1 && begin2 <= end2)
+ n. O& }/ }) ~1 o- D    {( P7 C8 k* b5 ~9 u( p1 D
        if (arr[begin1] < arr[begin2])2 h' V; B& @) j8 X1 v
            tmp[i++] = arr[begin1++];
$ W  U& Z9 y& g; Z- z5 a5 J9 ~        else
" f+ {5 I+ z5 ~+ Z7 D! q! c            tmp[i++] = arr[begin2++];6 |! b2 A. s, @" B
    }" o/ {/ V$ @! E% x# a/ W& K1 m6 C$ [( J

5 r* W6 I$ A$ L/ D4 T7 Z4 N% `( ?    while (begin1 <= end1)
! r9 e" M! Q4 i& [3 ]0 r        tmp[i++] = arr[begin1++];
% b6 b! y: x8 x* }2 N# u7 [    while (begin2 <= end2), i+ D7 q- K7 ~6 ~
        tmp[i++] = arr[begin2++];
7 T3 z% Y: l6 B& s# i; l       
( A. u8 l& U7 \1 s& k    //拷贝回原数组——归并哪部分就拷贝哪部分回去- ~1 Y8 g2 S3 D0 u. {, K
    //而不是拷贝整个数组回去  H! W* d6 B6 i  \+ G
    memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));9 q1 t7 f& D: i4 R  c# B) ?. @
}
. g3 }3 N2 A$ t: g* l- E
$ P+ S2 ]# _4 Rvoid MergeSort(int* arr, int left, int right). F, ]; W2 G% ]3 B4 L; I/ u, g
{
1 s( o5 s! h9 e5 @    assert(arr);. E1 x* P1 r/ l& o% J' c( s

  t0 r5 R' [3 ^    int* tmp = (int*)malloc((right - left + 1) * sizeof(int));. G4 H2 |! h" l8 D. E3 `
    if (tmp == NULL)
5 i) |; t) _8 i+ m" {    {
- J, y5 L1 b+ w8 e; n, M0 m        perror("malloc fail");9 W4 j  Y9 c! h- G% ?2 _
        return;
1 \9 O0 f  k; o5 g7 |6 W( Q    }
. Y/ \' Z3 Y$ C
& N  a4 d8 Y: c! O4 @# \; Y- H    _MergeSort(arr, tmp, left, right);: h0 v7 {! ]+ W6 J5 y
8 {. ?# |1 F2 `; }' J) d( j
    free(tmp);* l6 r# o7 Y( l9 D* R+ ~
    tmp = NULL;
0 s' t$ `3 I9 O3 m# A- {}
$ n- A, s! ]/ n% _+ S
6 @  Z. w" s6 X6 G; K6 }1
, X8 z# ~7 e" E6 I3 |29 G/ a: M0 R. Q/ {
39 I7 u. t: q  T6 G, D/ E/ l. F
4+ q2 \; J$ S8 J! g2 I
5- \/ n* M' n+ k
6  j9 k" A6 N! l8 t4 `1 q
7
! G) h* E# h, z( L! Z; b8" t' @8 n+ L6 S$ ~
9
7 u7 C/ X0 x' E; W- o10
' N2 U* {4 R7 x$ t5 y, h11
2 K: ]+ Q1 t: ^( P' r  h' X% k' i1 ~127 w+ b% h+ j0 U3 j
13- F  k& G( A2 P% _3 _
14
2 y! o- }) Q: M/ n% M! y9 w15
' Z9 _  V' P% r2 E) P16( k# G! [0 p, w7 Y5 R; `
17
. U! q  k2 ~4 B7 S5 h  O18( O1 Z5 @% H, G  v) ~
199 z* ]3 {$ H4 q" Q
208 [' T2 a) V$ W$ Y
21
* K, M; J* c8 |8 I# y22
* K7 K* t* i- g9 x5 V8 m23
( K/ H; g) ?$ A" b& g24% A# X0 H! P+ |  v' \4 h1 Y! Z
258 o7 Q3 Q* I2 T- l  c* v
26. ^8 m# w+ h8 J1 V, o
27
) d6 ]( C% x) b) ?/ g% A) ?288 r5 e( o; L3 s' v. m
29" q' U2 o9 I! C  K3 o  `+ `# j( f
305 y# s) c/ B0 M. N
31% |* Y& I- s' R2 x& {: ~
323 [5 k9 w! B9 t) N
33
1 b7 [) j9 B; G) V343 {4 ~% F5 K8 d: K' C% h3 x
35
9 Z3 l5 }  A3 t364 S$ [6 e8 e* x+ v8 `4 W; P- R. n! G" z
37
8 a' ]7 s- q4 y" }  d/ s38+ Q! d! T: M- Z6 u# k* S
39' U  ]! `, Q' A  j) m' X! V
401 O# U. F2 k4 W: J
41
$ u4 ]9 b0 ^( \9 h( S4 c42
/ |! T3 Y4 A% {  \/ i" ~3 [43, U) j. i" j; X
44
6 w( y3 ^8 e$ ^8 Q2 z45
5 s& v  H. J! Y; J( Y2 G4 ]+ O46! j1 ?, F4 l* I! v" F3 |) R3 ]
477 O; o; n* P/ c$ }) z; I  f
48
% L) S( `4 \- K8 l$ v* n49! [' y9 x: ?: N
50
2 f! M- _! p8 c" j! h1 i517 j! _9 E5 A: G) j. P+ y
非递归实现( i! a% [, G# H1 y) w! Z
​ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。4 n' v! {9 E' Z  @
. k! n' e6 |# z- P$ p4 Z( q# w) {

( K- s1 b" u8 e0 }
4 u9 `: ]0 u# ~( X​ 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
: K8 ?# q! g0 C/ @, p8 B! ]9 _* e2 ~9 m
​ 还要注意区间的取值,每个区间就是一组,就有gap个元素。
( U. d' `2 m6 v& k; I, S
7 s3 S" X# {3 j, E​ 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
% X) d& h0 X: I* u$ z0 [& m1 l- q* _+ s$ b
代码实现
0 e7 G7 `4 d- e; U8 X( L/ _
2 N9 _/ G) d0 ~; y) Ivoid MergeSortNonR(int* arr, int sz)( }6 h. z4 u7 e5 ^
{' O$ h& E) R; c, u. C* ^) R5 K
    assert(arr);
9 B  e* `1 Q! e
/ n  i3 N) b/ p    int* tmp = (int*)malloc(sz * sizeof(int));
! C' E& a( V  \3 J( d7 }: Z* |. o    if (tmp == NULL)2 ^' q; z, q% D( E# J- x. Y7 P6 H
    {
, e) @8 b  U! p3 }        perror("malloc fail");
0 u1 ~( f/ ]7 s4 Z        return;0 a% |9 ]. f' h& R
    }4 ^6 X  R# K; h( g4 n

( F1 n; p5 _" g  q    int gap = 1;
# t) U- L. c9 ^" Y& f% ?    while (gap < sz)
, }4 {. w: U! x3 ^  O( ]8 A    {* s; z( {3 |6 \$ z% Y5 {1 V, [
        for (int i = 0; i < sz; i += 2 * gap)
  E6 c7 |4 n& S/ q% O        {
  I& s+ }8 E8 u; k! F" T' n            int begin1 = i, end1 = begin1 + gap - 1;
: U& M9 n1 I% \! t; n            int begin2 = end1 + 1, end2 = begin2 + gap - 1;
# M% H: F2 g! [$ |) a            int j = begin1;# P0 v  h8 b* @3 G3 w3 e
$ A# z# E3 i4 e6 u' ]
            //归并
7 r% d4 n) L1 T0 q            while (begin1 <= end1 && begin2 <= end2)3 k( b' R# Q5 W0 I' `' f- @
            {
- \" ^8 G, U: s% C1 Y$ v$ j                if (arr[begin1] < arr[begin2])
7 a3 h! G8 y0 a: r" K2 o                    tmp[j++] = arr[begin1++];
/ c$ x5 Q0 T% \9 F8 I1 r                else     
3 u" M& ~* I+ i                    tmp[j++] = arr[begin2++];2 b: e7 j+ D( V4 J* o; h+ Y$ Z
            }
9 Y! d5 h6 a5 `5 G! }( I1 u7 n% ~: M
" v5 V! V# [+ w6 f& @% }. X' B            while (begin1 <= end1)2 @' j% s9 J% w( o
                tmp[j++] = arr[begin1++];' e+ }* v$ q9 u/ |
            while (begin2 <= end2)
# S$ k. v$ A! H8 v/ E/ T                tmp[j++] = arr[begin2++];
) j" s1 [$ x  A( ?) `. G- z7 t; e) C" J$ K8 m6 t4 C1 o7 D& J/ {- ]
            //拷贝回原数组——归并哪部分就拷贝哪部分回去
- D# l0 |' t6 W, A. L- W% A1 [            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));$ O3 p' F. _0 `1 [
        }
: u2 ^) @; [/ O( @" L        gap *= 2;
3 u1 Q5 s+ Z2 z  ^: o$ T, g* d    }, I! ]! T) h# E: Y  b/ F+ Q
3 E1 f$ {7 \0 a
}
, d2 Y- F4 K5 k+ J! B* E$ }3 `4 q* K6 H9 O8 u. M% d6 E
19 [: \8 J3 S2 H9 M9 F& `
29 X$ }/ Y7 n$ Q  a7 O  M
3+ F* t5 d7 c* I6 ?: q, @  o! X* X
4. Z8 s. I0 T* J+ u6 F2 f/ W/ S2 C1 ~
5% K0 s# N- F( ~1 B: l, m  M; q
6
8 t/ a& k( ?% H' p79 b" b% Q/ j% g/ A5 P
8" [" m/ ]& x" Y6 `- B' y/ d
90 x5 D. @) d4 N+ ^; K- l" z- {
10  r  [1 O% y0 i$ s3 ^' P2 s: X, e
11* m; h  g0 B5 J6 g+ ^2 ~  h7 t6 g4 K* I
12
1 {3 |! R, k( }8 A1 e  k& H$ z$ M& d13
% h! c& G5 R6 t4 c14: Z: ]( C% K' k. m
15
* ^1 g: x* Q% T( |, k8 Y7 X9 C16" L4 n5 f& G1 E3 K/ {4 k
17+ b/ P7 z# @3 T0 h0 N+ N
18+ p7 Y5 H$ p) r5 R
19
  [' V! X; m; G; F$ I. F204 j4 J9 M  g7 V5 {  v2 T
21& c$ b6 R2 z) b/ C- o4 c0 @
22
5 b/ S; ~0 C8 K) M3 F+ F23, s3 u# [$ _2 w6 ^
24
" A5 [9 z" H$ W- ?6 c! o/ S3 b25
& d  u- z3 s& A5 k/ ^+ \3 n3 v& q" w262 q; J. m0 T+ v, u
27, ~. g$ }+ g* \/ k) [
28( Z5 p" L1 k- C) P) Y3 F
29
# }) L! G$ v! w1 N$ c30
  B8 F) w2 ~: b- d: `" X31. c+ u; |( K; ?
324 ?5 L' c' n( L: ^5 o5 z
33- |! f& @/ o  o
34
% U  B" U" n# H1 `% K; u0 b' |0 }& d35" G5 r/ n3 d# P& k6 {) x4 d: o
36- B+ I; @  O- r/ C( Q8 u
370 m  Y, @% i4 M& C3 {- Z* Q5 ?
38
0 P/ H' p! q7 x3 p& T/ P# q399 X6 P0 ?1 B, s9 a, ]; X
40. j) f5 K# n9 Z3 i! ?( b: n3 t
41
3 J. @+ s0 Z) i& D边界问题( B6 Z1 F* ^2 u1 b  p/ K: d+ j
​ 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
# Z  _. B7 }( a5 k3 O0 H! r0 f3 ~# k+ @7 z! W" K
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:& l) h7 w0 j' O* H1 ^2 f
% y5 u6 Y' ^: B' N$ x
+ @8 A) R$ q3 l( d7 l7 B/ h( A' ^

& q  `) n/ P: }  y) _由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
; E2 k+ |5 ^. U# G7 p" H( q+ {: }/ s1 {) d! w+ D* j
第一组越界(即end1越界)2 ?+ b1 g) l9 o7 l+ {
1 f& h; c2 s3 _+ {( }2 v2 G& u
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
% Z$ x! f+ h$ O- A9 {
9 o6 v3 T7 N5 x7 |8 A( n) O第二组全部越界(即begin2和end2越界)
  g' F' D/ \$ ~& B1 F; \  k) f8 C; v. v4 g, q) i
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
7 y; t$ \5 h/ L4 L9 e3 e2 g$ _. f: [, Z( W1 a9 m
第二组部分越界(即end2越界)' m$ m: C; u/ r0 q
! h7 j  Z% l9 p" O! t
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。1 G2 I# x$ F! U5 |

) r/ N( z3 c9 v2 N- Y9 m7 m+ }​ 其实第一种情况和第二种情况可以合并为一种情况,原因:
0 j- K. x* d; B( d2 E- I2 u  _- [+ R, K
​ end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
9 w/ Z, _7 m' ]% q" S
' ?# C, u6 N: J  b, j. u" j% ^​ 拿两个数组试一下:
" U% Y1 ^3 c# H% P9 ]( [+ Y# l& u
2 \. n4 P+ e; L# H9 s9 u6 ?2 S/ N$ t* E4 \

/ J4 f! g( U5 M/ N4 H. I( i
# d& h1 n* K+ ]
' n+ m" @2 ~% j: q代码实现
3 G" N9 }% E3 b4 x5 ?
5 f+ G) c9 V. dvoid MergeSortNonR(int* arr, int sz)7 t) P$ t2 g% t. d1 T% H7 J
{( y: [8 k* O6 X5 H! L) K
    assert(arr);) _5 V+ K9 n0 T; J

* C% B8 W$ n1 u# J4 H* z3 u    int* tmp = (int*)malloc(sz * sizeof(int));
" Q) e8 R. C" ^' }. l    if (tmp == NULL)7 D4 m, r7 u0 @3 s
    {
, Y) s  I5 _2 i0 i, i; G        perror("malloc fail");
, @2 f+ O  [( q% a  ~8 v$ W        return;
7 [/ K) `: X( h: a! J" {; C' i    }- ~$ Q9 J* l( M0 |- b

3 o% `+ o# i9 Y, `, |; ]    int gap = 1;
9 l  }/ f& O$ n2 }    while (gap < sz)
, g. Z9 v8 [/ y( y    {2 {6 ]3 ^. ~: Q7 X- h
        for (int i = 0; i < sz; i += 2 * gap)  _9 f2 G2 t/ D# T
        {
# ?+ l$ ?0 O" q! }            int begin1 = i, end1 = begin1 + gap - 1;
8 h2 X* E( F9 u% K, p* |7 _            int begin2 = end1 + 1, end2 = begin2 + gap - 1;
6 w" M# J0 `) h$ ?4 `! w4 A$ D( F            int j = begin1;
: p+ j9 G5 n- ]- g# j; e( g                        //越界检测0 P4 |8 H  N6 Z
            if (begin2 >= sz && end2 >= sz)( Z, |% q( C" m( M( Q0 N+ ^+ T
                break;! D; |+ ~  ?. _
            if (end2 >= sz)$ M/ ~# f1 P, w
                end2 = sz - 1;) Z6 E/ I+ `' K
            //归并! _" S3 R! h2 h; U9 s9 A1 o) l$ t% ]
            while (begin1 <= end1 && begin2 <= end2)
& J; K8 K2 C; c) J; ^3 N8 O            {
- b  N2 a% ^) s, B% E, E. U                if (arr[begin1] < arr[begin2])
. h8 l: V! ~# n  i. Z                    tmp[j++] = arr[begin1++];
/ H0 z8 }# G- Q- L$ H+ t$ b4 L4 J7 F                else     5 r6 {5 J1 s# B# |- I
                    tmp[j++] = arr[begin2++];" P1 O9 Z6 _8 T8 x* ~
            }  c0 }9 k) `, G$ e3 H) Z- }, F

6 G- @! z0 @# l0 U: C            while (begin1 <= end1)
& Y3 {# L* N7 {                tmp[j++] = arr[begin1++];
) _3 y1 E6 |: `' y0 n" H8 L* H; o            while (begin2 <= end2)
  `' L+ X  J! m% l- q1 k0 ?+ R                tmp[j++] = arr[begin2++];  w5 f$ z. g" W# o9 s0 P, }
5 f$ R& |/ e; n4 Q# G/ j1 Y
            //拷贝回原数组——归并哪部分就拷贝哪部分回去
/ e# ^% S) P+ N2 d2 L- z* t            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));6 E9 g( s) o3 \+ X% T
        }$ u6 b$ B! Y+ d9 W
        gap *= 2;6 A7 t; g, y( X5 A
    }& B5 S& v' D/ w

: E3 }9 v( Z) ?" z9 A}1 h# X" |* t2 `6 S; v9 _

; N- h4 ^  B" N17 W0 K# _& |- c' w, l* @# ?
2
- J4 U; d$ P/ Y0 r3" _3 n) |' `9 o: h2 @
4
3 u* {; V' M8 l8 ~9 P6 k: H& D50 [0 J5 D$ U2 c5 j, R
6$ P3 w+ F5 P4 y- ^
7, C; M/ P$ x* e- J
8
; G, N- O" D/ B. T: N& T9
: }2 V1 t" y% V' c: E10
+ X5 i5 ~2 w7 B% i! |+ H* E0 k  {11$ c* {' j" \+ C5 B# \
12
7 x  z% p* |7 ^1 n2 h2 s13% \. Z+ R) X6 P$ H7 P0 ?
140 D9 X; F! Z( M& j) f
15& [2 R* b; [+ ~( z' L0 C
16
& {% W& q1 |6 B2 q) m! X) i17) \6 T/ u5 g  Z
18: M3 U) ^1 E  e8 |9 N8 u6 _
19
" f2 b2 I9 d5 P! \' W$ b% n7 a20% P, X4 j# w/ T) M5 Z, v
21
4 {1 A, @+ ?% C( {22- O( c; @0 b( R+ }6 X- d6 n0 J
23
# W' @5 C) G# ]" F7 g/ J24
- W  V( [. {1 B# O) Q) A: a25; w( T5 T6 E! C- c: z
26
$ O! E4 R0 H* `. X+ l27
: f$ R, H$ v1 b& f- R28
& C( G- c: l; o9 A- c. j29/ ^  l# e, n  d, v$ u3 `2 c% t4 {
30: a  E' z$ k  ~5 S+ _/ e2 A% i
31
! `; k6 V  q# C: Y9 h4 w0 [, {32
8 w4 ~7 y$ y9 E33! V  ^& j5 E  j& n
34
1 Z* M$ J& J2 g! \/ S4 z2 M, E, m35
: B, N" P. b7 _, x8 j/ T, Z368 ]5 V3 ]2 X; R+ A
37+ Z1 p' k9 m, I! f; e
38
9 g3 ?/ x3 y) `0 t+ X) J39
" Y6 Q  M3 g' j% T  A8 r* J2 f40) X8 V9 f. m. F5 T/ U  L
41
4 @7 B% ?9 [4 x9 k$ J& v5 z42
  M6 C+ @+ r% k43
3 [6 c# @2 W2 W- O- b* ?7 N44
) e  |0 Z( p4 k45
( f. @9 j- m8 T4 [归并排序的特性总结:: x( J8 g3 ~, O
1 u' c7 C& I5 o1 ~! l
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。* D. w( y" \! B  o4 q0 k. L
时间复杂度:O(N*logN)
! T6 N5 v+ S( V# H8 }空间复杂度:O(N)
' b+ G/ l) _& [稳定性:稳定
* E3 i- m7 Z9 g. k( d6 y
8 T8 ^9 _% @8 G% C7 L% v————————————————
/ S$ f1 j6 n( O, i( u版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。% Z4 ~) J' V! n9 c
原文链接:https://blog.csdn.net/weixin_61561736/article/details/1267966576 {# H9 `* D% S/ k1 i, m/ {( y

- ?& p- r8 ~* q" z8 K) c9 c5 l( ?! S& g; {( E5 q5 z  U+ k





欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5