数学建模社区-数学中国

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

作者: 杨利霞    时间: 2022-9-14 16:22
标题: 【基于C的排序算法】归并排序
【基于C的排序算法】归并排序
, ~, j: h7 Q5 H; {  \1 B8 R0 ?# M( s0 d, N
前言
. m2 {- c( H$ e本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。# v8 z% v4 Q  k/ r* e' n% }( p
" B* l) |% K- {' ?( \% R
归并排序$ B1 r6 ^2 j' V0 _& u  u5 F3 o
基本思想
9 B" O: @, n0 a4 w- u% P: j​ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。2 \% B. H3 x8 P- j' O+ K
' m7 p& p+ x( ^. B  G. A# R5 k4 R" J
  w4 z# `6 f# y

$ v0 ?2 W; H" Y1 _8 f" D: W​ 合并的思想其实和有道题目的思想如出一辙:
" }% q" i2 ^0 H) ^
9 Z: M/ w, I3 [& q; O6 c2 g" \: x4 ]! U: o: i

  k5 B8 A: s- L7 }- F* r0 h​ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。# O3 _/ v9 g& x: D

7 K. V2 q4 B6 ?7 Y- Z[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]2 r5 q% @3 f- V8 k
# |  \/ A: o, N; L  {: Y3 G
int* merge(int* nums1, int m, int* nums2, int n)- h* ]9 N/ d) q1 O
{8 u6 d" B0 O% w, ]- I- b4 [- ]9 }
        int* arr = (int*)malloc((m + n));
& n" D3 t) q) V' @. T0 m, b- Q    if(arr == NULL)+ I2 L, Q9 O+ L
    {  H* E& R3 B% @5 N5 Q
        perror("malloc fail");
. T  y9 v$ D: c& F0 R        return;
" @# b: ~+ ]! ^; Q    }2 X: q; M9 j, v) z# g# s% [
* q- l' o1 [- K$ k
    int p1 = 0;
% e! S) R3 ~9 \) j2 ^7 j    int p2 = 0;
" ?0 g% S* W7 v9 Z4 ~2 g    int cnt = 0;
" e  o. \: q( q4 {    while(p1 < m && p2 < n)+ ^& y& n$ w, e/ p( l
    {# {! X6 _. @; |5 I' |- C. s. A
        if(nums1[p1] < nums2[p2])1 l& P* v2 V/ s: R1 M
        {0 o& f2 y: r9 O# }" A
            arr[cnt++] = nums1[p1++];( ?  s* F+ r; o7 w/ D+ U
        }' F. }* d8 d- L' U  ]3 P. k3 C
        else7 W$ E7 f, m1 F2 b
        {
% o3 U2 y4 z) F$ Y0 h" W6 g) |            arr[cnt++] = nums2[p2++];) Z, E' [# V$ J3 K( t% |
        }
) o9 j; I  g! `  _7 o- D8 Q: A    }
% q" O, }* E0 M    while(p1 < m)9 h, g" v; [* g0 H/ A
        arr[cnt++] = nums1[p1++];1 t/ d7 e) j+ ?( {# M

3 E8 m% L( h; S3 x    while(p2 < n)
( Z' M8 e% P. Z, _; u# B        arr[cnt++] = nums2[p2++];% q% h7 H2 B* S3 G
9 l- S  X2 ^" p0 z& t; m2 b
    return arr;
3 E; K. N1 d* b0 L}
" r0 c' B& Q+ u" [; ~
" J/ k( G$ ~% z- N. H/ p+ x8 {1- h( p+ ~! R  D# D. x
2
5 z; b) n0 H: n5 p8 ^. T3
7 e: i! E! `8 R4
2 i2 C/ r6 s* ~1 n4 c) D) p5
. R, {' `/ j7 f0 L- Q" b6
7 ~  R/ ]2 F; y; K3 W6 P2 F  X7
6 l- [) w. m( p5 B8
' k8 M- c$ Q( x+ ~" _9" ]- {7 i: G; j
10
& B1 v- V( {9 a/ Q6 u) K11
5 h$ b4 L$ S/ n' H& A( J# V3 x6 M5 ?12
  V4 C) @% v- e7 C$ V# s' @13
; A: z' W; o* a14# n7 T5 X, H# o$ S0 R2 X
152 \3 M: G+ Y: ]& S3 H0 ?
16) ~3 c2 C! Q6 n; k9 n9 {: F- u
17. X" D9 b( L; ~* H( ], [
18. D( R+ F, E) G2 k
197 @* H: ^# h+ p, W9 a% |3 F
20$ g5 H$ f$ `# _3 g4 f
21
0 Y# M( b  j: I8 X22
0 {7 K/ Y; ^: C7 f23
& I# _$ m1 i4 l$ d4 ?" e. P24
% i. W6 ]& [0 {% A. E8 \5 \( G6 P25
# T# d* A1 Q# X5 z1 |26$ h, m$ Y5 y. Y* j' _6 B8 j  G
27) S3 Q5 G) A5 S* z/ u# K. f  u
28; @2 M; _5 O/ G
29& T, r: x  K# w, P; O7 s+ U" x( k& s
30
  _1 Q; w+ [; _+ v0 G& H311 ]  E) f$ }+ f
​ 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
' y/ q, O7 C9 {. s4 w- x% a
, i5 b5 Y& n# d$ q递归实现
2 V" _. b: I* T​ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
% A7 M1 _  T% h, @/ w1 J( E" y: t5 ^( R3 G* @' D  J) `) H
6 b( e* ]4 y# e8 L5 J
) T) H# D3 [# r. L4 t

% `1 ?7 o; r. d' _3 w0 G& \* ^3 V  q
void _MergeSort(int* arr, int* tmp, int left, int right)
$ S/ |+ z8 e/ o( ]) n; `. i; F; e2 P{1 g% x5 j/ d7 q# b6 m
    assert(arr);; }0 k$ D* t- ]( ?2 S5 l
7 _* p% K$ |: d0 W% @, ^# B
    if (left >= right)//递归结束条件不要漏了
/ W4 z* z$ i1 [: V( G8 g' N        return;; ]3 l" G( `$ b

/ I! u- u: S2 W( J6 |4 _1 {    int mid = (right - left) / 2 + left;9 l$ |- ~  E; n
0 _) ]/ Q: p% L6 @$ a
    //划分左右子区间[left, mid]和[mid + 1, right]4 a0 v  `# d5 E( ^9 h/ }
    _MergeSort(arr, tmp, left, mid);# ]4 X3 I# X; ^/ T
    _MergeSort(arr, tmp, mid + 1, right);
8 C5 S8 a. ^  Z6 U8 U
9 D* g' X4 Q0 g6 E( E    //归并
5 p) [+ Z" a/ b    int begin1 = left, end1 = mid;
' k$ l( f, W7 E" h, G/ X  ]    int begin2 = mid + 1, end2 = right;0 [3 l3 B) }% O& S& Y" ~7 y; J1 D/ B
    int i = left;) ]4 k0 G6 V" N, h; T$ l" R, T
    while (begin1 <= end1 && begin2 <= end2)
2 ]0 S. K2 f9 C2 k    {
/ U# {/ {! }! `, w( d' q: |( t- Z        if (arr[begin1] < arr[begin2])' r9 }4 S5 I+ Z- Y' f
            tmp[i++] = arr[begin1++];
) f" Y. v) k* [        else7 e! {: ~+ |5 q5 ^7 U
            tmp[i++] = arr[begin2++];$ B' |3 M, q" i8 h8 K" C5 z
    }
) O8 T0 Z: `. C+ P- ?+ d6 ?* X4 X7 l( W
    while (begin1 <= end1)
0 m2 s7 _2 k* {: M5 x( k        tmp[i++] = arr[begin1++];  G& ?1 Z' ~9 a- m) i7 B* u: Q# _6 B6 Z
    while (begin2 <= end2)
# A+ Q3 q1 E0 |3 T        tmp[i++] = arr[begin2++];; R% ^7 f: W0 i2 E5 ?
       
6 t" Z  a% {$ w1 m    //拷贝回原数组——归并哪部分就拷贝哪部分回去/ l% i& D8 {! i* s8 V4 C& P
    //而不是拷贝整个数组回去
, a5 r2 F  l! O! F* L7 [- R    memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
( s5 X% F3 j8 p* m2 S% Z& v: L}+ _9 _: ^1 g+ I  ?+ Y9 k
7 i5 r5 z4 g' O" w- i/ {
void MergeSort(int* arr, int left, int right)
( R" S% i7 ~3 o' j& _5 Q{
1 a, S1 V" d5 C# A# [- M    assert(arr);) Y5 Q9 w. e1 x5 f, o* q

5 h$ M% @% x8 f    int* tmp = (int*)malloc((right - left + 1) * sizeof(int));/ T6 Q$ w+ l4 @0 M$ N9 V
    if (tmp == NULL)  \5 R% G* D$ a" D& V
    {0 i% {* C; C/ u5 m
        perror("malloc fail");# Y$ p9 y( L5 L- P1 A
        return;
' o  k0 v# T1 B; Z/ `. e    }
; l- F, {) q! P: o& \/ t% ~) D4 D4 q) L" R/ m$ f
    _MergeSort(arr, tmp, left, right);6 H' ~4 J: h! M4 E' v. E9 X- L
+ x6 ?% q0 X( E9 O' G
    free(tmp);$ N3 k# Y; ]" m7 I- x
    tmp = NULL;. S$ ]8 n& ^: J4 q* i
}% [9 v5 G% V2 l8 g1 g9 Q

+ V% \4 g& t: d7 I+ N1
8 i- G* g8 g6 t  ^2& H8 H: A0 F+ N4 ^1 \* o
3
4 t4 _  F' |: q( T45 H1 H2 y, c9 H/ c/ ?
5
/ ^. R9 V0 |7 `, O8 j60 G  x$ x7 ?2 ?8 a' A
7
% G: G: |7 X# b81 X2 E1 a6 V1 |5 a" g8 L
9
; u, q! f! Z+ u4 g0 e0 c: Y4 c10
+ H, r- ^& H2 J/ r1 `3 ?' ?11
7 }! U4 y) q" F/ _: d12
- \9 k3 t5 P! o! m6 w13" p9 x9 k: C5 A! o+ P. T7 C9 _
14
) i0 O6 |: i: I% f/ @, X4 I/ l$ W15( P0 s- W0 I% ?% S0 E0 B7 @$ V
166 Y( m- n; U+ W& w/ ]) `
17
. Z1 m, ]: e0 p2 o" _: o0 p18
' b4 W1 ~, U  G0 N19
( x% J$ ^( r# U* @+ V20( F. u! P0 E3 F" m/ V
21
" M9 p1 E1 P2 {226 I* _. c5 K- `
23
$ v4 A0 R, P) Y9 Y) X' ?24
1 u- i; T) Y9 H! q! h25
) P6 Y- `4 O8 K* w' U1 f8 C7 N) b26" F- E( D$ X1 t; W
27/ B* q7 W* T4 Q# [! G5 B
285 e: u; s3 o. h9 U* O/ T
29
) H; r- X1 V* R% N8 I% h& |8 @0 F30( U6 b1 o% M* n$ `9 T) d; _
31
: s( E( K' z! i& w' D0 O32( ]) w7 m2 \: x, G: h1 p
33( o! S; }7 z: k% B' C
34# ]- i" C1 u8 I/ X4 f2 I( G) D+ O
35# d8 y( p9 ^8 }( ]5 b+ [- s9 ~
362 |! f* l. i. v2 O, g/ m) t
37" L, i3 F7 b. i
38! z( `- X" c- ?8 |5 M
390 S5 M3 [- k- I% t
40
/ z) P1 n. j: N& ^6 r: h) g" T: T41& O' }8 f0 ~3 {+ a& K
425 g$ t0 l3 b3 l
432 r- ]* r: ?6 S7 V" w4 k
44% X: b/ _0 y3 f9 b. x2 s
45
& Y' a2 F% N7 r" a- S2 C8 b466 V& w; A) c' G5 z4 ^1 G% I5 g
47* Y6 l" Z* K4 f  \2 {
484 d6 x" X( n) g6 f5 M) u  B
49: y& O2 K$ O% j% z( e( U( i
50- X! v* \& |  {$ B, Q( Q. d
51
! }$ `9 @* w) o  K; C非递归实现- q' M( ], n6 P4 [0 J' a3 E
​ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
! b. k  g3 F/ A8 X/ ~
: O! F3 b# n4 X) k6 X7 K
) ]( m5 {, |  H$ ^& u
) K. U. T" B& y9 n( S$ l​ 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。5 S  E. S$ b- W, ?( s8 ^
2 W8 I( K9 f3 q
​ 还要注意区间的取值,每个区间就是一组,就有gap个元素。
" h: _6 r% w: K( v; G# F2 @; D" U
3 v* k) X4 M8 a" @) ~9 |% p. U​ 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。- s2 F! q) G% K3 F1 k1 t* Q

- O- v! Y) x) H, n) X, b' Z# ]* n代码实现9 _! a5 h! Y2 }7 [( t: Z, L+ @) c+ C
. z8 u; L5 ]/ f& m+ r% G
void MergeSortNonR(int* arr, int sz)
, P" S" E; ^) Y5 h  [{  W+ V8 t/ Q( h  L+ q
    assert(arr);. }! [/ V4 U0 b3 m- l: R5 N

; Z4 ?) K% j* |    int* tmp = (int*)malloc(sz * sizeof(int));* O- T# l$ o- W  \3 T0 d3 C, k
    if (tmp == NULL)
) d8 a: a6 A- m1 e3 i! \/ ^    {
( f* s% F0 b' L7 D        perror("malloc fail");
( D) f* }5 |/ O        return;
7 t$ V5 o) W/ k/ ^/ c- ?) v    }
( T6 b4 |" q7 N1 H: ?% X' c4 s/ X# z! i7 @6 s  A6 X
    int gap = 1;
3 @6 g# y) z+ H6 Q    while (gap < sz)
5 O! y* H* i, B    {
  j& U- ]( v& s, l/ O; E        for (int i = 0; i < sz; i += 2 * gap)" |3 i9 `* U2 E7 D# A  c2 ]3 z& C
        {
+ ]" G0 Q5 F7 H& j; M            int begin1 = i, end1 = begin1 + gap - 1;
8 p" \8 r% N% P            int begin2 = end1 + 1, end2 = begin2 + gap - 1;
: d% l  w. Y3 _  ~, S' Q$ C- z            int j = begin1;
# l+ h( B( s) W( M" a6 _8 G2 A2 F
' t- ?- v9 n% V- U; F: }            //归并
8 i4 r! i: x9 h            while (begin1 <= end1 && begin2 <= end2)2 D% K) n$ \% Y2 }9 }$ b
            {" ~8 S0 h  H" q6 h, T/ }4 y, s
                if (arr[begin1] < arr[begin2])0 j3 C' M9 J6 H* b& R2 X+ d" L+ _
                    tmp[j++] = arr[begin1++];
* U% W0 J+ b  P1 M2 H+ ~; n4 P                else     
% |0 ?4 H3 @# T  ?0 x  q& p                    tmp[j++] = arr[begin2++];: ]" X  D$ u* e+ B3 S$ U
            }
& ?* {$ ^5 K# W4 c1 _: w6 D
0 g8 ~0 E7 N% f  Q/ A1 Q1 c4 R6 h            while (begin1 <= end1)- f: ^7 z5 L5 P3 I
                tmp[j++] = arr[begin1++];) B# S" d: t( }: \( P4 O; W2 S2 ^* \
            while (begin2 <= end2)
6 M6 H% f3 O: v0 j$ \& Q! Y0 g                tmp[j++] = arr[begin2++];( u  z( ?+ W+ G
  L$ a  u( G! Y+ i; {4 c
            //拷贝回原数组——归并哪部分就拷贝哪部分回去
7 `6 P# r8 ]. A7 G1 s: [            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));4 ?3 @5 k' \% k  h* c  Z; r
        }
% f# g& [" L' c' l$ V1 _' B7 @+ n        gap *= 2;
) T. S( l( v/ ?; {" h    }) k, s0 U/ F/ C' a# g9 J, ^

$ _3 `" x' B9 }& w- p7 Q}
: g. Q% ^7 w+ @* P
1 N7 w) @8 Y' U  `1 r1 e0 W! e1& v& w; ?6 Y! t* k* a' H7 `
2
1 Z" X8 v9 k! V$ W$ B2 h# L; }7 @  u' |3
; o9 W* {* c# I! W: w5 i0 Q- p4
' e& B) n2 f+ F. ^& B8 @3 C: q51 j& U% F* D" T$ f8 j# A* K2 r
6
; R4 I. L( R- w# c; T7
8 W$ E1 K; C/ M87 B+ r. P# f& q! e7 ~$ e
94 y+ N) U0 e4 m+ _
107 D, o& d% v  l' p0 ^8 s# D
11
- r$ y4 x1 t" F! w9 L12
9 J9 b/ {$ i# R5 h13* H5 W: Y  q5 \6 I3 `$ p
14
$ ~  a5 j  j2 n; o5 l) W15
. t, H# P$ f0 g3 `' f16
  t1 L. {/ ?" S: W( V3 Y17
- q4 }6 W9 Z. b& I0 @, \18
6 z/ z3 \* q  t$ O196 k: D  t5 l! K! J# E8 a( e
20' v6 `( }- `" d6 F. O; n
21
( [' |8 L! I9 f  U" \; T22
$ E0 C9 o4 Z- a5 p3 z/ u- i0 R23
) U, C8 I. A5 Z  i: b24
9 S& b- C* R% D% E& s0 e0 Q5 m0 f25
1 a, ?( J/ R* H6 {4 e, ]8 X9 j26
5 j4 z" W  O9 u4 ~+ S& G3 z& X27
; H4 ?/ b6 H( q/ v4 E28
% L% o( W# L4 H' l: T+ {29
+ T" {- E/ `. d+ x; W1 i+ }# ~308 e$ B6 n! c0 v1 @7 {5 b& R! q; g
31
  Q! i8 I. Y9 y5 y32
" y7 l/ X; b" P2 W+ V# N2 v4 c331 y! p) r3 i2 B  T
34
6 }4 Z+ @- {7 I3 T35) Z& ?- [3 u8 w1 x4 F# n) s5 _  n$ g
361 G1 p8 b; N, [
379 w( @4 O, @" j( Z; o
38
4 L7 n7 ^2 m* @39
# w5 W. M7 o7 f2 P6 u40: H0 g# C; _+ y, O' I& V
41- [! k8 R! z  z& s
边界问题: m7 C3 t  {5 }. T( S- E
​ 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。+ V7 g' o3 v( U) e- ~

7 d! Z$ P+ x; p/ z举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
2 C4 t& |' T* R! O2 @$ g# K1 S4 D' g$ V: a% C, d2 T6 v

7 {2 b  P& c* |( a( q& S
6 L5 q: B- h! K3 y0 k由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)8 @) M: ~! ~  Q; W% g: t
: I$ o4 X& R$ d7 F# q
第一组越界(即end1越界)
$ {+ Z: n9 E7 x7 l/ u) K/ [) M2 b1 ^2 r( J
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。% l4 S/ J& \* Z
8 F5 J3 \+ v8 j+ {. i0 C  k
第二组全部越界(即begin2和end2越界)
  z9 g  m7 S) ~' B7 i: u; B2 U: V
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。  [- s; X$ m6 z/ }: z
4 j: h& i5 p1 K
第二组部分越界(即end2越界)9 K. c  o# N6 m9 m# P* E
2 h9 _6 _: k# o! n; j
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。; l- k, [9 w2 p4 ?  O4 M* O& n' z

8 k, a$ q+ f6 h6 o+ f5 G( l# a* j​ 其实第一种情况和第二种情况可以合并为一种情况,原因:  }. g' h9 n/ d2 Q" M3 W( ^

+ j4 e2 v1 A* |5 p6 D​ end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
+ _* a1 b$ B# k# y; |! K" o1 P2 z8 B7 r# Z  r
​ 拿两个数组试一下:
# }! y# v! U+ \" x. W9 s) m; ?) [! e5 G, q1 P; X0 \
  x. h5 Z1 @4 r) }

3 W1 M; x4 [3 {4 W( ~  Y; j4 O: U" J

# H# q0 G6 q: v- C% ^% h5 x+ ~$ m代码实现8 x+ W+ ~6 {1 N& y

- _$ n  |9 p* U6 r) |5 k5 \% C8 Xvoid MergeSortNonR(int* arr, int sz); g9 s& P$ F0 ?
{
- }9 Y  w: k, l2 \$ y0 ?    assert(arr);
. h7 u( p/ |. W3 i2 @: Z2 P, W. Z2 H, X( l  H2 ^2 y
    int* tmp = (int*)malloc(sz * sizeof(int));. N5 T" Q3 H8 _3 Q3 v5 d! ~
    if (tmp == NULL)
9 e: d$ [" W, M4 J3 H8 V% t. i    {
2 \7 c! c3 y( y2 b  Q        perror("malloc fail");0 ~. B/ H0 [! k: ~8 v% r
        return;! Q6 ^$ ]& Y1 U; L" q9 V9 h' \
    }  b0 r# {, q& W0 C7 C. r0 h
5 R  q' ?0 y& W* n3 o! E
    int gap = 1;& {, i; d: Y1 \& r% ?. G2 k# u+ F6 i- [
    while (gap < sz)7 b& ^% J: ~+ y& ~& D
    {
/ L- j& x* l5 M$ }* ?" X8 S; x        for (int i = 0; i < sz; i += 2 * gap)
* i+ e2 s8 D& @8 t2 s& S7 l        {# j7 P8 b' Q  h5 M" O( T
            int begin1 = i, end1 = begin1 + gap - 1;: y  G2 L9 I, \# B! y8 q( t+ R8 l
            int begin2 = end1 + 1, end2 = begin2 + gap - 1;
% d/ Z/ C0 l- [+ l, q7 X            int j = begin1;
# [' U9 ]$ _0 ?8 G                        //越界检测
# A; j' H" v8 W9 f; j- e1 Q' q            if (begin2 >= sz && end2 >= sz)
" `/ V: x, o* \, E3 y                break;
0 Y+ I5 y0 c) X  X: _  t            if (end2 >= sz)1 P, b% Q1 w" e7 f
                end2 = sz - 1;
7 L+ t2 I7 [8 n6 @            //归并' u* B, n- U: d0 _3 d: N
            while (begin1 <= end1 && begin2 <= end2)
2 v7 a% L8 P" u* l- U            {( _; e0 |+ d" r; `& |
                if (arr[begin1] < arr[begin2])
$ ?4 o7 _  o4 Z$ `- M$ z& h) I' v                    tmp[j++] = arr[begin1++];1 N1 G6 i/ H( N+ h; {3 y
                else     & ^) \8 W! L# b/ a. G8 K$ ]; J3 ?
                    tmp[j++] = arr[begin2++];
4 s, d" N7 [. q  L6 h8 [            }' j$ d" e9 W- Z4 g7 {
6 Z9 g( n% m* x2 Z2 y  k6 C
            while (begin1 <= end1)
1 D7 G, \, A& \- E+ _                tmp[j++] = arr[begin1++];
* p1 }& \$ e6 H) m5 a- |0 W            while (begin2 <= end2)
8 y. ~: g" J5 x- s2 j                tmp[j++] = arr[begin2++];
8 r2 O, r* \& J+ K- L! j1 y5 _0 ?1 a, F: f/ R
            //拷贝回原数组——归并哪部分就拷贝哪部分回去
5 `6 B0 Y% M$ B' b7 b9 i) c; Y; `            memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
6 m' b! x& |+ G9 \# \: z        }/ ]$ y5 h+ h" }' @- q! L
        gap *= 2;. x. T0 c& @7 `, k' J4 W
    }+ _. @+ C9 j) g! \1 o5 j

% ?9 f1 H  o0 Y' Y# W8 i}
' J/ r) T) Z" X6 o/ [# S/ e9 \& L
1  ~' e3 C& c( p! i( m2 R
25 \4 u2 J1 {, M7 J$ P) T" C
3
# K' X! [: r* G/ s7 {! \* k1 z. Q48 `4 T  c6 G. L3 B7 ^, ~! h" E
5! U/ x! S7 r! Y9 R6 H* l, q* w
6
7 |) f! c1 y0 K4 [2 ~7 ^( z7
5 k3 i  J8 A9 r- I80 J; r8 t4 j5 O# I9 n
9
- ]6 N2 x8 t" w0 X0 a108 q! e# e8 P) u5 h5 c1 @
11% O7 W* j1 O8 A& d9 y$ p% z8 W. |
12
+ h$ _# t" q2 t. p13
9 E6 |# H. s: u2 `, {6 Q, V14& H3 h; [9 M- Q. g
15" P" @- b, g7 N9 z) z3 Q! e4 b
16
9 R, ]; T3 _& v, o8 A178 V8 R' w9 F% h) a- `; ?
18
3 z0 R& q9 v# {19& K% z5 I8 b$ ?, F  t0 l- ^/ V
203 h3 r# b8 k; i9 E
21* i0 z4 w7 P7 t0 y
22) C' k8 R9 T( w0 T' P- \: M
23
. \9 g7 k2 `' e' i/ }1 E  h$ F24( ~. _1 k: p' B% f1 ]4 }
25
  S* j/ @% `3 H- h6 z" X" S  k26
! [: N; |" s  }) _! X5 b: k278 P& D+ z( K( b: a/ n) [
28
- M* Y) ~' w- e) T29
0 h- {, x- G7 z309 L8 f) m0 l* Y2 q: s
31* G( y( ]2 P: {2 n  q. _0 x" X
32
/ I, D1 o, D1 r/ f+ W; s33
3 Z3 u7 `% u+ |0 N+ Y- h34
' Q- H" H! i9 V8 s$ Q2 [0 u35- ?* j* h0 C3 v7 H
36
/ n( _$ _6 n9 [# O# a2 {37
7 D' |) ^2 y$ B. h- z) Q38- q0 k, y, }+ f. F
39
" D6 t. o% j+ v* N2 \- t9 O40
3 `, ~" v& K' c( X  i41$ E# ^1 K( H1 U! P  q
42( e% k1 c2 C: a. q: x
43$ w+ I- r* @8 F7 E6 n7 m
44
0 K9 X& g* t; ~2 Z: q6 M5 ^452 I& {7 G) N0 u
归并排序的特性总结:/ T9 W: ~+ D5 w5 [1 B
% }* F% @0 q/ F1 \
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
  Q3 Z( Z+ s. _时间复杂度:O(N*logN)
' Z9 p& \  Y) Q& k( K: s2 h空间复杂度:O(N)- \, Q& v; b; A  Q9 l
稳定性:稳定
; `# D8 @. j7 i/ A6 Q% B
9 {! h, D. C* }9 x2 q! I0 b, O6 p————————————————! Y2 ]7 o8 @* s$ v
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
. ]# @" J; D+ U! ]原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
2 `) R3 q. f' _; o
* b( v1 }9 L5 [- B/ t, f0 ]( I) l4 l





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