数学建模社区-数学中国

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

作者: 杨利霞    时间: 2022-9-14 16:22
标题: 【基于C的排序算法】归并排序
【基于C的排序算法】归并排序0 _* Z6 B( `; `# W

" {# t3 z$ G8 Q前言
4 D; A& R* }# s9 o& u/ g本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
' l' |% P% F0 b* k9 }/ ~( [8 r5 F8 j  Z" x* }2 d! g- A# @$ d, |; ^
归并排序
0 l! J& ~6 ~+ M3 Y' @1 n# ]5 F基本思想
+ b1 r& N5 q+ T8 x4 c- w​ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。4 ?' \3 b! ~) Q' Y7 x

4 X/ Y  a3 H& T/ K0 z+ p5 g4 \! j, P# W6 p" j/ ?
1 Z( b' j4 ]9 x, S/ M- p5 Z
​ 合并的思想其实和有道题目的思想如出一辙:
0 h' v* g6 j7 \* F5 Y# _$ S! i
, c* F; j  e* A* [
8 d0 ?$ J6 a' I1 [4 {" J. C$ k0 L/ v; R8 U, r1 x0 t0 T& M$ N
​ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
, N% z$ T7 m/ w# s. M. o. \  p
& _/ c, L3 @  ]4 B* V1 F  [[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]" E- R( Q$ }6 g- t) g( n" P2 K

; P  t9 K) c# l& z0 Mint* merge(int* nums1, int m, int* nums2, int n)& W3 |0 }8 a7 E
{
9 \3 w; |; M' s/ v2 o7 b: ?$ e, e        int* arr = (int*)malloc((m + n));
) B3 j* k, w# f. G9 ?0 k- d    if(arr == NULL)
1 r3 R) @- L. \( ~4 c    {1 k- I! k5 J4 B" A, C2 U' b3 e  G
        perror("malloc fail");* @: `9 P2 X' @0 l) ?% ~
        return;
( ?4 p0 \" K1 a+ g; Y* T: Z* v    }
3 w# ^# n* P1 l; r4 J; X. Q
% ^2 n1 |& Y6 G  R    int p1 = 0;
2 w7 V6 r4 U0 z6 W& d6 W8 ^; w    int p2 = 0;
! y7 o1 U4 f& n' F; s  a% `: e    int cnt = 0;3 x0 J8 }2 y( ]* e8 c5 m; O- c" t
    while(p1 < m && p2 < n), S* M) _9 y- n2 w3 O- R
    {
& k8 ^  O6 ]9 k! K        if(nums1[p1] < nums2[p2])! O$ X0 l, U3 r# K
        {6 j% ]5 i! J+ ?+ l9 T! L. C
            arr[cnt++] = nums1[p1++];
' F' F) a: {! P& w0 w* Q8 n        }
: m9 s9 c& S' y2 f$ @: e" z        else, g5 H9 T; D* b" y# f. U" A5 {
        {/ F. L' j- B0 Q' ^; y0 H& z9 C
            arr[cnt++] = nums2[p2++];
) ]$ W* j& v7 [; \  D! t" I        }
& X! C' o6 U. x" Q3 \/ V) i    }
% W, K; s4 u2 f/ Z    while(p1 < m)& X- S7 d( ]0 E' V
        arr[cnt++] = nums1[p1++];
, B( P, z1 V2 q; J5 A! K2 h8 c4 S
$ q( R0 l, r! j9 R7 d" w# B    while(p2 < n)
* G9 S1 V8 S$ P# C2 |; V: Y4 Q' Z; S        arr[cnt++] = nums2[p2++];& y# _# ^+ L& `+ R' w
, P  Z7 i; i6 e& M
    return arr;
( Y1 x6 w- p- l- p' s}
7 X- ?) ^' y: i8 V: O/ O
! J8 U) {4 Y: p( y2 r3 x' s+ r13 t2 ~8 }! P7 H' p1 x" s2 q
2
* @+ A, @( ~. T- S" U, Z3
1 W' |; ]; @4 t+ ~4/ X" i# `( u0 b& B) T
57 v7 l; Y8 o& C& {- k( k
66 `1 j. L; d7 z& w( T1 E
7( u9 P# Y& c- _/ w" i9 x1 j
8
- c& p+ p( A& J0 D, P1 X$ K9) j+ K- g0 K" Y5 i
10
  H6 @, s" {. P- V& d  o* |116 a# {- N2 c5 g8 l
12
3 w* h0 t; Y* ~/ D4 E! y13" b+ h$ t# E! P! R( k
148 h  \; n8 Z3 s0 g5 R1 N0 B
15
+ O: W4 B. e/ B/ ^5 z16
5 I( o; ^& _- l& }& x! z2 z17
. T* t7 ?  }/ U& D+ d5 R18' C; ?# z- I8 o
19
8 p. [; U' V' D) ^# E, O) n3 S  B- Y20
+ u3 F9 h4 O% c0 F" @7 M21
  \; ~# M6 ~3 J9 a2 G3 F& V22% E3 z. ]3 x) `" G; ^# C
232 q2 m) ^8 H5 W) l' N2 X9 l
24, ?7 K3 J9 ~, f5 }# F: K
25* s. ]2 }& m% d1 n* B
26# P4 L1 b1 H7 I* C. z3 I1 y
27/ _% N( ^; f& a0 @8 w1 f
28
% E. d6 F7 z9 Z9 N1 g29) S( Q# K4 U1 {$ N
30. g5 }- S" h) N; ~7 y
31& A. z" y  \) ^* F3 L$ C
​ 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。0 `% K7 f8 V2 _4 C* h  t
* u& X0 C" P4 W* A$ {7 T8 P5 I5 J- I+ h
递归实现! D& u: x0 L8 {+ Y; ~
​ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
+ [& z5 l8 q1 {7 O& r! A
( ~9 X% ^8 T  p" }1 u% ^2 X. W9 U/ t, r& C& C+ g5 ^4 I( w

, K; m0 g% _6 s2 Z, z6 i6 k3 I6 Q' ~9 G

% M0 e8 Z0 V4 f! qvoid _MergeSort(int* arr, int* tmp, int left, int right)4 `1 E- p, s4 `3 [0 S7 T
{- }- v' |4 [6 s9 N& i
    assert(arr);
+ [( O' a+ P$ k1 ~0 ~: H7 K( h  j: V' f5 k
    if (left >= right)//递归结束条件不要漏了
- b) _: Z2 g, a: x        return;
$ C( q" n- n, q3 @0 {' n4 v7 g
; i! l/ u7 ^% D: P+ c3 b, W3 d    int mid = (right - left) / 2 + left;3 C' U+ _* k; `& x

/ p& o/ H- N8 r    //划分左右子区间[left, mid]和[mid + 1, right]
3 h  w2 \0 }6 Z- P7 e* J9 s  S    _MergeSort(arr, tmp, left, mid);8 H  Y+ H0 u9 i8 v
    _MergeSort(arr, tmp, mid + 1, right);2 ~7 ~0 \6 r: |" j1 i
0 {" I" {0 U* Z8 w
    //归并3 T6 p" d1 t, k* P' d. b& t* i
    int begin1 = left, end1 = mid;
+ [/ F( O# S; c1 {1 K    int begin2 = mid + 1, end2 = right;
9 \5 h" Z; S# ~    int i = left;' n# M# P; @9 d5 ^: b$ Q7 S; Y
    while (begin1 <= end1 && begin2 <= end2)
( O) |7 i( }# T2 e    {
! b% H, }+ T0 P5 s5 P" d        if (arr[begin1] < arr[begin2])
# j5 r) B9 v6 x- X            tmp[i++] = arr[begin1++];- `6 r. K1 {) Z* T5 Q3 U
        else5 A2 A- H6 Y+ W$ S% ^
            tmp[i++] = arr[begin2++];
, Y9 Y5 c0 A2 `5 ~' z    }
( u& ], e0 ~" M) p0 S, o2 W/ H' V: \9 P; [, k& a" l5 t2 v
    while (begin1 <= end1). K, F% [' c# V7 n
        tmp[i++] = arr[begin1++];( G7 x' d9 P1 u5 q. O3 @
    while (begin2 <= end2)6 Y) N- e/ a- Q+ V6 i' O$ m
        tmp[i++] = arr[begin2++];- [% k" F6 L! C! p8 p/ X
        ! O) |7 @% T# A( k  u8 w" a3 C, ~
    //拷贝回原数组——归并哪部分就拷贝哪部分回去3 j& q7 r1 x6 m4 A* p* G" N5 `
    //而不是拷贝整个数组回去
; ~( n. }/ n9 ^2 Y) E$ R: U( s2 {    memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));+ {7 B3 y. t; h8 Q, y# m
}
9 m2 a% b* Y  a" n1 ^( E1 K
5 d5 U; K$ S) m( [  `void MergeSort(int* arr, int left, int right)8 }0 e' C1 j7 W& _* S1 ~- H9 `0 }
{
; L2 o  u8 j" E* r    assert(arr);
8 t! z6 E' B, D6 r  O* Y5 t' {; L: g+ t* [6 Z1 z
    int* tmp = (int*)malloc((right - left + 1) * sizeof(int));# K( b6 F0 e4 z4 M  k
    if (tmp == NULL)
0 l, G  w1 S5 v, }    {! M+ G( O1 D' H" I+ ~
        perror("malloc fail");
/ r9 l, V' ~6 B# M2 ^% J        return;0 E, [. B. h' O1 J0 D, Q/ \8 A
    }/ P3 Q# d/ D. u0 R; R: q# B

4 K4 x/ {  t1 h  C' V( H    _MergeSort(arr, tmp, left, right);7 W1 w+ u4 n+ u4 g" Q
5 N" {7 h* T- d0 K
    free(tmp);" P+ A) D9 x  m+ N6 z. Z) m7 F+ |
    tmp = NULL;
; c" B1 m$ V. `, G% G# D0 }; ~}0 F/ B3 w& X' D% y  L3 R4 D0 Z9 ]

, W) @  z, {- E. u17 N/ ]) ]# L5 p! j/ m1 K+ [' G  O
2
0 j1 S2 _" k; S+ s3+ b$ S8 w( W' A' D% _. R9 h
49 ?3 ~- S9 I- H" m  g; Z' p5 p
5
7 q6 w, M$ a  r( W# _8 G65 }# {& q* N( [" H8 T
7  ^; E2 h* _; g& U1 M" t
8
' @/ o$ I% V% V9
) p5 l1 H  M8 q1 r108 @# \1 Y  I2 X. b$ q& \
11
! g: z# h5 \+ Y  }6 _12
* t# U# u5 x' T+ e6 \) ^/ h6 z; r13. {, A/ F: q' @- d: K2 q" K/ z
148 v; w3 S4 w- t/ @9 l+ X' S
15
9 I' E# S5 ^: c" X165 j5 _. Q5 I+ w7 T5 p& g
179 s7 ~! h% L5 H1 \6 y5 h
18
. i% @- m* W. a7 i19
8 f2 c* c: ^  V4 M+ |6 N- ?3 k2 x- b20
3 ~) q- K  E0 j5 `1 d4 s4 \# D21
2 l) I: \$ Q7 u% d229 S; e3 {* W9 \. t- s) W, L6 `9 w
23
6 |6 R0 R; |1 ]$ O/ E+ L- i1 l24" l# c4 D: A; o3 \1 r$ C+ U
254 ^' x" I% |" [4 w) p& ~" `0 n
26; r1 j& E( u8 u2 Z1 i! S
27
/ P& S, Y. @" A/ K8 M  F) H0 e28
$ r- ?4 J! G/ j3 t2 s29
$ X7 r: j* j: E3 A; m. v& s30
" a8 m* o& ^/ a8 P31( o3 J8 |$ N* Q, u2 G  g
32- d) y) l9 i  v* Q$ m& d( M/ K
33( Y2 u3 Z7 O" [
34
' Y/ B  r5 `  c$ n35; l, k; D! s9 b, Q4 Y2 n
36
5 s& `: W4 u' @7 U" e; i, _# _! k37
. i  B4 A7 v$ T9 ~  |( z38
( o/ }, ^$ j1 r1 z0 c! ?1 Y3 E+ _6 }3 W39
0 r4 M+ s2 w% V$ r$ m, o40
) |' `3 K4 I: m9 j41
$ }& B1 e3 g/ f4 i$ |; j- C42
4 j/ \  {' Q: ]43. {! b" L2 v, T6 F- p) H/ G+ W7 i
44
( N2 k$ j+ c; T. W45
* D  l, b4 o2 E: K0 V46
0 o; {5 M. R# s  S47
2 d9 H2 \. H1 j# h) f% ~% Q8 y48' @. f0 k, b9 Z: A: |' M
49
1 N6 X/ e6 q3 v6 P50
0 p5 H' K$ C4 V& e5 L- O# X! B* t518 \4 N, ]$ F9 x5 Y
非递归实现- P& U' z. b( q. i& A
​ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
& z) o/ n2 Z( M/ N; \- S- ^9 r! X, \* l0 i8 d- |) c

6 X1 ?: z: l( ?. d, \" \& q
5 _4 A/ J9 d) F/ N' }​ 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。  P7 g  Q! K# o( Y# ^. C
5 c* S( N" a* }) s8 r; J8 x" k8 R
​ 还要注意区间的取值,每个区间就是一组,就有gap个元素。
% {/ e) [+ [) R9 v( W- T4 p6 T3 V, X2 x9 b+ D4 s! v
​ 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。- ?/ h/ i; }) j- a

  _, P' l7 \* O1 ?代码实现- u; v$ g' M1 q+ U6 I- y' ?5 ^
5 G% m2 q1 A: T4 g7 e% U
void MergeSortNonR(int* arr, int sz)) q. M6 h/ L) S& L3 |; O
{# G, T. L6 h8 ?4 w5 V% F! u
    assert(arr);" ]% x6 l+ b# _/ V  O7 i
' Y* f; n3 S" m  _/ T
    int* tmp = (int*)malloc(sz * sizeof(int));
( h0 w, `3 W; R9 A' U; G    if (tmp == NULL)+ {" Q0 t( c2 Q: C+ b) S
    {$ H7 \' z" h* C7 |6 E
        perror("malloc fail");. H0 X7 H3 B( G6 ~. l) g
        return;: V5 P; m: {7 r# k4 Q( r1 s
    }( m0 D7 c& }: j# B* p" E1 ^2 i
3 _3 `% U7 [. |. D
    int gap = 1;7 }# D2 o& D5 g- a# M
    while (gap < sz)
! j2 K$ M* s& S    {
! Z% T* M9 J- v: k        for (int i = 0; i < sz; i += 2 * gap)
1 S2 H6 r1 S! \+ _        {
# ^# N1 T8 ^. E1 c            int begin1 = i, end1 = begin1 + gap - 1;
1 y- K  ^* g5 ]# G( l4 }            int begin2 = end1 + 1, end2 = begin2 + gap - 1;
( n. W# h0 _; }/ F7 u1 g  Q            int j = begin1;7 z! \$ o6 H( ^" p! d
8 T7 U+ _/ |- j( T4 C) c- z
            //归并
/ U! s8 {  q" O( A. w# ?            while (begin1 <= end1 && begin2 <= end2)
* [% w! d7 W2 G* [) ~) d) Q            {
$ T- C" N' C: d& ^6 g                if (arr[begin1] < arr[begin2])9 {6 n! v; @3 G5 w- L8 K6 a$ a
                    tmp[j++] = arr[begin1++];+ [+ Z& V0 j" X) ]% @
                else     
, N* z, j1 K0 S5 r                    tmp[j++] = arr[begin2++];. S7 z: I" I* k# L7 ~! G0 X( B
            }
$ ?7 B; A2 d$ o' m$ ]" R1 N
( H, Q; ]+ \* t  B3 v3 l            while (begin1 <= end1)
6 W8 L. N$ J# [                tmp[j++] = arr[begin1++];2 p( F1 m( u% p' h
            while (begin2 <= end2)/ u7 K0 S5 Z: a0 M2 p6 W
                tmp[j++] = arr[begin2++];
- k( N9 n+ X0 k5 `/ {
$ G  w# ?9 p9 U- G1 l3 w            //拷贝回原数组——归并哪部分就拷贝哪部分回去
8 m$ D3 t" e$ c, `) C5 Z            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));+ R4 k1 `+ Y" K: f$ T# m& V
        }
. _% [* h5 `2 E9 x4 |# F        gap *= 2;
6 o' B5 i' Z- ^# |. ^: \& ^$ [    }2 o2 u2 ?% g- Q  I' b5 c

8 I, U8 D, n8 G. q  z3 L, n}3 Z2 V; B/ m$ s9 ^# m
$ r5 ~: ?3 {, L4 v& c
1: e0 f: A3 @* |9 A
2
9 E0 P5 l( I, s& I3. V1 [3 [; k, L0 a% v: |0 s0 b
43 h; d: ^, t, {* C& a
5: s% u9 M, F# \& F2 V# `9 F/ _: S
6
7 F' P% O& Z* a4 C! G7
/ b0 Q& A: _1 q! P. R8
0 n' h/ s+ S2 @0 m9
" p1 s& o: Y3 e5 `+ G10
1 G- ^1 ?7 G4 R1 P% t. {5 c11) Z; |' o9 |# f3 f, B
12# C: ?7 B$ e4 M: d. h7 V
13) v* m  ~5 O1 m) q
142 Z7 q# Z) A8 H$ U5 r$ }
15. x: g( ^% r, t; M& U4 o0 N
162 ]% Q: r) k  I) }  L9 }: P  Z% E( g
17
8 q3 N9 h: v1 `7 j18
! ]# n6 s, w' Q$ i9 M194 f. ?$ P* z/ q: H+ y# ~7 n
20
3 N3 U+ K! U4 _4 O' g0 H21
9 U4 I% K$ y; y! @8 X22
  |' K  k, {' w1 p) ^; Y1 }# ]5 M23. [2 {7 n3 l9 a( {8 [
24. i% v3 I9 J9 v1 f
25
" M9 M" P( J% P2 l26
$ F9 h) Q9 o$ I27
5 i+ Q& x4 V7 H1 F, Q2 C283 g- ^. L% m# Y- Q
29+ V3 R- S# A* ^( {
303 w9 a+ h6 M7 w1 V8 v: D
31- M* _2 a/ Y; J- c
32
8 W/ c' [& ]+ C; P! _. Z33
' W$ M$ E0 r2 @$ |/ |348 f# R3 M7 u7 ?. \6 B4 S
35
- r2 ?2 P5 T+ q3 `- n36
% A; E5 g7 X+ {9 b0 }37
8 l- g2 V  b: u! D) f38& x1 }" I: K% A
39, Y5 }4 `9 ^6 {" l8 q0 @0 z! ?# n
40
, L2 @4 Q. Q1 A1 x+ ~% n7 N) k. o41  W6 u( f( R7 j
边界问题) N. l5 x- z$ N; f2 k6 z' x
​ 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。+ _; A6 N0 H+ i/ w6 m/ `. V

( Z8 U% m3 g+ p* I. ]1 l举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:! p% v) Q" @$ w2 @

* ^' w* J% F( e! g% q# P
4 S2 P6 J$ T- P6 w8 Y, L7 F' o" C5 ^; ^2 K& X0 n- d$ B
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
1 B9 e  }, S" l# ?! l: O/ u; e% C* Z6 W
第一组越界(即end1越界)2 P( C# \* {* o7 _
6 q, `8 J) y) \: J, ~
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。8 f) Z* M" ?2 f0 r; P
9 V0 t" L9 i4 Y( K" }' G9 r/ `5 g
第二组全部越界(即begin2和end2越界), w# e3 l) X# r% G! E
7 ~! y# I9 \' w5 P" _9 I6 {0 `
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
$ s( [; J$ Y! p0 ]
$ A6 z+ ?+ j- V7 v第二组部分越界(即end2越界)
+ e$ {; M# p& i! \# d; {
. f. X" R% Y  x应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。0 T# g4 T, `5 e) r% j: w

- I1 `0 l7 S6 r: I​ 其实第一种情况和第二种情况可以合并为一种情况,原因:3 G" F* I# U0 w- W/ t5 _
+ i+ O2 ^5 z# Q: u" I; {
​ end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
6 o: c/ v3 E. Z! G0 S" ~$ E% I' i/ s7 T+ q6 \+ S
​ 拿两个数组试一下:
! g, d" U0 ^+ D! ~" j5 M/ F- {/ z7 {

$ }5 x1 C( z$ o! L* e$ S& w% w8 _) |- J' Q  S- }/ P* Y# X- U
6 h3 z0 I' h) k% R7 q, y

) X8 j, Q% l& \# i: Z+ U  U9 t代码实现/ B4 y) l- [. J1 O+ {  M" @

" D, F. Z8 Z0 |: A8 `void MergeSortNonR(int* arr, int sz)( d2 R& L7 a+ ^
{3 o- i. ], f# @" E  n) n3 `; n
    assert(arr);+ m2 {: D9 e% `7 l
: C6 Q/ Q7 \0 c" g* q3 L& p
    int* tmp = (int*)malloc(sz * sizeof(int));3 P* _1 w3 y# Q/ \
    if (tmp == NULL)
- `5 C; b/ y+ R! u+ `" Z    {4 e" A) Y" s; Q( }% U- T; Y! S8 [4 n( R
        perror("malloc fail");' `5 ~/ O0 ^; q. U1 F8 I% }6 y
        return;" c$ F1 d3 I- w; X+ L( j' E+ N; P0 k
    }
: M1 z% ~! s3 R: N: {  u- v$ J' j' _, t" m, S
    int gap = 1;
3 U: D% N3 J" U4 R& H+ Z$ n    while (gap < sz)1 o' g! [% R- {/ m( g. b
    {( d* S9 {, K6 U* ~" B
        for (int i = 0; i < sz; i += 2 * gap)
, d" q( W/ c9 P  G( r! Q3 h5 F        {
, Y5 X# m' }; Y            int begin1 = i, end1 = begin1 + gap - 1;. u$ ]  X2 E4 A* V" w& X& j
            int begin2 = end1 + 1, end2 = begin2 + gap - 1;. u7 L' x3 h  w2 P3 b
            int j = begin1;
; P: ~3 ]( ~* v& D                        //越界检测$ H0 f# \: {. E+ P0 y1 o% C
            if (begin2 >= sz && end2 >= sz)0 P+ Y4 \# u3 @- p) ^
                break;
4 J3 Y% c: o  u/ H9 w" G# m            if (end2 >= sz)
  ~; i) c" Y0 D- ^' h6 D4 ^) P8 w                end2 = sz - 1;
+ |" h! A4 |9 g) V! L            //归并" Z7 ^2 b1 y( Q8 D; o% W' t/ R( C
            while (begin1 <= end1 && begin2 <= end2)
6 }& q9 l+ |$ ?: L            {
/ x, ~6 I# D3 p2 \                if (arr[begin1] < arr[begin2])- I' _4 y/ r7 L* |
                    tmp[j++] = arr[begin1++];
2 ?% W  o& K: o) K, F+ t                else     
% \* @2 w/ F: a                    tmp[j++] = arr[begin2++];
8 M5 h2 Q# L4 I. B            }' j8 G- v  I' i: ~, I
$ d/ T) y/ S+ d
            while (begin1 <= end1)8 T1 y( i' @8 N% e1 h# {0 h# G
                tmp[j++] = arr[begin1++];
; g) p( q3 R4 u8 L* k* \4 ?3 H( a) K            while (begin2 <= end2)
1 }: S$ a+ ?5 X                tmp[j++] = arr[begin2++];
, V1 {. y$ L1 }: z
6 q, M2 B8 O$ o! B' I0 C            //拷贝回原数组——归并哪部分就拷贝哪部分回去
6 l2 P# H/ o9 \  w" Y  q, @; B            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));4 p1 p5 J' }  l; A6 N
        }
6 R; q) }: J$ O$ W. z9 i7 Z1 _        gap *= 2;
1 _" D6 ]9 `/ _4 `! `    }9 p: [' i, O" v; g
# u" \% T; D* m2 ~
}0 B0 M- v- j1 G/ Y
8 Y% N1 B& r" N" [2 q) z" `4 o! S
16 n% B& D! p$ ~7 M# V4 B
2) H) x# t  L4 t1 O/ {% ?. g' `
3
* M2 t- r7 F6 M7 q1 U* P; A47 E7 v) l. E6 ?
5, |7 S+ w+ Q  t, Z. l; u- Q
6
: G1 P4 u* ]+ s  W7
! o9 d, R; q1 o8
) ]" v0 I  o$ a4 W& Q  [9
9 i. o& \2 K6 d108 J' H0 N+ o0 S* G4 @
111 ?/ n$ Y5 q* P6 O) ?1 t& X
12
1 Y& T3 T9 J/ r# w' |, B3 F13
0 ]7 I( n5 B7 I1 Y" H14
6 u0 l0 M) l6 }6 l( c15
9 J% z: {- O# d  B16- ]# c% i7 [) z4 v
17( @# x) M# ^# U% M. B" O! w/ u/ S
18
$ _7 `/ @' f4 T8 o$ O: V) D194 O5 b) G! ~6 @- Q( I
20  Q( d# R' Z4 b" O( ^( H
21+ B# R8 ]5 X6 n& ?" c9 X
22
$ X& _4 ?/ Y% p23+ ?, K3 l7 J) m( b2 |
24* i4 ?9 B/ f; I
252 f# V& g9 i; M, t" x
26+ _( m' {- e4 [* ~3 y5 G9 u) T
27
7 c/ g( I/ ^8 M& K7 b282 K3 y0 K5 S0 k
29
1 m8 n& }5 \/ F# t; j0 C! }, ~307 ?: c7 g) S' r; K
31) c6 U. \2 ~5 v9 l! w
32
+ _3 J  c: L! g, ^' I332 E3 h" V( h+ p; N7 J4 r" D3 S
346 }& W, q4 U+ t
35% d' v3 N$ T5 J$ F/ o) \8 G* d- g
365 J- L2 l% r# i
37; c$ e3 {/ A: O) X
38& k5 k2 p0 _- }% C. G, F
39
0 w5 ~' I0 B+ z+ _" Z8 ?+ n40# T; M; u$ D, F9 X1 n
41* E0 g4 R& r& P1 ^6 }! |; v- y
42
% d6 X3 B0 i4 k4 R& k" o43
$ E- i" u3 v( H0 H! d) @5 U44" s3 c4 E1 r' e% J' r  C
45
. l. X" {8 c, I8 x' N  d. `" }, J归并排序的特性总结:/ m3 Q  S( a0 k, ]. Z4 O
$ s# h% E( q: E: y* g2 }; g) }
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
- Q) D: Z! U$ @/ |时间复杂度:O(N*logN)# U' q: \$ r% p, s0 G: R9 ?
空间复杂度:O(N)
0 e" n9 D0 J6 H) O稳定性:稳定5 E7 W8 A3 _( ^  \' T

( x5 Z# H3 ]/ N2 w/ d————————————————) _' Z/ y3 {! k( K: U
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
% j! P/ n- E5 r* o原文链接:https://blog.csdn.net/weixin_61561736/article/details/1267966570 m" F  W# J4 B" k

# @. b0 _$ K) W) P. E2 d4 `; B. v. ]& ?9 t





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