在线时间 1630 小时 最后登录 2024-1-29 注册时间 2017-5-16 听众数 82 收听数 1 能力 120 分 体力 563241 点 威望 12 点 阅读权限 255 积分 174195 相册 1 日志 0 记录 0 帖子 5313 主题 5273 精华 3 分享 0 好友 163
TA的每日心情 开心 2021-8-11 17:59
签到天数: 17 天
[LV.4]偶尔看看III
网络挑战赛参赛者
网络挑战赛参赛者
自我介绍 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
群组 : 2018美赛大象算法课程
群组 : 2018美赛护航培训课程
群组 : 2019年 数学中国站长建
群组 : 2019年数据分析师课程
群组 : 2018年大象老师国赛优
【基于C的排序算法】归并排序 ) n% i; u2 z' n9 _, f; }
9 A% g. U$ Z# r7 L
前言! `! d; c b( t% J7 \3 G
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。; @" ?) @ U4 k
, b6 o! R H/ K. p; t 归并排序
; R, `" z: k1 e. f/ S2 P9 ~8 ^ 基本思想, s- o4 \ G' o- \" T
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
2 f- T; d0 d/ g9 Q G4 r
: d% a: J B% B9 u4 d5 h0 } , t" G$ P1 z8 W! C0 o; M
0 W5 h% o8 X2 z) D/ s3 x9 J 合并的思想其实和有道题目的思想如出一辙:
, P1 R) t8 x) j& v2 {
: O8 U% J. F' p! X: M4 C
0 a7 F/ z) @4 U0 g, h! B2 H ' }" k! U) z! `' K. X. ^+ M
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
/ b! ~1 h1 G7 b1 j2 f% D" ~2 r+ c* Y # w3 j1 G, o. U, z8 _; s
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]( U9 Y2 r, r) R A
: n$ t4 E7 W, t. s8 p" a, P% m+ Q int* merge(int* nums1, int m, int* nums2, int n)
5 j+ Z e' K; A) ]5 ]4 N {9 j5 _. `, d$ m( g! b7 B+ i
int* arr = (int*)malloc((m + n));$ N2 \) f# l" {
if(arr == NULL)
" I- H: g/ Q" c9 X {) Z H# E0 {7 {9 b2 H, u; O$ h
perror("malloc fail");
) O. D9 }& r1 u3 o P return;; ~* ?; ^: ^$ p
}$ m0 \$ \- B0 q- z0 L H8 ^
6 p! h$ p7 i6 V p' U
int p1 = 0;
$ D+ a* e& I% m( r' \6 o! l int p2 = 0;5 m! M" C2 m$ Q2 p
int cnt = 0;
4 N( Q7 M- h, ^! ?5 n- H% T while(p1 < m && p2 < n)
3 g7 M, g' \1 Q3 b( n {& W# q6 N1 A# W/ i# V# P
if(nums1[p1] < nums2[p2])
/ c+ ^0 l0 w ]8 l; |3 |/ }# I {* s& L7 w2 M* K% q- k; {
arr[cnt++] = nums1[p1++];0 T/ Q6 \( s- N
}6 _6 Q( @5 P, X' l# R, g- V& I
else
( ^5 a: X' |, x y3 G: m {
+ h' d* j6 ?& j0 Q2 s+ f" e arr[cnt++] = nums2[p2++];# k% y* }! X6 O
}6 j% \0 {" q3 I- X
}3 l* t; X+ K4 p) Z0 H4 z' _+ }7 F7 x
while(p1 < m)5 O' V- y" w. H
arr[cnt++] = nums1[p1++];& f( o. v8 a2 w {1 T0 k! O
# j2 y" V7 P8 C. x; v, S4 Q0 Q while(p2 < n)9 H3 m3 _' |$ V$ i) R" b
arr[cnt++] = nums2[p2++];
+ O3 `! ?$ s O! P
# j3 g( t% w( n; A+ j return arr;
# i1 _* p5 T" k }
: a/ |4 R3 o( p8 M: `, o! V
% ?' v* f5 q5 A# y 1
' l6 l1 a8 ~" G3 n y; z 23 T1 g& y2 y [& q4 d9 \* T* p1 {
3
. F9 z# P# n- q9 G9 x( I: R0 X- w 4, I0 v5 C0 q! d, j9 u' E. l
52 ~0 n4 w2 L/ {
6: t4 {8 A* R5 x& u4 @6 r2 {. U% H
7
( Y! |: U+ @6 O5 a& l+ ] 8
x }! P+ i/ l% \ ^# j5 o& A8 V 9
2 |5 k3 D. B! ~, K9 l+ p1 X+ V 10
5 b9 L, R3 R( A- w) b 114 }; p+ [. g0 M0 Q* }
12( Q- W- F3 i9 c
134 v1 W6 v5 h4 o! g L+ A; E
14
' J4 I) G8 w; c% U+ o2 K' Q+ L 15
% G1 u) l' S1 b9 i7 q' `0 ] 16$ ~* ]+ `# e4 ~: h) I# M% w9 q
17
- x& ?2 l1 W8 G3 h% J, c 18
( d* \# j: t: w+ Z4 f9 ], V* t 19; y, y: t0 o( t1 z# u w
20
5 k0 Y" Z, L k8 O 21
9 A8 A" ]4 I0 C' n* u, X2 a! s8 k 22
' D) Q3 U- f2 x! z4 A2 h! |/ l 23, {; U, I; h" e& M% c- d; k' ?
24, q, Q& F+ m& L4 W2 e/ `
25
1 ~9 W$ m# D% I 26
. r, }- ^; l w 27
0 i# Q5 l# ]/ g) M! D9 [/ I/ j 28
+ c- c, |- l' Y8 y3 x 29
4 }" V# C4 \- E+ _6 x 30* j" ^; C/ r% S% {$ B N
31
5 I {+ m' h. y o0 W. a 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
3 }- ?( }9 s4 \$ a, g y
6 {4 R* Z2 O1 U1 ^( N9 O, |4 | 递归实现
/ z9 T" z$ \% ^+ S+ a 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
4 n% W" N. |8 E" {* A1 A. N ) X* ^1 L# ^. T! d, @: L
# M/ b3 ]: a0 u8 _& J1 O, N, R' D% \
$ g, Z% y1 l1 a2 W% G9 z; S
7 Z! j7 O4 r# n
/ n: V/ h( g' p. `+ {$ E8 b1 i void _MergeSort(int* arr, int* tmp, int left, int right)
; Q0 M$ R( R8 Z5 Y9 M {
4 B4 G1 {9 g: ]0 S, x+ i! U assert(arr);
) |6 {5 H& ^: L) B; ~- F2 i 8 V* h4 ?. C7 b7 ?$ b
if (left >= right)//递归结束条件不要漏了
! T2 ^# {! K4 `$ t return;- V5 h( c4 G) n2 A( w
Z8 W8 E w$ x7 E! X int mid = (right - left) / 2 + left;8 L; s: \+ F. Z# B
+ E6 {1 ]. o* d //划分左右子区间[left, mid]和[mid + 1, right]! b* u9 `3 w' ~# t% G$ n
_MergeSort(arr, tmp, left, mid);
& {+ w+ R: E/ ^1 L5 [ _MergeSort(arr, tmp, mid + 1, right);8 w/ m5 o$ h# h; E
; H1 \& {; c* A$ ]8 y6 F
//归并
0 e( D }# e( @6 s0 Q1 \& v int begin1 = left, end1 = mid;
' ]* b1 U% M, D( E int begin2 = mid + 1, end2 = right;
2 k% _4 {7 d8 y: I int i = left;
' Q7 S# Q. [ o% C while (begin1 <= end1 && begin2 <= end2)
# r7 [: g+ @% D' s {9 Y7 M! l/ u; n" B+ s1 M5 i
if (arr[begin1] < arr[begin2])' i+ w% e8 G! [ P: K
tmp[i++] = arr[begin1++];
. o6 _3 S" E( Z$ ^5 e1 S else% {6 {3 ~ a4 m; C; k
tmp[i++] = arr[begin2++];
6 b r) y: U v: E& j: R4 z }0 ]* i! l2 V% s) T# L
4 [3 x5 _" D9 a, {4 L
while (begin1 <= end1)$ P7 F+ r ]+ I& D y
tmp[i++] = arr[begin1++];
7 F; u8 z2 Y* M4 C6 e1 ^ while (begin2 <= end2)
% V8 {* _- Q' M$ R( k tmp[i++] = arr[begin2++];' A, W" a# V' Y* {
% W; M% r, U7 q0 t3 _) Q
//拷贝回原数组——归并哪部分就拷贝哪部分回去
) a$ \& h( ^4 H5 b( W; a //而不是拷贝整个数组回去3 ?% i5 F1 ?# T# X
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
$ N5 _2 Q5 Z& q' c( r- U0 j }
4 l6 p: A( e3 A4 k+ ^2 A! Y; p
& U: L; y+ X, _) S! T+ p1 z$ p( \ void MergeSort(int* arr, int left, int right)8 A4 c/ v& J) u5 r ~
{ X ?- F. \1 G: h
assert(arr);
7 `* ?& ?" s$ \9 |4 a- Z2 G + A% k) ~0 A& p4 S. `
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
' m0 \1 h; N) d8 o% d. M2 w, n, t+ z if (tmp == NULL)$ z4 `, L- Z( q% c
{
$ N, q: l% k' E% H P3 \ perror("malloc fail"); ]# v5 @3 ~! d9 T4 J X* t
return;& s, P! G. }1 `. B2 X( O5 l
}
$ R% t: t) B4 ], Y+ T8 ]+ I
1 L2 ? b. @2 o7 _ _MergeSort(arr, tmp, left, right);. u! Q f6 z+ Q! j6 {7 x! R
) S( x3 L. e, C" N4 P; g/ H0 A
free(tmp);
: g: B1 u. o$ v2 V1 m; w. F% l6 w' P5 p tmp = NULL;
: c6 _; A2 |1 R# B, }% I }
$ t; v( F2 I! { ( G6 ?5 `) h* @ x9 ]* i$ h
1
4 [ S9 s% Y1 S/ _" i: {2 e: M+ [ 2* t" z l% a# p- R
3( @ [% R1 C$ _9 G0 u$ K) |) s
4+ J( J. `3 b# H1 L( D: C
5
* c1 m0 m3 D9 a; f9 _0 T, Z8 | 63 c8 A6 o) e! d
7
' h% Q( w& `2 K- i3 [. y I7 p 8! U' O* W8 e& ]6 z1 v
9
' d- G. g$ S0 ~* H* { 10
2 c& v. @3 L e 11
# D* a! m) n2 \: I: Y, O8 v! G 12; z$ x- N& p8 D& D: E7 P5 |8 v
131 h) S2 @* Q% J
14
2 |, b, N2 B9 z, v& e 15
% ]0 Z$ F: H6 e% e Z& L6 M: F 16
4 x6 Y7 [0 `- u4 \/ ]: |1 r/ a 17+ R( X9 v) B1 ~, n. f. |
18
1 c Y% _( H/ G5 U3 p( d3 N! H 197 G7 ~7 C$ K, C4 Q
20
# Y* t1 g7 M: s f# g# v' j8 Z% k 21( }! @+ T9 [' Z6 i- {; Y1 Z
221 {' P2 o5 L& ~! H. p0 B
23
^$ _2 \0 V& {# }8 E1 O6 K 24
9 s6 A) Y& g5 |8 ?9 _$ F3 F 25 F3 s& |7 w" G/ x: {/ I' [
26
) b7 b* h/ r5 y, | 277 S- ^0 [6 J& l \4 N
283 O+ f$ m2 s1 A9 j+ m: @
29
3 ?/ n" \" S; l1 x 30
, {. J& v! |4 b0 I. q$ a6 t 31" J. j2 H2 U7 {
32
6 m; K% E6 ]/ v1 }9 o 332 D$ i7 o. ^, N {
34
7 C5 E! P6 K) C( C 358 g3 n {& s& y6 B
369 X* t$ H+ ?$ D" D
375 ?1 F) i- E0 T0 U# x: M
38! E0 ~+ I y4 }0 e
39
5 Q+ |# l2 ~+ R, S9 d y 40
7 ?2 a+ l2 d" r$ f8 O; F3 k) g# m 41
3 f( t `8 E; Y( m& c8 o 42 g5 ^2 m, B* z+ b! ?
43
) l! h4 F$ I8 |. ^, _* | 44
; ], P8 W. d* @5 q$ Y 45 z7 w) O9 w0 f& y, U8 I, O8 B
46
, l' ?) s6 P* ~# ~' {1 p7 B; x$ i, O 475 v2 g: [: n, B& H; V- d
48+ x6 ?' a5 t/ g+ B: J1 A2 ~% T
499 J; j0 s- Y' Q L* S5 Z
50
4 P" M1 ]; Y0 d# G5 q3 E 51" D' w2 I. Y9 s' o. s N
非递归实现3 Q2 @! N, _; g9 w) Q
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
5 G; v8 L/ G" [7 g) Q2 n
5 ]; j9 o2 u% o' g1 X0 z4 a1 c
9 ^4 o2 e+ }# d7 u( D
% N' l' ]. }% a; ~* g: p* A 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
8 X$ N# S9 x: ?$ \4 X Y" h
% p8 _2 q* v$ O [ 还要注意区间的取值,每个区间就是一组,就有gap个元素。
$ K! H: g1 j7 E/ D3 H
) }) H7 a0 C% J9 @' u 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
! ~- o/ y' Q; y4 Y) e; Z6 n V ; H' G+ u% y; d4 I2 n- i
代码实现! S& N6 S I; |0 ]9 X
8 B* ]+ o8 c. B9 v1 ?' z1 w
void MergeSortNonR(int* arr, int sz)
: l d% m) I+ s2 s; \0 b% K {8 n3 u. B) B; u% f9 `9 ~" w; P
assert(arr);
, u$ y! m- W+ H1 A& g . Z1 N3 m+ I2 `& Q
int* tmp = (int*)malloc(sz * sizeof(int));
, ]4 J+ U) t! B' E) S D) R if (tmp == NULL)
7 T8 `; d; @5 W' x& L1 b {3 }! D! V) S+ P( ?! j
perror("malloc fail");
2 b$ |: ^/ `' O9 S6 }+ _& w4 @ return;
' t$ h+ G. y$ U" g! y3 T }' n! b! Y" D' \5 M3 H4 z2 F' \ V
2 p# t! k: ]% |7 x- A5 |. E8 k" I int gap = 1;
4 a7 y3 }/ v: [5 @" F: p- h while (gap < sz)9 `; R6 F- o) j2 G& q' x) O
{
& w8 p& s% j! W g for (int i = 0; i < sz; i += 2 * gap)7 y! X- f! g, y8 q0 {6 p( H0 ^
{ x1 `$ p# j* V W
int begin1 = i, end1 = begin1 + gap - 1;' c$ j1 M( m5 D4 q
int begin2 = end1 + 1, end2 = begin2 + gap - 1;5 v8 o/ M. u1 [& ]# G
int j = begin1;
7 f. p8 Q) z- s
+ U, C8 L7 E# D+ I" _! C# j M //归并
; Y+ Y& t( n: f" ?8 M" t while (begin1 <= end1 && begin2 <= end2)
& S- |# p6 \8 `$ D5 V {
( m$ D& f2 U; A; b if (arr[begin1] < arr[begin2])
! O, a+ ~9 H0 u. E+ O tmp[j++] = arr[begin1++];% o9 W) ?1 v+ k
else
: y9 Q% Y+ E* L+ a; _) Y m tmp[j++] = arr[begin2++];
: _* L) k: M( p- k/ s }
. P9 l$ G- ~* X# I5 H+ A- ^ " d( z% s# T' g& S
while (begin1 <= end1)
2 q1 o3 K3 f; [/ l7 @6 r1 b! R tmp[j++] = arr[begin1++];9 t( e0 x9 v' `; x1 R8 L
while (begin2 <= end2) ^. {+ D. s4 q1 k) D
tmp[j++] = arr[begin2++];
) M$ S0 ]& r9 Q1 z0 h) W8 D
" q C7 ]; t0 Y5 X/ V //拷贝回原数组——归并哪部分就拷贝哪部分回去8 _+ M* n8 r& Q5 [
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));2 [) n, s6 }8 h4 E0 L* `2 }7 A
}( ?7 S0 c. U+ Z: R4 s
gap *= 2;, d7 [4 ~% Q% @* I% o
}
# S/ k1 {* h1 E3 E& o& F
' j$ Y+ l! o. n3 a7 n6 Z5 I3 f }( y7 A. ]9 O$ R) m+ J
' r1 j2 u3 ]; N 1
& g: L) L( U: z2 B, P, q0 N* h 2
4 t; _; y" q- M; j4 f9 R2 E 3% ~7 r: Y; a8 F' J* l5 w8 Q
44 U8 u6 w8 u( K
54 T2 ~$ u$ L6 t1 z' }
6( k& D% R8 I* y7 }' l- }
70 M9 j& u/ ]! s4 C
8: u& [3 L6 j8 E! A6 A& b4 ?: T( N
97 P) f& O$ `7 u: X+ i9 r/ D
10
- u S& b4 G9 _: e0 d 11
* M$ a: E( u" X. n 12
( b3 x/ K$ e. r/ N& S 13
/ t0 {2 x: s, j8 ~; P 14
' E% W( ^4 H' ?3 K/ Z 15, ?" I2 D, b7 K1 k
16* Y* X$ I. J" M( h8 R* W
17" U4 G8 P8 q! ^' _# D8 R
18
9 u! R- e. V, x* L" e5 W& v* W& H: | 191 {8 a9 Q1 Q! r" @" V+ g: e
20
& B: V! |/ S/ I# {+ k 21. [. s- d. A/ F' |% B
22
! |* V: A. S2 m- \( w( b9 O1 i/ i1 f 23) O' t( q" ?5 o) ?+ L; Q) q3 b. M
24
! g8 ?. Y1 @6 x9 G1 v 25
* |. d* f- P7 I3 R. L3 F 26) U3 L% B9 S+ Z- G; k4 z8 h
27
' y! ^+ L# H/ A" a( f) h$ M 28
; Q$ j+ s$ R) x( h 29# v8 z$ E& M4 U7 _! a- _5 L% Z8 p ?
30
# X# F6 |# s2 ~2 a: _+ w 31- q5 u8 H) N. N0 ^4 U% Y( Y
326 L2 ?7 `2 I+ u7 _+ Q
33
' B5 ?6 f! z* C% O# k% h m 34
, q7 [ s' k1 e; q( v- H 35% }- Q1 r: B8 ^6 d! e* d1 s. A
36
. c4 M: Z3 c% [' j U; W 37
4 K& n) i/ m# R0 C, b 386 I5 |+ M3 x+ J& f: Y$ L
39
8 h5 }$ H" l4 A+ R) ? 40
/ ~: a$ L/ I3 P 41* G3 [3 s" w5 d# p+ e# O: q0 a" V: b# G
边界问题
' E' f* e3 u) S9 r* d( t2 d 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。/ @" }! ?6 S" D$ m/ y/ F( Z& S: z6 l
' z: k: r8 [- l2 X$ X# i
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
2 m( T, c" \, d, E$ J
( O3 s; h7 t3 k5 l6 L# [" P; I
3 V2 R' O& U" U" r
! J. i# I* A$ D/ v: D 由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
5 J. p# p2 N. w6 l
0 L4 I% P. K" {$ `' U; |: V" G 第一组越界(即end1越界)0 X0 h2 k/ i% u% l" Y: o; n$ R; O
# `% r- U# H4 P 应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
% ^( T3 k8 t/ c$ V, Z6 W/ E( Z 5 X6 f9 v5 y. f6 [; e
第二组全部越界(即begin2和end2越界)
# k& w9 y; c; b! f! h% C 0 K" k( l/ k# ~+ W
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
5 m0 z7 t. D' w G6 w & S. w) M! Z4 ^8 Q @. Q' M
第二组部分越界(即end2越界)
2 |; |) @% ~( s9 c* A7 D: z 2 {% w+ w( b2 n7 h$ K
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
" [. }9 t ?5 Z2 v7 L
+ N+ u. Y0 u4 x& I) y9 N 其实第一种情况和第二种情况可以合并为一种情况,原因:' T5 z* P" O# G
* P1 p$ Q4 }( T/ ?1 S end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
' W2 @) M0 e* P( N! C$ v
! c- _; u( B! ~" U+ T 拿两个数组试一下:) N, _- j- |+ c# ]) m$ T1 q
) h8 Z: c: _& ~) d
5 y# }( n6 A c* h; z" Z7 l6 v5 H
' m9 Z; { S4 K5 h% |$ `: a w" \
$ m7 ?3 i- h+ S$ n M
7 Z6 W. M; _ }8 W1 R 代码实现
4 z2 T% m9 P- C4 W' D9 a1 h5 R# m . m5 D X; M) v3 @
void MergeSortNonR(int* arr, int sz)5 q/ W5 S' }2 w! d$ ^% W
{ q( G: |& F6 m R0 t- o! z
assert(arr);- U$ p% l* V( [) i! P% |
( G2 K- r& X- c# t$ u
int* tmp = (int*)malloc(sz * sizeof(int));
4 N4 L& O" ^) i) u- x if (tmp == NULL)
+ x1 Y& x" U* c, E {
# ?, W$ _3 h. o. V perror("malloc fail");
& H/ W% l- ? c$ F4 c# | return;+ T+ w# I% X8 J" Z, N- d( Y
}9 ?( r8 d# e" F g: y
4 G8 x5 j/ ^; P+ f5 E3 j
int gap = 1;
4 H7 g T$ S. A" W# Z8 W4 _ while (gap < sz)
7 G) H% L' c' T3 e8 m {
; `% P! |8 ~0 b" z/ P for (int i = 0; i < sz; i += 2 * gap)
0 F& J' u9 P7 H& q4 }) q {: L, W$ }/ y- A- v
int begin1 = i, end1 = begin1 + gap - 1;
8 ] D; }" _- ~9 `+ x3 R int begin2 = end1 + 1, end2 = begin2 + gap - 1;! X/ P$ T- |# ^. D+ P& z. ?4 P
int j = begin1;- i4 b0 p$ k6 p+ \
//越界检测& S4 C ?+ _* z& U$ S1 W7 i
if (begin2 >= sz && end2 >= sz)6 M9 G9 }! n) H
break;! ^/ K* e# ]( l% t, B+ c$ G+ A$ a, \- \
if (end2 >= sz)7 ]& [3 O6 J ^' b4 j1 ^
end2 = sz - 1;
6 D- z/ |& A' g* V2 d //归并
x) I( V) C6 ^" s while (begin1 <= end1 && begin2 <= end2)6 q7 s4 A0 }0 X' ~# d. \1 i
{
4 o: g2 Q: W2 Z l; T* Z8 j if (arr[begin1] < arr[begin2])
- j- S R l9 }. T) ^1 o b% T7 h tmp[j++] = arr[begin1++];
( s5 p6 j2 F9 V2 k else
' v) Z: j' f6 Y3 n tmp[j++] = arr[begin2++];2 D- G# J' P$ a% x$ j* z
}8 a. C1 a1 R& j6 m/ v# p8 l: y5 }
) |; k- I7 e9 Z; X6 H+ E while (begin1 <= end1)1 N; Q! ]0 d3 l/ w! A1 H5 w
tmp[j++] = arr[begin1++];
, l9 l7 G! i4 g* q4 C( U while (begin2 <= end2)
1 Q# {# w& u ^, h tmp[j++] = arr[begin2++];
2 a9 X% Z8 j& X- M9 J) b
6 N3 S( S2 s: T1 g/ A //拷贝回原数组——归并哪部分就拷贝哪部分回去9 P* H6 L! i* o1 O b& i
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
" m" h+ X0 X" |3 _# K }
# A8 O8 B) L: \ gap *= 2;. n" Z: i8 z* n' J
}: z. S5 s" M8 n
5 `& [1 r7 B6 Z* U O$ |( { }
3 e& _- {- X+ ~9 F! P, D
. a2 O& j3 M7 d 1) C% w3 K: q# `" X* `/ |+ a
2
( e( c, r L3 p) t- U 3+ l/ \) w0 Q3 Z
4
- Z) ~. ^3 ?* S) O# \; `, { 5( b3 y% q. ~! t+ S. \% s
65 K6 S" ]3 e! F4 J0 g h
7" W% c4 H! ~0 J9 W# E% {+ p9 B
8
8 a! B |- r9 i. z3 D- ]# W 9
. X. I6 K- G3 H. n( t5 g# h9 q 109 z+ J+ c$ s \2 Y
11
7 ]0 L& i2 Q7 c. w) C 12- d$ k8 w$ k4 m7 h1 D$ H
13
+ K8 X* C+ |3 }7 [ v 14
7 Z k$ N N0 V6 d A 15
2 s( ?: ?* C/ l' w% r, ] 16( `& @ `4 u; y% [- M+ P$ D
17& X) t( ?/ M H3 d: f, F8 P0 q
18
* V# k, K+ ~6 E/ |! p7 ~ 19
5 G P5 I$ F; e | 20! B" [7 u9 S4 i# J
21
1 E! Q' w8 f7 o( R- J 22* c3 r0 I- e; Q% [/ v
23% \) ~9 h" |. w& n, u% k3 l
24
% O! u. l9 \- d( Z& V( n# Q 25
" Q5 @; Q1 W) V# X4 ? 26
* [- s9 \/ Y- o" I* L+ b 277 n+ R' a2 B! u. c5 c
28
( X V- A0 z; D& M 29* `- D" U& P7 v) q; Y! x
30
/ X' u' B( [: u9 w8 y' N 31
B( f$ q( a" } 32
P1 X e7 h/ r3 e- G) |- z9 @ 336 u( ?" D' p3 I2 b& P8 E' O5 R& J
34
/ W }% I# e# x2 T 35
7 ]/ @' V% q: p+ U 368 Q3 C. p# ^9 n+ @ T+ \" ?5 A
37+ T. F& U) E4 R0 C
389 T" l* J, y+ G+ e n
39
$ K; `3 r* ~8 V1 @ 405 S3 v* J2 S K# l$ O1 u
41# C1 L$ u4 q5 Q1 R0 D9 F/ t1 S
42% d7 B6 M& B: z" t' `0 A
43- X' ]$ j6 N' _6 N9 d
44
9 `$ U" ]; ~3 z$ f: n/ a 45
3 t* w4 `" ^' s' _, f" O7 \* w 归并排序的特性总结:% [! u8 I1 Y- d; N; I
" }) ]# ?/ `( o4 S$ v( |# d- F. O 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。% H$ `5 d' A) ]* o" F
时间复杂度:O(N*logN)
4 h' h( X2 ^6 G( _! v- W 空间复杂度:O(N)$ \: C, w2 ]1 W( P( ]. t5 C
稳定性:稳定' a' i' c, b1 w; |3 p
4 Y/ k. G" i7 J2 Q5 ^ ————————————————4 H. S5 ]3 R n, b
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。% b9 t) }" z6 N6 E
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
" {8 l( c2 A. O9 c % O9 j- O& L3 b. r: U
, ^+ `4 Y4 F' m; ]
zan