数学建模社区-数学中国

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

作者: 杨利霞    时间: 2022-9-14 16:22
标题: 【基于C的排序算法】归并排序
【基于C的排序算法】归并排序" d# X; z7 R- _1 ~& W. j) o
! I6 L% q6 E6 w5 e% H
前言7 J* P0 T3 N6 y+ f7 q: c
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
+ b/ Z; K3 U# M) m3 h
" g2 X; x6 s6 J8 D+ m归并排序( h3 @# t' l  M5 ?. ]$ i; b6 \0 |( Z4 x
基本思想* J$ a( ^! w0 _. F! v, N7 c# X
​ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。) k4 V& u% X# t( M9 a% v$ F
! x/ }6 |* g1 S, i

2 b$ e/ O7 Q9 r7 t6 v2 B# Z4 |0 i; D  T. [/ x* N  M* j& Y
​ 合并的思想其实和有道题目的思想如出一辙:  y% s4 y7 H) m# E2 K5 T
& n8 e, ?! G8 {8 `) m7 o

/ g( A( q3 D7 k8 r5 d; W8 a& B; o! b; ^
​ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。$ S8 K  w) R" W7 a7 H6 Z

/ c; @! Q" x( l. [1 E[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]# t2 L1 a( t0 a  |+ l: Q) H1 M

4 a3 j1 S4 H6 j$ F4 Z. nint* merge(int* nums1, int m, int* nums2, int n)
  z7 E: o! |7 Z{; a6 `0 o* H# Y' |5 I
        int* arr = (int*)malloc((m + n));
# g  ?/ L) \, Y    if(arr == NULL)  v5 m  `/ x  N& B$ J" i# G
    {0 ^+ A" ]* b- P1 d4 j
        perror("malloc fail");
* Y, X/ _% E* ^* f        return;( A8 h; K4 \& d6 U9 J" O4 U
    }
) X7 z. c( W( Y" c/ S
$ R. a" ?6 D; {, {    int p1 = 0;
5 U: C9 K8 k) p. [    int p2 = 0;
) ]4 i3 s- N* C( E% e# @2 r    int cnt = 0;
* `& ~7 g8 S( @$ @    while(p1 < m && p2 < n)2 a& n0 x/ T; I" i! u" j" i5 x
    {1 f4 s6 Q& Y4 i/ G7 j+ n7 X
        if(nums1[p1] < nums2[p2]): v2 G8 f6 C8 a- S8 {' W: H
        {
' g( j( B0 U+ i5 p            arr[cnt++] = nums1[p1++];
: c9 y6 a: Y, `        }, q0 e/ @) v/ w/ v$ {* U
        else
" D; b6 Q+ o, ^# q8 z        {" W2 g* f1 g0 U) d+ J& Q9 g
            arr[cnt++] = nums2[p2++];
  m" Q, F# p. }! \        }: ^* r2 ?8 ]0 J/ O9 B+ c
    }) I3 W' x; ?; ?1 R  }
    while(p1 < m)4 H( g! j/ @' w3 Y+ I; F( Y
        arr[cnt++] = nums1[p1++];( @$ W# m2 J9 R9 d2 M! }) N+ A- W
" a7 {8 O: f6 I' g$ ^) U& q
    while(p2 < n)& ^0 J4 Z& V- {0 h& ^. Y9 w" o
        arr[cnt++] = nums2[p2++];) `  S4 X6 Y4 R- I' l+ C, q

8 V0 v0 \; Q( n& \; n; b: L    return arr;
+ p& ]0 l( U# m5 l; S}' v6 o0 }: s+ D" T8 U# A# _
- c- N, i% v) _7 V5 L
1
2 Y4 X" A- H" q& n' G! G2
" h/ A' C& ?# {7 N33 [& C4 h2 d" @% @) x% q0 o; Z* G
4, ]# R, m/ ^1 k
5+ W, H( [' G) I! G  }+ t' w2 u
6
1 |2 ?# B1 w; Y& }' m" ]7 X8 H7) d# F( l+ n7 K& X" H3 _+ \
8* }& h) e: o# }; k7 s! A  `. m3 K  I
9: {$ `' N- L" Z5 b6 Z
10
8 E( e7 d  b$ ]( E11
; q# e& O' {. X/ g+ w12. W7 h/ i. N4 z  w5 I
13# }( d% O2 z$ \1 ~) R. C
14$ p/ @9 ^' ^3 H+ I4 e
15
1 B: d% w  m! |$ z0 K3 \+ ]16
; T! P1 |, O6 t# ?; X* e# C' L17
) i* P' @2 `3 b3 i. R6 [0 ?18
7 Q$ X. }. D% \; h! |+ P19, h4 a7 |4 m& M& V6 x. H0 |* z; \
20. g- p; Z5 y# z: ?8 ]
213 `1 F6 m+ _1 I: c2 s+ ]/ w
22
0 y* j% g5 N2 }5 T0 |3 {/ E0 B233 a% A( a2 h: m! ~
24
3 W# k0 b: Z2 I* X2 V+ L25
0 ^6 \: u# U" P26
( A& T/ ?$ j! t7 z9 P27
9 T8 C* ]  l0 C8 Y28
% i' F' ?( R8 A0 s9 v29
" e6 b7 n5 G( \0 C1 W30
* X: a- _  A3 G9 }' O8 G7 B6 e31
3 m7 p* C( O- C- N. i​ 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
* n9 Z9 ]" D% i/ G+ A
1 g  z* t0 J" ~3 M; N递归实现
$ V' l& I, J2 ?& y9 }​ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。! Z, ]9 C5 f' O- `. v0 O) h
3 r6 [6 ]0 k* k! a# o
3 g8 ]  H0 R0 m7 e5 ^

- S: y2 M9 f# ]8 d" }0 l  q- N. W) `' ]
) u" d- s  m6 @
void _MergeSort(int* arr, int* tmp, int left, int right)2 S8 H) w0 X3 E" L
{4 b# P1 P# X& K( z& V0 d8 Z, F+ v$ B0 `
    assert(arr);
7 c4 x2 _1 J0 W" M5 t; s  a' P8 B) x3 M4 O+ i( S
    if (left >= right)//递归结束条件不要漏了
5 [! E: @' X. n; l0 N" |4 h* h+ }, A        return;1 k! |; z( l; L

/ S! b# ?0 _6 H5 f8 g/ r! y1 Y) D% S    int mid = (right - left) / 2 + left;: N/ M9 c; K$ @9 e
) u2 T7 j  F4 r- d) `
    //划分左右子区间[left, mid]和[mid + 1, right]
3 f5 w+ B- g( G2 P4 G$ K! z# c    _MergeSort(arr, tmp, left, mid);
2 N6 x7 \$ A# ~- D. d# X    _MergeSort(arr, tmp, mid + 1, right);
, \5 r# |. D7 Q5 f  |# c0 j+ V5 E5 q* e1 R  P* ~9 R+ P( m
    //归并
3 D6 o# j  q, N    int begin1 = left, end1 = mid;
( u( v8 t* I! ~4 v    int begin2 = mid + 1, end2 = right;
. [0 J/ F! K, U1 l3 U( c. e# v    int i = left;/ z# x( a) V5 ~1 A" U
    while (begin1 <= end1 && begin2 <= end2)- E. e4 z/ n  B* D
    {
+ u5 K6 Y4 j: B5 o1 h& c  w4 U        if (arr[begin1] < arr[begin2])! y& j; O  I) T' ~7 ^8 D" [
            tmp[i++] = arr[begin1++];5 v5 Z( d. u# L, Y5 C
        else. U! @! x+ \# F5 B
            tmp[i++] = arr[begin2++];# q+ T( {4 H  |
    }: }( [& Z% Y0 W: V( Y

. s; Y, X! I- J; n& N% H+ M$ t8 k    while (begin1 <= end1)* Y( I/ C- E% F1 T
        tmp[i++] = arr[begin1++];( |8 f# ~) E# j
    while (begin2 <= end2)9 v3 I! E( w7 O9 y
        tmp[i++] = arr[begin2++];% ?! X) K$ q4 n/ h- r
       
: L& V5 O6 d5 u4 e9 R    //拷贝回原数组——归并哪部分就拷贝哪部分回去
& I8 ]6 E6 s7 `    //而不是拷贝整个数组回去
# [# y, b: h  f3 w    memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));- g& c& l" `& u0 p& Q
}
% _7 |: `/ }) F  W: g3 `
9 i$ Q, n  W6 K3 d$ V2 R* b2 \void MergeSort(int* arr, int left, int right)& H. A0 w, U5 v: e. Z( w' G
{
' o5 [) P% S4 a    assert(arr);
( [9 f5 D8 `- L
8 c( J+ I: Y) m    int* tmp = (int*)malloc((right - left + 1) * sizeof(int));0 }* U- J" g9 ?; U; _# y; R( u
    if (tmp == NULL)4 I* r6 U- v4 ~" T. v7 J' S: y. f
    {
7 v' V- V+ V2 R9 C9 |9 q/ K        perror("malloc fail");
9 j+ I, z. A. v' @" i' Y        return;, O4 q, @% x- `$ }; d
    }
: X( I; f3 |* W0 U' T
+ H! I) E8 ~( Q! E: o$ `$ l    _MergeSort(arr, tmp, left, right);
( G" N- o3 o; \; D5 x5 A8 \) G6 m6 o8 p' ~9 I2 b8 N
    free(tmp);
+ u0 N6 v- E" g3 C    tmp = NULL;- I* f- g* G: ~4 j* u6 s# |
}* }/ q/ U- I- [0 n# s
- Y$ T* t' P9 B( a
1
. T/ L( T1 I' j2# X. p+ I3 [) K$ M5 w4 |
38 s, ?7 _' ^* z. I- @' E( c
4: D5 Y6 S% S& ]0 p+ l- i
57 }: X3 l0 `3 C5 H
6  M5 `) c! [; ]9 F; |+ g
75 U4 i0 J" n2 P) i- a
8
! u' @* Z' t& ^& V9
7 j1 i  `' y+ D101 }  S  \3 n' Y4 h+ n8 h
11
1 S6 Y  n6 J# _) F124 Y2 |4 f, S3 V5 k9 D
13
2 P1 ]; F; ~6 O! ?1 y: s6 G6 `/ Y14% X& V% k/ w( T! m3 y4 P
15& I: G- ], `" K
16
8 s5 ]/ q7 i) W) i) j17
$ Y. _# L$ b* v: f18$ o4 ?0 ^: V2 z# Y
194 K, Q, c6 \/ w7 B* l( Y2 Q' I5 I+ i% e
20! }( Q/ l3 r  |
21
6 W6 H4 O9 f  [9 u9 T# |# K2 f22
6 R7 @' n4 J. o23  y* V5 ^( @( X  ?+ ?
24
# p& V+ T% `' D/ w0 g# u( E25' E! H- p3 T7 S1 g4 C5 A8 q, y2 Y
265 k8 _* h& Z* m$ w  l6 b# T
27
: l" y+ B+ b) ?+ P; T* l! H6 y28
2 j( Z! J; h3 Z8 \% e* }29% j& m! K; ~( U/ B
30
8 J) d4 d( G* L4 z6 Y31
( n5 d- o% R4 L! n8 v322 r4 t4 m. M, b' E% k$ E5 z' q
33
- z2 E4 e$ L: J4 W/ ]* B34" i% c% z8 i/ Y: d& S5 Z- X
35# T. W* x/ U8 S6 Y2 \: V1 P
36, s6 E/ h* M* T" z/ w$ s
37! h) {- Y1 T; \! O) A3 L$ O
38
8 M4 _9 f0 b+ X! [5 m39. H- f+ H) h- ^! F( Z- n
40
! j' q1 y0 U3 Q* _  w41
; h2 \+ b- w3 J% M42
/ R5 `9 t) ]8 m2 S/ P- e  y433 c8 T/ b3 e. l3 s: `( d
44
, P' N" d/ J. g/ X* r45
" u! o5 [$ f/ d, s3 M8 n46
/ h; |' y/ b6 n3 w) i) J47
* F7 {9 p. n, D/ A/ U- a. Y# s/ t* w48
4 B( u7 y8 ]( s- B49
  o" S  |% G- f& ~. p5 r50
# ~: Y" M& t2 `6 ]4 F8 U51: U; W; u1 x- Z- l" c+ U
非递归实现8 ~3 f( V. _3 P0 U# D! W
​ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。- ?) i. G- @% T! U) A  U- V2 l5 H

8 k) ]# e: W+ }1 [* ~% g3 D+ p# f' P4 s0 [# B& q. u. Y
: R; y( j! O6 ~) j
​ 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
9 F+ p) {9 ?( o5 @. T! e% |
" N! z4 P7 I( r& O6 r* y0 I& R​ 还要注意区间的取值,每个区间就是一组,就有gap个元素。0 x' M; v( d2 ^+ a5 S) q
0 s  u  \; }' m- z! x/ Q# f$ G8 ^
​ 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
; c$ r; l& M1 A% d- F) O" P9 O/ i( U
代码实现
) ~4 P+ ?1 C) ?/ ]( V& |) j( K, |7 I( v0 a/ _
void MergeSortNonR(int* arr, int sz)7 V9 n5 R' O/ t( X9 p' V
{
2 ]6 P: }( {% D4 {5 [    assert(arr);# L  m- u+ R, f) }/ F& l

4 f. p( X) @3 }, N9 Y    int* tmp = (int*)malloc(sz * sizeof(int));
; A! K4 Q$ C* e' }& S1 h$ \    if (tmp == NULL)
) H' L5 g2 y6 L9 O# M7 Y8 N2 G    {+ i, i9 }! B  N9 `5 |
        perror("malloc fail");
+ J3 B( a7 s6 |        return;
2 D, x' b7 b- _    }
8 A" g* `4 c* y' z; x; }0 I& Y. G; G
  u+ R# _4 _$ r! K$ l+ a6 ^    int gap = 1;
4 s" S* S$ y4 A$ J$ c9 P- ~    while (gap < sz). t5 N  y* w" }  y3 k4 i
    {8 x+ k* T0 h% g
        for (int i = 0; i < sz; i += 2 * gap)
' P# t& M2 M; E# D3 [  {$ |* f        {+ a# p" k- S. C& F! V2 }
            int begin1 = i, end1 = begin1 + gap - 1;
2 z5 v+ C- p1 \6 N+ e" R5 e            int begin2 = end1 + 1, end2 = begin2 + gap - 1;- s; s5 G) T. K) E; `, C
            int j = begin1;
3 D5 p1 }* z) i# u' o8 [1 |
0 P7 R; U4 d, c6 F  x            //归并
$ H' P" e. V$ Y            while (begin1 <= end1 && begin2 <= end2)& t3 L$ M2 F, U9 V; o) p$ g; U) Z
            {- Z% y) t0 p# o+ g6 ^/ y; q2 F0 ?9 f0 {
                if (arr[begin1] < arr[begin2])2 b9 j6 d( X- t
                    tmp[j++] = arr[begin1++];4 L. g9 _* Q8 @! I0 C* K
                else     - b" p" }5 h, h& s4 y% x5 K
                    tmp[j++] = arr[begin2++];: N5 Q( B; Q( S: V8 [! ~5 l
            }+ }. @4 u# S4 c2 a
& S. ~4 i5 C$ S2 Q; ^
            while (begin1 <= end1)" F! {: F' v# M$ c/ n  R6 i* b
                tmp[j++] = arr[begin1++];
! o) P  \& c% A; w( ~            while (begin2 <= end2), A+ W* D" Q& {' `
                tmp[j++] = arr[begin2++];( g3 c& X, J- ]1 F$ ~! [5 D- l

5 S2 w; u/ h; a            //拷贝回原数组——归并哪部分就拷贝哪部分回去
) u6 L( j% W* D3 B            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));! {7 T' Z/ l9 L( _
        }! j9 h1 j+ L. p# c+ o6 o1 p6 O9 C
        gap *= 2;
# ~1 Q/ A# }/ \4 C, ?    }" b9 B# x6 i( H
& [" T" G# r' D7 ]/ @
}
( O0 X- [+ O1 U: S+ `0 G5 k6 x8 ^
0 [3 ^8 h/ H# y8 X16 w) B! Y9 {) A) {0 @3 Z* d  ~
2
$ B9 P2 f# s8 S% n0 P3
3 Q6 n/ j% p. B! J% q4
9 W0 ^2 C8 |$ l  x4 `- N5
% u, Y; u- L2 i/ H2 r0 X6
" }# k; Q1 m2 I3 _7
* M+ e- E) T0 a7 |/ u8
0 j0 u# o2 l* S% s4 G! H  z9% L7 G# ~' Z7 f" B4 D
10
+ Q7 ]6 r# T" {( K* H" B* U4 @. y11& I/ Q3 r2 K7 l9 B
129 b" e- w% I" b5 a4 [' v9 D( N2 V
13" Y# k$ A$ z# \4 s0 g/ y+ C8 @: ~
14: \! h' ?3 E  k& u: b
15
) q. r, l: D7 O9 n16: g2 `) c2 j. |9 s2 v7 {: M
17
7 t' R- J" i0 S* R7 b18! w; s) F: f! t0 ]& g
19; J2 ?7 S# H, W" r1 T2 b
20
/ w  I; ]0 P$ p( Y: \21
: L9 s! N. c) G- \& \4 K9 q22! i( O% |$ _) f* J8 V" T
23
" p3 Z" q! Q2 o) w6 D5 o" Q24% [& x5 L: Z( h& C: s8 m3 ^
259 k1 e3 W% ]2 T6 V/ Y& t
26
/ w# A  _% c; o# N5 ~- }272 a- t( r  P6 }% h1 P( p
28" W2 U2 g' n3 N5 Y9 F9 B
29- X! h7 e+ `& n& Z
30# }, [7 `2 t2 _/ J1 }  @
31
+ ], e6 I* h2 v! F) N9 ]3 }  w32
) j7 b9 K0 a" A9 b33
) F, y! j  _* N; Y; J; r34
4 K. D2 Q3 @5 `/ k5 G35
! U, ~: O2 j% P36
' m7 e, P5 {$ A2 M  `37
4 f3 Q- a7 l# u; e9 r% [8 z1 r38
* m2 `) \! x4 M1 y6 V: r+ b! T39. Q1 P( }1 t3 H# ?
40
7 R- _% h+ S/ v. x) A41. S# f" {) e$ ?* h. f+ D1 x
边界问题4 }/ V8 k3 G  Y' z: |' j. B# [
​ 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。) I3 Q$ p! Y1 W8 i$ F: V( `& E" @

- c9 X9 ]3 y4 C# u9 T- w举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
3 k4 O* M! k& g1 W( l. `. [
3 Z* {5 [. K; I$ j0 E9 z3 m$ f3 i# m3 G! N/ ]" _, b# {# [9 W
7 r7 h- o- b/ J, n" S- c
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
# A# m3 I* O4 u) g. Q& n! _
. L% e/ X5 k0 |6 [! R: y第一组越界(即end1越界)
. i! y& Y: C% N$ o5 C
# ~6 `' Z: s9 `5 j* J: e, _应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。, _' G" C- J/ Q8 O8 r

' s! R5 A5 Z$ U  O, h第二组全部越界(即begin2和end2越界)
# t1 ~- J6 D! n, J) D) m: p& B8 K, \- ?; V
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。1 P* t7 \! g4 i( b/ @0 h
3 s0 \& r2 D. a" Q4 D  i
第二组部分越界(即end2越界)8 T- F" V8 v: y5 y! m
4 I" _7 c6 @1 t0 Q
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
* q- i! k$ P% {  j" p+ j& V
5 s4 w& \7 E" e/ k7 t​ 其实第一种情况和第二种情况可以合并为一种情况,原因:) o4 @! _( g6 `: w& ~7 [
3 V0 u: G& b8 {. a6 _+ [3 \2 B
​ end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。. Q9 m9 [0 R8 V0 L" j
' ?# S. _- b" [) a
​ 拿两个数组试一下:% B4 b, f9 ~* u( o1 r
1 P5 e8 p2 o! b+ n& V: S6 Z: f( ?
1 @  L& G: Q; J8 u

7 f: _9 N( b, J) |6 a) N( k! ]/ r1 p8 C& P& m3 Y: }1 y& V
3 n2 ?) g  `; r
代码实现
' u0 g) j# I% O$ H% D) a# i9 n* C9 O& U4 P& J) I1 p
void MergeSortNonR(int* arr, int sz)5 \# R  ]9 g$ y7 V) n
{# f* U! X( x: h7 T" \
    assert(arr);& H+ i2 K& a* M8 w
, H, F/ s% f0 Z: Y! D, ]1 A6 P
    int* tmp = (int*)malloc(sz * sizeof(int));% L+ U8 B1 g- v; X
    if (tmp == NULL)
8 Q/ O9 N3 g& L+ z0 _. }    {
" L0 d4 o; c5 h( U1 A        perror("malloc fail");
: T- G0 u% r$ e: V: S        return;, }! H3 E, @/ W" ]( S! T0 w2 H
    }
9 u+ X6 \0 m4 w/ \7 M9 d
* A, y1 A4 w& d8 M7 T    int gap = 1;4 ~! B( a# ?* e% a
    while (gap < sz)
% X, h7 o. I, D; y    {
" e, T/ k+ p( }0 Z4 n        for (int i = 0; i < sz; i += 2 * gap)7 N" Y6 C9 P0 B) \1 X2 L
        {- v. y5 k: ^4 H1 }. {- U/ }
            int begin1 = i, end1 = begin1 + gap - 1;
7 p" ]; c& `/ L5 @0 ^$ z% k6 U) {            int begin2 = end1 + 1, end2 = begin2 + gap - 1;3 `4 U& v1 N) K. B& ?, b1 n
            int j = begin1;
2 f7 \$ [: E+ D7 ^" v$ p, i                        //越界检测  R% `, `! |$ ^! N% C; I% ^
            if (begin2 >= sz && end2 >= sz)
$ B! k) |' z) R0 Z+ ^  G                break;; J% r' X' t! s" @7 H1 K9 R
            if (end2 >= sz)5 m2 i/ D+ ?1 q; h
                end2 = sz - 1;* L- `4 u# D/ b% g. E% D2 D6 [" B5 w5 B  c5 D
            //归并
0 E6 Q: G/ S; |2 {            while (begin1 <= end1 && begin2 <= end2)+ I% Z, o1 H# z+ N3 l8 X
            {/ R9 n. Y3 ~' d2 v& e, n
                if (arr[begin1] < arr[begin2])# J  z- S% H' m4 m( ]
                    tmp[j++] = arr[begin1++];" G, h) h8 m. V7 H
                else     
) d: z4 w9 D9 Y0 R* P) e                    tmp[j++] = arr[begin2++];0 U) e. n: c  f6 b
            }! p4 {7 L2 J4 t4 V5 r1 d- ?: M
2 u9 |& }1 S2 c7 M" W# l( Y$ G
            while (begin1 <= end1)0 M1 p! s6 l# @& q7 i8 v) s" }
                tmp[j++] = arr[begin1++];6 E' K3 [/ u4 R+ M' m3 r7 \
            while (begin2 <= end2)
2 ]3 v  J7 O. w! y, z0 N; j                tmp[j++] = arr[begin2++];
$ z  m7 v- S3 k- e: |
. \. s7 c6 d+ M' Y            //拷贝回原数组——归并哪部分就拷贝哪部分回去6 h% t+ e2 P4 h
            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
) F+ W: a! K% T5 c1 }% t4 C        }
+ P" A1 M# o; w5 V        gap *= 2;9 @1 m7 [) t- c, b* e) |  }. Y% K- g
    }8 V/ s8 g& A1 C# J, X. E4 X. i

) i  y5 {) k! z6 m# ]- e}
- ]# C9 o2 R! \0 S# p# k7 L5 `2 M0 J" B
1
" d$ S2 Q! A! o9 `6 X! o6 n" c4 z2% L/ s/ q* X4 Y! X1 p# h) \4 |. l
3
& y: y, Q  \5 y0 y, D$ p" C4
/ A4 _7 O1 v4 b$ W5# b' K0 n, `$ q" _* g2 x. ^6 ^
6) A8 I( G+ ^5 G) ]- S# Q; ^# U- _6 ^
7  o" H2 u( \9 u4 X
8( `9 K: y" s7 A# B" W
9
1 o6 G8 c# z" x# }10
6 ?- h% W4 x+ N4 l113 ?) F" a8 d' p  e/ K
12
9 _3 O1 e! g2 l/ T13
. o" v$ j3 [) T7 O' G0 y$ _142 p7 y4 S' H1 `: l
15; P+ p( u8 r, l
16
% m% n1 I! c5 b9 o3 [- [, X17
) f( Y- ]6 x0 f0 w' [. v+ u1 b% F18
) t' v( i9 z' k7 E& S19
- H& v$ [- v0 n0 J: |+ q20
# {- r3 y  ]! U- {! q: b" l. v217 \  _6 i" B% v* _1 [
228 R7 s$ B1 B" Z! |
23: D$ x, K& m& F- I% e, E) S0 X# P  O3 g
24' L$ \0 L) K1 V) p; W" t9 g
25
( T9 `3 J. t* M/ E# E6 |0 W9 F264 G# E& B; n- r7 R
27
0 o& s0 p& y% D4 k; `! [! B28
% W$ }# n  _- i29
5 B9 ~2 [- ]" K4 T# f30
2 G4 y  h/ y1 O2 {) E0 S31, i; E+ K" l6 ^! F2 m1 |# ^
32
# v) }7 k+ f; k5 f% ~% X33
' N1 O) V' }  ]: f! V* A344 J6 \" s0 M8 S' [% F5 U
35
% e! w; h5 Q* y9 H! g36
% m7 x* P3 k7 o- i37
) f' s' e8 T$ c+ h- w- X38
9 g/ X* o( U* Y  L5 [. s39
8 w1 K9 o1 ^0 q% Q40) c! B: C+ c1 P# J
413 f# c: V+ B0 l6 Z" @
42
: E" W0 R* T" \" H. T0 y437 ?, P: S5 o/ m3 z2 Y' r! P6 ]4 _
446 s( w( Y  c! g- g
451 e* |/ [6 b# u6 D
归并排序的特性总结:  y$ w$ t' e+ S+ v1 p( I

5 K' D5 N( j% A+ Y0 i. M  m5 `* m# c( ^归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。2 A. j. S. d; n: ]
时间复杂度:O(N*logN)1 M( v1 W5 T7 c
空间复杂度:O(N)  b% a3 @2 a5 c3 O) J0 N. [5 m
稳定性:稳定5 c# k9 v+ k- n

4 J, F* p; F# r$ n% n# t3 `" L————————————————, N; D  N: A% ^' B3 C( Q
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。' m3 ]# m' N' J3 ?3 s  Q( a
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657( i; h4 Y% L  v7 C" U/ ]; ?

# e8 N, M5 `3 p4 V# t: {% |  e# K% K3 a/ g2 l





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