数学建模社区-数学中国

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

作者: 杨利霞    时间: 2022-9-14 16:22
标题: 【基于C的排序算法】归并排序
【基于C的排序算法】归并排序1 W0 |4 M& N- |9 w0 q
: L7 v8 q# e+ K
前言
. s  I1 @! N* ^5 @, g  P7 s) h0 j1 M本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。: _- C7 X. p2 {+ ^% V2 ^) u, r

4 d) d% P) v, x% g  t归并排序
1 K: ?6 l7 S( b0 |3 O7 g: z1 R基本思想  w; v0 [1 P* {$ T+ p/ t+ h
​ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。) K; V; Q) d9 w1 W

5 K$ a) N7 n4 Z1 ?. N8 O- S  j) e* K( y, i4 ?6 x( F* r
: t* b3 C) ]$ `. H& i3 F
​ 合并的思想其实和有道题目的思想如出一辙:
+ A, D+ B6 D2 `& L  M* [- Q/ {& y0 }) j0 G( _

4 p  }, o* e. e! h; n$ M' x, [* F+ I. W: n7 [
​ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。) i# j* y" e: d9 W% w7 [
1 P: D% w/ P/ _% z
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
: Y4 G; Z- [+ l8 B
7 d6 X9 j) y/ E: U1 p# d% t( K- wint* merge(int* nums1, int m, int* nums2, int n)
$ r' b, T) L" g5 g" ]{
( G' D* Y( m( c! `        int* arr = (int*)malloc((m + n));
. J2 S% f2 r5 [, `. `    if(arr == NULL)- M7 |3 m( R% ^0 Q( t) j7 \: G
    {. f" Q% e5 y( v1 l- I
        perror("malloc fail");
! t  X( P5 A: ^        return;
# E  a, ]' O) a3 ]$ `, A2 J    }! E, c. t2 ?, e$ n9 G, y& ?0 z
  R7 j4 `& q* f% G) P
    int p1 = 0;
) S! P/ M- w( H  b1 u1 y    int p2 = 0;
" p, t  e! |. L9 r( f% @1 l0 j& p    int cnt = 0;
) c& k, J9 ?. C& V) j7 o8 j: b    while(p1 < m && p2 < n); A9 j: N5 N# M9 T; \$ I* A
    {2 N2 k4 c  z! ~
        if(nums1[p1] < nums2[p2]); u& F  ^1 b9 f- Z
        {& c# ~! c$ z2 u% v' l5 L% q
            arr[cnt++] = nums1[p1++];4 G: f: X0 b" Z. v
        }' f/ s# q( i7 T, i
        else5 W7 r# [- M/ v; e6 v- o. X( o' g2 y. t
        {
  Q' z# v# Y4 C            arr[cnt++] = nums2[p2++];
( ^. Q$ A  F7 v- I  o4 B) K        }
. w0 a  Z- I% m' M0 d    }
8 Q) p$ Y& L! S# q- K$ D0 V6 E/ A    while(p1 < m)2 p6 N( _: h% m; \( `1 S6 U
        arr[cnt++] = nums1[p1++];
  Y2 {& z) P' Y9 w! @5 D
% ]$ K0 d. M; i0 u2 f3 z1 H# j    while(p2 < n)
; t: F* j' k# G# V, O2 \3 D        arr[cnt++] = nums2[p2++];
5 `& n  j: e& |9 F; f* ^" r" g
    return arr;0 X. d! n- c$ k7 d$ w9 e, j
}' N  Z$ Z. V6 Q, q. a& j4 k
5 w' @- M8 ?2 B9 t. M7 s
1
+ y/ i2 |( |: u7 j# O8 g2
7 c9 I7 c: g" P( V% C7 c7 w3
- ?+ X! q- O! a# z& `4
! h% L7 N6 P# p7 `4 F1 J# h53 p+ s$ l* M0 I
6
+ s2 O! x* B+ O7
( w: D8 ~4 m8 {; W- }. C8$ X: g3 K# K. |* z3 s! Y
9
, e! \* }3 ~( o10
8 P9 N9 W8 |6 x6 s+ ~$ }, c" Y11% j8 ]1 c" r1 \- p# t) m2 M
12
: T. O) ]; A5 f( i, Y6 t$ Y130 u! Q% Y$ E/ q6 g
144 `! V. W( u( J1 F6 P  x& X
15- z& Z6 N  [3 q3 e( Q2 E& ]% H: @
16' c% P* T2 I2 D9 [4 i3 c9 h8 M, _
17
4 v3 i. R; }# r9 G8 {) C( A7 l; ^' _182 u* M* y% M5 |! `5 n
19
% X6 S( |; `7 m' o9 l$ |5 N2 `20
; B9 k& L2 l  v" O) j0 ^21
2 ]9 i- G- o& ?& ~9 i! N3 v22
% A) {& n1 ^( h6 i23
  C& f) q( U. u) |( ]24
0 v* r# ~1 M( |25
! z: Q1 [" h, d' j$ A26
& e9 |0 B6 y' m27' Y- i# o) {3 y! i: c. o  k
28
; l* d0 f) a0 @29
8 ^, p! ]9 o6 Q3 \3 A0 B30. T( B* R( L! [3 Z; p+ }3 x. u
31
: @7 n* A4 e9 p# P2 X/ F/ W  ~​ 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
9 a3 b" \4 @7 b
; ?4 x* i* ]$ z0 M3 W. a& ?递归实现
$ P" c$ b, J. b4 j- e" Z" c​ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
# y7 Z7 z' ^7 c3 n- k
# L$ Z$ x/ f" U! t+ n0 q9 @8 M/ J/ }- P: p) ^7 r9 B
! m3 v/ P- D( e8 Z6 h

* x1 d  k8 _( P' F* y
$ X# G) |0 {; ?void _MergeSort(int* arr, int* tmp, int left, int right)- `/ o* Y4 g1 F  a/ s6 ^! z
{
- k% ~! h, f' [2 ?4 k- u    assert(arr);: S  z1 A& _# M: S) s+ r# L
7 J" ]6 m+ [, l% _- a. D: O
    if (left >= right)//递归结束条件不要漏了
* O) C) w2 ]9 W( T9 H; @2 Y        return;# r9 |7 I6 p) {, s" r# R; ]9 R
# q- c+ K2 t0 @5 w$ a: ~
    int mid = (right - left) / 2 + left;
7 L4 S# w# z, g) a
: |! x! F0 y7 Y6 p& a- q8 }2 `$ L7 I    //划分左右子区间[left, mid]和[mid + 1, right]) m, b& V& ]1 w2 Q9 i/ W6 r
    _MergeSort(arr, tmp, left, mid);4 h: e+ D6 n2 h
    _MergeSort(arr, tmp, mid + 1, right);
) e4 F7 V; S* J* l/ [1 V  T2 e% {' \0 {6 E5 _, t" t! X
    //归并
  i$ h8 N3 [( `# g% j    int begin1 = left, end1 = mid;
; d5 @; S! V8 W    int begin2 = mid + 1, end2 = right;4 k+ f& p5 o( ]' ^- {+ ]
    int i = left;7 G$ |- u5 |: A
    while (begin1 <= end1 && begin2 <= end2)+ Z6 G! B. t, K% q
    {
8 M7 H& H  d5 ]/ P* s. J        if (arr[begin1] < arr[begin2])
! \1 S9 N$ [% e1 r            tmp[i++] = arr[begin1++];
4 |6 ^, y2 F# P        else; _5 E2 Q  h/ K( ^# Q: R; j
            tmp[i++] = arr[begin2++];
5 `7 l/ A2 Q% C0 |# s8 H- w6 \    }
" P- P9 p. r- P+ m7 ]  G- e0 Y
  i" K. I  d( G: h4 l. b: _    while (begin1 <= end1)
1 p! i: m$ e' X2 t        tmp[i++] = arr[begin1++];8 L7 s8 o4 s3 j
    while (begin2 <= end2)
1 O: R4 _6 D1 Z9 H4 l% J% `        tmp[i++] = arr[begin2++];# V: i6 @$ i+ f; Y8 `
        ( M9 r$ J. [4 m4 f1 r
    //拷贝回原数组——归并哪部分就拷贝哪部分回去, x+ \5 F$ @' Z; i$ I3 e
    //而不是拷贝整个数组回去
, N6 |" B& g% \& A4 {& A* X8 ?% w    memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
8 i+ H4 M, w& U4 f}
8 k" s6 L9 N  ^; G: s) i; {8 q
: ^) V( Q7 v' t* @0 W# Uvoid MergeSort(int* arr, int left, int right)
- n! S/ {3 \, q/ Q+ J{8 s& O  y3 n5 L% ^+ J/ h" m
    assert(arr);
) h- j8 B* a8 P. u  d; I: ?1 M/ n* `2 u) t
    int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
2 D% D: n- \7 ]( D# G    if (tmp == NULL)
# s- G" M, V# N. h+ p    {0 h6 s4 P. a% V0 V4 {1 u0 h7 l. k! S+ P
        perror("malloc fail");
  K( g; p- z8 X        return;. `( N$ J$ s! F+ c
    }. ?, c% i6 u2 N9 P) s4 |/ ~1 ~
9 b* @% D7 M% \9 X, c. {& W" F9 y
    _MergeSort(arr, tmp, left, right);
4 S+ B/ W# u+ A8 D# w* g0 x7 k- K  C" N) c, A3 r7 _) ?+ }9 r
    free(tmp);4 o0 }7 A. a. f
    tmp = NULL;
1 R& ^9 ^9 \3 |4 p+ `}+ N) r$ P0 u4 m  }

* `- C9 z  D$ H0 R1
# Q: D3 Y" H1 t6 c) w2- o: m5 w$ u4 [
3! ~) R: Y. T2 ]5 A* F
4
' B  L6 {' @  R2 D3 X5
) {! f8 j6 K+ B0 c9 w& J) L6  d7 n* R) k. }9 N
7, E# i9 Q; c+ }& j
8. [* a9 m4 Y& X' `* i0 T( C
9
$ `8 m" U$ @4 ^4 O3 l6 C' Q10- R/ G, k1 t3 [! E/ O$ n
11' Q* n, Y) ^8 a- A: Q- C& y
12
, p8 w" J4 O( Y137 m, O. _6 F0 Q+ C. o. N0 ^
14
# y; m5 @) S  l( R) L159 B' H8 h4 l, u
16+ W$ a% Y/ W: ^: C% `5 l
17
- K, e, U! K! V/ C' F9 p18
5 ]2 Y9 f. h& m$ l! _; w9 M" z190 c& ^* b+ O6 j3 R% Q
20
0 I* `+ l: |* c- w  v21% P5 j  {5 M' f$ F' {% t
22
% \3 r- o1 J$ z23
8 a: {) N+ ~7 C245 ]- \% F. f3 o0 |
25& m$ y# F; Y4 x
26
) [) L3 M% K' X27
# q1 j0 e% j9 u% r288 q: t& o/ @9 b, K5 B$ Z
294 h1 }% V2 ]5 X1 _
30+ T& \, \  K% m% u9 _0 [/ R
31: F+ z2 n* W  W$ V/ E7 B" v1 D
32
4 z0 @# o' T7 r7 p333 Q+ O9 g; W0 M! V8 i. Q5 m
34
  E) W- }4 P: L. w( ?5 Z9 a359 H' j2 H, n" M
36
6 W4 b& N# m3 R1 W3 l% y. O% ^( H! c- c37
8 K' K) b2 `1 p. J6 ^, D380 A- K) z; u, Y3 [% L+ B+ A
391 ?; t0 g3 G7 V, I7 ~
400 a6 e5 n$ ?4 T
41. M& g1 z5 u( F! p( F
42( j+ M# W% F' \' D! a0 y
43
" C+ t& ^' Y: Z: ?0 g* B44
7 J" i( w: v$ E  t6 h. o$ O45! T6 s, R! s" E3 K3 b; `8 ^9 Q  z* H
46
1 k3 W; b- O* f; ]. M7 B47( u  u0 p1 l4 h0 m$ O
48+ b0 E' }, ?1 x. E# R5 y
49
  V% @! z2 w/ R3 Q) B50! z( l/ a) r: E7 v
51$ E6 _/ D( a8 [: v1 o1 Y9 M5 ^
非递归实现
. o! @% s7 q6 [8 g​ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。$ i9 O+ r. N( Y; D( c
. f* q% T3 _' D, @* @( @

8 \; p& m; R  ~8 U+ X, S
, I) ~- C+ M, G5 \0 Q3 J  S$ z5 S​ 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。! F  M; f$ G+ W7 E6 _
: h3 S8 ^& D  K. D6 M; H5 x, W
​ 还要注意区间的取值,每个区间就是一组,就有gap个元素。. ]  Q( J+ A: S7 p% k* o$ [$ P/ }. R
, ~4 {: {; I8 y& R0 ]
​ 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。; _  M! ~/ p8 h
" p8 t& B6 W# F+ A% O  E. O* s( ^
代码实现& N' ?  O. ]8 [' i; `/ U

1 ?5 B* j4 U: O/ Svoid MergeSortNonR(int* arr, int sz)4 }3 \2 g1 S# s8 ^/ v$ m% Q& y
{. u( f3 \9 A) R( d) ~/ m
    assert(arr);8 o5 i/ Q+ i, E3 o+ z" Z0 N
' V+ c, w2 f) {1 J2 B/ p& Y$ g# l
    int* tmp = (int*)malloc(sz * sizeof(int));. F/ Q- f7 N, j7 ^  w$ z, t
    if (tmp == NULL)7 U) f7 r$ R1 b. ~- `
    {# _$ M1 x5 `$ d6 |1 k2 F7 [3 r
        perror("malloc fail");. [. u, g/ s  R2 W" X6 u4 ~
        return;
7 I0 K% d3 v2 s, f    }
/ K! B2 M1 T) L( ]" T, M
5 j% a, O7 Y% j" E    int gap = 1;) V8 C3 r0 n0 d! @- L) l
    while (gap < sz)
0 P4 V- b; j& v5 q: g    {$ c9 J2 o$ Y' \& E
        for (int i = 0; i < sz; i += 2 * gap)# ^8 m- `7 f( Q: N0 W0 @0 ^
        {
8 M. N. \+ c. K. ]# M- v1 [4 n4 J            int begin1 = i, end1 = begin1 + gap - 1;% G: S, R. N# _" a* D7 t( O+ J# _
            int begin2 = end1 + 1, end2 = begin2 + gap - 1;0 \9 q) n# }3 V1 E8 e) J8 H
            int j = begin1;& b8 B' d5 d' r' ~6 u

- ~: Z0 f" |# I$ P            //归并
  i' g4 d0 G  |$ m4 s7 \            while (begin1 <= end1 && begin2 <= end2)6 V; ]4 W  r; Z9 ]2 T" c
            {- i( W! t; M* D" J( J9 s4 a8 _6 F# V
                if (arr[begin1] < arr[begin2])" U8 s! W9 v5 j( U% K
                    tmp[j++] = arr[begin1++];+ i& R+ q+ w% g* J" _
                else     * c3 H6 @; G$ i* ^1 E2 L7 f7 O
                    tmp[j++] = arr[begin2++];
3 D, M3 \/ g7 F# G6 T2 e            }$ u; s" u8 G9 m+ ~% E
" d$ A5 C$ |3 @8 i! ~
            while (begin1 <= end1)! w" d( d% w: F  r0 Y3 U
                tmp[j++] = arr[begin1++];
  o1 i* I9 h' P            while (begin2 <= end2)4 m' r& x, h0 N  O  i& [6 U4 X4 `
                tmp[j++] = arr[begin2++];6 I: C( J( V4 N; l4 R

$ S0 p5 D7 d) U  F2 F            //拷贝回原数组——归并哪部分就拷贝哪部分回去
! [, f% Z8 {# J- q+ N$ t1 K4 q% ^            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));3 i& r+ t! `8 A; _- N. d4 H: o
        }1 X2 o, }4 [/ V) @) h
        gap *= 2;
/ U# G0 F( Z, V2 ]5 R* b$ L$ J    }/ B# ]' N4 P3 |: h+ b* o. k: z

$ p& a4 d# }) ~0 O# J) e8 Q}- M& W( }% ~9 n- C2 f& k5 Q8 j

+ D) f' u$ Z2 [/ o1 L3 w2 U1/ ?9 v. G: ?8 W2 n
2
1 b5 h. J" ]3 r. I- S3" L/ D+ I' X# D* o( C3 j
41 ]9 _2 B/ v* x+ X' e: o
5
# ~3 r: U5 v7 F( d# z% S6+ W2 x% O$ v$ k# I
7
8 k. t( A5 S+ b; k3 h0 q86 S4 g+ r: X% T% ]7 M' w
9
! v: q0 V8 ]/ X, s, c! O10
- e" Q* u/ v& V0 N- B. ?11
( V/ x/ E6 _/ J8 S12# T7 f# d6 r$ `7 z/ X5 S
13
' Z% G' G$ I2 G  j, V  H* x14# ~7 A" l3 c5 u
15$ u' }8 `' w( l7 k6 L$ g0 a
16
% }4 |- d, T( d* Y17( X; x0 K# n4 Y8 k) n* S
18
: u. h2 s" z$ u& M4 C: l+ a! X19# a* n" {/ ]/ V8 Z7 ~
20  h  h  N7 h7 v% T. L6 l7 l
21& U1 i* l' l( w2 N& V
22+ D5 g# ]9 l& O- b
23
& ~+ i  i: S3 a9 s1 B, }24+ X3 F  t- E4 F% I6 W
25
6 E6 w1 H* Y# p  ]; h/ I4 `26) h7 B  z  J- |; T! Q
27
; y: @7 a$ _4 X, t+ x2 a: n# n28
1 J$ M' P; y/ d. I. y, O& A6 R1 M29
: H4 ?' O3 p, J* P30
- Z% m* O! j2 A" u6 a$ W313 U' {1 M( \+ I# z: e
32
7 P% r$ ~% L; F330 X4 m5 Y; [7 n
34( [- B/ d- s  F* q0 s3 C% I
352 q  Q( ?& A9 {5 @/ X1 W
36# h( B3 `8 \* I; h: [3 p, q; L
37
, K! b# U. [8 ^( J8 ?6 x38
! |/ x9 [7 m* g) R7 |+ {39
5 \& Q: E, O1 z0 E1 g40* r. f2 i: V" o! w1 J& N: [& W4 Y
41
( ]4 d% P% Q5 j( T( ~边界问题
* e7 r  g2 o) ]0 {2 x​ 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。* D9 {& p4 X. g8 W* [" c
4 u% W; l9 z- Q3 r; d5 L
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:$ q& c3 v' e9 K1 o/ a: S

! K" D. ]3 n) S1 o
% Z5 V& r9 g  N, u9 g$ E2 y+ i- Q  i, K7 n# X7 T
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组); X' N* Y# f- H6 K

& _, x3 S- Y' E' G第一组越界(即end1越界)+ f5 D6 [# `; m% m/ k

) u: u# Z4 P( i! P( C+ a* [) N0 R应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
) Z: l1 z- t3 X' G
1 M1 U% |& C: r6 l4 U* r第二组全部越界(即begin2和end2越界). V# C; S5 P4 v9 G9 v

; E  L9 L: D. I' x2 h% G# m' v应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。  D5 ^1 P5 g; v5 D5 v) h- w, L

2 W/ [5 u. e9 `7 h% \* Z8 ~第二组部分越界(即end2越界)
) `% p0 Z/ b% Y' [  a" Y* `; Y, K
+ P- F9 w- e% ~6 E应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
* C7 s  {6 H4 w; p- y1 a
2 R+ R6 y) U# I& T8 e​ 其实第一种情况和第二种情况可以合并为一种情况,原因:
% m, K7 t' x9 p  q& g" @/ D5 w4 O. v. Y+ E) h' O. T7 k% f
​ end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。8 Z1 u5 |, @0 B
4 G& [: ^# H/ |" Q
​ 拿两个数组试一下:* n/ @3 i  ^6 z( v7 A2 k* g

3 U  p6 |& E7 F; Q6 ?# i  P" c
$ L; a# {. B' Q& l2 d+ T: B1 }9 D; y, }$ h& V0 a

+ k$ m0 Z: [4 A4 [! y8 A
3 [' Z% ?- S" O% r3 w# B3 i9 J; R代码实现2 [3 m) f3 X5 b$ u5 H* K

5 j% _$ `' i: S# j6 L, X; Lvoid MergeSortNonR(int* arr, int sz)
& m+ X; n2 X+ |{
1 J7 e7 o& b* M! @$ n    assert(arr);
7 n6 C' `- n  R6 p. b6 f9 a5 J2 N8 w9 M3 I' Y9 f' Q/ d
    int* tmp = (int*)malloc(sz * sizeof(int));
# j# z+ g+ D# m! y! e) ~    if (tmp == NULL)
9 ^9 h* I) c: Z4 D$ `, \, W+ u    {* i# @# v7 F( d1 C
        perror("malloc fail");
6 G$ Y7 a6 J" {7 G7 S        return;8 Z7 Y- K: o" ]5 C, W. Z; o8 t; j! A
    }
, C5 i# ?; u5 V' o" l; I
. E$ j+ u+ {  c1 Z    int gap = 1;
3 _) {& B1 t. Q* k: x3 _    while (gap < sz)
+ I$ M" d% W/ o: F    {
6 L  f- w* O% v3 {0 K        for (int i = 0; i < sz; i += 2 * gap)$ s9 f* X9 y! d$ p( Q
        {, d; T3 R  M. c- t
            int begin1 = i, end1 = begin1 + gap - 1;
3 P- f( ]2 O5 \4 G8 c* c7 C: O; n4 L  e            int begin2 = end1 + 1, end2 = begin2 + gap - 1;
! i  c3 p( e: v2 |+ G            int j = begin1;
( L. N3 `9 V& \8 r4 ]4 [. M                        //越界检测9 K, J( o6 W" {, [7 _2 F' L
            if (begin2 >= sz && end2 >= sz). }  M& D/ z" t! b
                break;0 e* p9 p% c' ~* }1 }
            if (end2 >= sz)% N% g/ }" Z# E% H
                end2 = sz - 1;
: E: q8 t8 e' m- @) X            //归并
& _( a& `7 u# M/ \            while (begin1 <= end1 && begin2 <= end2)
2 @& ~' i8 [! A6 n* E# |            {
3 o* b1 L4 x8 e9 l/ [                if (arr[begin1] < arr[begin2]). _- K# G4 [/ @0 ~9 z# b0 W0 Q
                    tmp[j++] = arr[begin1++];. d% |$ o5 S' Z% c; \
                else     
% V9 ~' s$ I4 K2 E7 a5 P  B                    tmp[j++] = arr[begin2++];
( m$ k* B- z7 Y# Y/ v" |2 Y            }" B8 s3 e% B9 C* d: |& X
5 Y* t5 ^  y: m- d! w
            while (begin1 <= end1)  C  s( S& M' @5 E# O. P! a2 p
                tmp[j++] = arr[begin1++];
4 x# o5 x3 ~7 |7 q9 g4 c% f            while (begin2 <= end2)) X2 S+ a% z; s  P, |# @
                tmp[j++] = arr[begin2++];
9 Y: _5 N, ]" A# g% U. `, E5 f2 V! S2 ~, Z8 p4 r
            //拷贝回原数组——归并哪部分就拷贝哪部分回去9 `& }+ y0 R# Z  ?/ i% m0 Y
            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));* b  `7 a: j/ N; p9 d4 u1 G# K
        }
; g$ ]# l. d0 P0 b9 v        gap *= 2;
+ m; c: g, U6 ?- f    }
: c3 N% k0 {1 w: J# d0 O6 ]7 }# {# \' I' ~4 r8 h$ J7 Z/ i7 `. i
}. _, r4 i, p2 x; s) U
! s7 |+ A/ ~# a3 X7 R0 h% H$ _: k
1
; P3 d* ]% B* L+ u% Z8 k2
. t" Z# y  U6 m( }/ `. |2 z# b8 z* M* F3, N$ P8 |; R, `
44 `$ S- D% _+ b) p  K% q# t
5
6 m, M7 b3 F' k' j0 S6 Q& a* o$ Y6
' p. j& S8 p$ Z/ a& U7
7 v& _- K( L2 T6 |9 ~8
( Q5 M* _. X; `% u6 y9: Q6 `6 g* d$ I+ b% a4 p2 @
10: S! w1 U' d! L, b' O) t' ^/ n8 x* F& Q
11
0 U2 ~* Y$ t& F# b1 {( V! L+ O& N126 d+ N" W0 Q. P3 c5 `" n: H1 N
13( m! |# M$ J* S( q! A
14- U. c8 h" @2 f! F" k3 Q
15
( i/ d; S: p& [# A5 p16/ D, ]7 c3 K. g( N9 t/ p
17
  p( J4 z% e, g, j  ?18
, O3 n2 Y8 Y5 c4 P2 ]190 z' P* P9 {1 i. E+ E
20# Q  k; L) S5 F+ G  B
21
; x. o4 Q- x! c1 O$ L* y9 N22
7 u* U- d4 s& }23
' l& r& h# ^9 A2 Q240 `: E1 A% ^; r9 `( g/ ^9 {
25
5 t/ q- |& @) N" Q26; R9 Z, w; {! e8 U( }1 f
27
* H9 d2 d2 }3 I- t5 h28
2 a/ K4 L6 w: S29
) b! W! l0 {3 l' t3 K306 N' Q5 }3 t. c6 v# ^
31
1 |: _6 R9 [0 z& c+ B2 i* i322 m- i$ B1 w3 f6 n- _
33  G+ o& ]/ f4 J8 J4 o% L+ n% `8 s
34  j5 ^# W/ l, J2 q9 \
35
3 n6 n6 r  z* m6 ^" z/ m36' g' Z4 j9 W8 n5 A* e' u
37* g) x; p8 X8 ?/ b" E( \
38
* G1 K% `5 z" S: b7 V9 t39& G( i( E& k( \4 o# D4 Y7 r
40
2 \. t( M9 `+ y, K$ J' V41
4 ~& q7 }! ]4 M3 C! e42: n, {/ \" X' [$ C4 q
435 Y  |1 G; f, Y: \$ k4 S
44
7 O9 B* k" Y2 s45
" t, R1 v4 X6 ~' z8 \8 |. `% q: h7 ~) h" k归并排序的特性总结:1 o! [2 J- a( B2 q4 P7 t

) v  q; k( v& K6 {5 W. A归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。9 d* N! @9 K% w5 b& Z( h9 f8 P
时间复杂度:O(N*logN)
) n! P' Z  e* e$ b* M空间复杂度:O(N), n$ J* J' F1 M! g& [
稳定性:稳定1 [8 |) v7 P4 r7 s# r

; d2 |1 K; x. P————————————————4 f) {% u4 h* E* G! {! {  N
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。3 d/ Y2 _( t, ~/ X! ]$ ]) f
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
- o2 R$ W* h( `3 B, P1 q# _  g# T8 G1 m% G3 M
, C" w, L" D0 o( h3 O





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