- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 563312 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174216
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序
7 G, i5 l9 J1 q* m5 o; p9 r( P* W, l6 b/ N6 N; z5 B% i
前言
& |' T! P; u# ]3 [4 j4 D本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。$ o6 i' Y5 l4 H0 a+ y
% Q+ i* F8 o: y4 r2 |& @归并排序2 e3 ~5 V% U" [
基本思想2 \0 O3 c$ a( @1 I% D& M) d- R4 f
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。2 d$ e8 p7 `" O6 R% T
+ w# N- ~/ r, t" S! g& d
- Z/ C* r# S: H; K
) `# n, i9 _6 L9 j" I2 U& X- k' c* \ 合并的思想其实和有道题目的思想如出一辙:1 y& d$ N! w# Z) Z6 s* ?
5 x( `1 ?4 `$ \3 x9 S u6 l* s
, |# j' S4 h2 C& W' Z% [4 D% P" H* q
4 Z0 ? a" E L# C
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。5 I7 y9 \, v( ]3 i. ?- n
3 i& y; L2 F$ r' l& G4 P6 A[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
3 [/ M' k7 \$ Z: o1 W
# F* O' S8 B8 e, o, M1 l2 P% [, |int* merge(int* nums1, int m, int* nums2, int n)
6 J1 h$ u) l$ F8 O, `{
9 U; d! b9 X: L; h& g4 E int* arr = (int*)malloc((m + n));: {4 X' v% O! b$ h: J; a: ^
if(arr == NULL)
& T; b6 j) I y7 p3 D4 i {
: j8 ]) O0 [% e3 G+ Q: d perror("malloc fail");
! m! s7 S4 D% B# b return;
7 i: _! V% h- [6 o }
1 ~, d1 X8 E( y- Y+ z/ _7 v! q4 w+ `4 B7 M' q# B
int p1 = 0;1 M( z$ c0 x' [. e% `6 R e
int p2 = 0;
4 M; ?3 Q5 U1 _3 K+ s3 O& A$ z \3 r int cnt = 0;
; w# J3 s; b) V# |1 u5 c6 _ while(p1 < m && p2 < n)# Q7 b& C( {- w" d; Y* n! A; o
{
+ }" s1 o% B0 k! |# W if(nums1[p1] < nums2[p2])
P j6 l1 B, E q, ?) b, v, k0 c {
- h8 i/ u3 s4 H/ E' @1 ~ arr[cnt++] = nums1[p1++];
; {7 _# F5 X2 F. B' ` }
3 b& r. E1 ^! o; k! Z5 D6 ?4 u else
7 H. c8 {. v# r& j# b {
1 @; n5 ^6 e1 W! m8 G3 a k arr[cnt++] = nums2[p2++];3 Y$ P1 M3 c( G- \
}: x4 I) i4 P8 r& J C2 t$ \6 s
}
- @ y) h6 E: j4 Z) s while(p1 < m): v- x' b" N) u4 H$ P4 E
arr[cnt++] = nums1[p1++];
; x) o0 Q2 \9 q6 Z4 X! a
+ o) u' R2 B* K" o while(p2 < n)
5 o) j( R. x( k* _; ] arr[cnt++] = nums2[p2++];
5 z( l3 e8 ]5 j9 x( W" Y% b1 K: S3 @2 o
return arr;: J7 x( t, D* J; p8 J
}
8 K# Q; u; c% I+ L/ n8 e6 j2 `
1; N$ f$ u8 a; ^- r! u7 W X
2
. F3 N7 w# x3 K33 G) n# H; E8 B v1 Q
42 \( e9 I8 b$ |
5
: p+ d% v3 N- Q- K& c1 s+ @6
5 p6 V( i: ^7 B74 x5 O3 r/ ]/ k/ B, k7 ]2 [: L4 x
8
6 A+ {9 ~. Z4 W) Q' j7 f9" e: {0 T3 O# u/ k0 p
10
( x( D3 h" C3 F4 @; a113 {8 K* F) S" t; l% f
12
/ Q! Y6 [0 }( d0 t2 _13
! p. v( K' U% o2 F! B! {9 D9 ?6 o$ b14
/ _; O- @2 d! ~3 {$ k' s$ K6 Q! h, f15
& N9 c, A1 g6 A- q1 r164 e7 }8 Z7 U( O- F
17" T& p# i( @3 Y3 ?8 V& F2 X, S
18/ G8 e) K# U9 Z/ P9 o& Y
199 {' W8 R' C; ~+ `$ R. O4 b
203 t) _4 L6 w9 b8 \ j. r
21
/ n1 f* D* g# ~ U6 ^22
1 o9 R3 S. G5 c23
: z* _- x/ F5 ^4 r24
6 G% H8 F& a1 a( H+ q25
; c9 K( I+ ~' h& W9 k6 Z26# Z+ V3 h& r* ~9 D, `% v; B
277 g r. w" u# G
28" j( e+ m7 P8 A* }" V2 d. t
295 m% S$ t+ k0 }7 j2 D e
30/ B! V8 |% d2 m
31$ ]+ V! Q5 m* l: Q4 ]4 T
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
4 V: o, H6 X4 |2 B: c" c. P8 \3 Q$ l3 h$ l, f
递归实现3 y! O! s! L( O% F' L$ K5 y
通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
! [8 r" Y/ m# o
# j* g# f3 Q+ K, [: O/ K, `) {- w) z
9 z0 x& D2 A# C2 x; o+ {
# N! H" L% V# S( T5 L' }6 n* @' V v0 b# x: s
void _MergeSort(int* arr, int* tmp, int left, int right)
: i* |. p# M7 x{
& O2 z+ c! K- v- o% u4 N; G assert(arr);
. j+ H& i9 b/ E8 {) F1 w% |# x% X: f, ~. b
if (left >= right)//递归结束条件不要漏了
0 i$ w8 y) _& J. f return;8 E8 z* D6 I$ `1 _2 O' [
! E3 b: C! @# _ int mid = (right - left) / 2 + left;1 l; J9 m; n" |8 l
, e" k3 A6 j+ b- B+ E$ g //划分左右子区间[left, mid]和[mid + 1, right]( Y0 ^1 ] A) V2 a& M7 C, N( m; g
_MergeSort(arr, tmp, left, mid);# h! |$ O) w: ?8 H
_MergeSort(arr, tmp, mid + 1, right);
( ?) F) t, K5 v: W% d
5 Z+ |+ ^5 k- s //归并& s3 j6 h8 t v. v2 O$ X, _
int begin1 = left, end1 = mid;8 ~2 u A0 a& s! B
int begin2 = mid + 1, end2 = right;
# w& U4 {: n0 I* j; t6 y( l int i = left;1 r; S+ v* C% M7 l+ n* o" G
while (begin1 <= end1 && begin2 <= end2)6 k9 i! w d @+ [
{& C$ {: n: X- u) m8 E
if (arr[begin1] < arr[begin2])
4 G7 J0 H% y% v# r+ H8 T2 a' E tmp[i++] = arr[begin1++];% |/ a4 \, d1 W6 W5 z0 }7 h
else3 d, I$ x# l" N
tmp[i++] = arr[begin2++];
2 z) K4 F6 c5 m" s, X+ T }
- f6 L! p! Z5 d$ Q6 `) P+ j( u R6 V3 a( S4 z) e- Q
while (begin1 <= end1)5 W9 x0 S' i. m. i9 K
tmp[i++] = arr[begin1++];) L$ w$ `. {7 B$ y8 @
while (begin2 <= end2); Z* ~$ F" W8 [( v% Y
tmp[i++] = arr[begin2++];7 M: U2 k: K8 p, {' N% y3 t
$ Y( M* g4 @' k# d9 X
//拷贝回原数组——归并哪部分就拷贝哪部分回去
' ?( C3 n, V. i# y i! Q0 w' D //而不是拷贝整个数组回去- {; j6 J8 G8 `' I9 @
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
. a' m* d) y. W}' Q) ]% A. l2 X4 G8 p0 a
: y* V1 [- R( p& Lvoid MergeSort(int* arr, int left, int right)3 _7 I( l/ A5 j6 H4 f9 P/ ^
{6 l( X4 `% K& C, b5 l
assert(arr);# U, K$ n& J, r
8 A; |. v$ B. \: O& r: @% {+ y( h
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));/ x6 [% H# f% e
if (tmp == NULL)
. k9 r* h E) n. T6 L- v {
. _) n) T* ^9 Q) E. p perror("malloc fail");7 f1 L8 Q, d- q
return;: `7 }4 ^7 m& Y! v6 a4 [: k
}/ j5 B; M0 @# O/ |
6 |" [/ ]1 E/ x( b8 d% f/ ~
_MergeSort(arr, tmp, left, right);
! z# d4 M- Z( ]4 l) {$ `8 a" ]! K2 G8 L( _6 U y2 E0 t L
free(tmp);5 I& N7 L) {4 w% p: N* r" E
tmp = NULL;
# s( D- Z1 v4 i$ S% I}
" i( d$ h- r5 F7 y
3 w. i8 ~( W$ y+ h {2 j: Q- k) X- x( x1
( Z# @8 b" `" N# a2 {" C& \26 v4 B; Y6 V: P2 |/ p' J
3, U# J* H1 m) V7 G" ^
4% @* }8 M" E. P6 _5 g/ @0 l
56 J9 E7 {5 Y* ?7 X3 L
6
! ^2 x+ j3 p; f& _ r* e; ?8 o7" D# r4 j% @/ n6 ]1 w- `; a
8. L. z- w% a7 q1 Z! ]* \
99 U8 o/ y) Y! Q- K, t6 \9 k1 g
108 t* }1 ^* m+ m! z
11/ X2 N J% S+ Q3 G& @% U$ _
12
8 Q) x7 w* i9 b4 P- Y7 Y13* J8 m( J8 e% y6 N
14
* T2 h; ]2 L1 h9 i+ v15! Z8 U1 u- L( I4 M( A c
169 M; f- M2 _. U* E- G% P
17
* I" f5 y' e2 n0 F8 X18: e J9 w9 ~& C+ q' K7 F3 b
19! Y; ?8 l6 T" ^7 t8 |
203 i: \$ M; t- F' R% Q0 X* T
21
" Q( I9 }; E! B# ]! @% R22- v( n' H$ f) E4 {$ q1 Z4 v
23
0 o8 N+ ~9 f$ i" W- W24
" I6 Q# r, d( |. h25; V& U6 q6 y( L" Y; e
26
& ?. U* e, \5 r9 {4 ?+ i9 A0 N2 K27
0 K- m x H# V9 b4 c28+ }3 [. |5 e6 e6 ?
29
. v9 l+ V) e% ?: m; U$ _30
c9 F9 ~( l4 f! l5 b J31, `6 K/ I$ D6 ], k* S" ~1 w
32
/ L+ X- D B/ a7 B4 A7 k33& x: ]8 M! `9 M. ?/ C0 V
34( U( m! J1 C0 |" F
35
9 f7 M* y+ U# H6 O8 b6 t6 ?36& o3 W4 a& P3 Q% M$ |7 n
377 a2 P/ H! R' c
38: Y& D8 a) e' R% r- ^) C( P
39
9 A5 r! H1 _+ G- [40
, x( E- X" _3 ^% _41+ A& ~5 f7 y9 V* r0 Q3 ~" d3 W: q
42+ H6 ^2 B+ X+ a0 \
43
# ` g' _/ _$ D3 ?& m( v44% J4 [* H( \2 {$ @ y1 C
45
- y% Y6 J9 p8 k4 ]46
) ^6 J) R' w# N8 n5 l47% Q7 e# B( r- |. f. P
48
/ k, j) K) L( P% \$ o49
n: G' [1 _% c50
# |3 H5 g8 {3 R5 L. G9 S0 B51( n6 D, y) p( T) U* z8 {* U; d+ K
非递归实现: T' ~# e; q, E; P/ s [+ o
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
U4 l" i, `* T, D
3 Z$ ~% r" G6 T- x! e
9 I! n; i3 S" `+ T; R$ y
m4 ?, n0 O% ?$ e" S/ a 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。4 z# k4 _; r! g, C7 a- l" M! t# U* j
9 x8 R, E% C! `. X# J 还要注意区间的取值,每个区间就是一组,就有gap个元素。
% _5 R9 G ?# N! m0 p J9 E N, i! ]/ ?' ~( Y
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
* K: p1 k5 z0 Y: n/ e! R8 b" x; f4 ^4 g. {. F4 d5 F5 m+ G, D9 I
代码实现
2 C3 J- q% P7 Z4 {0 j8 Z6 h3 {4 C! [# z- k) V
void MergeSortNonR(int* arr, int sz)1 S3 r+ V5 m3 L: d- z
{: z8 @$ d. k8 c Q
assert(arr);
# a! x; a. J' O0 `* m) s2 E5 t, R& ?. P
int* tmp = (int*)malloc(sz * sizeof(int));
- E- w. c3 Z4 } if (tmp == NULL)
! r0 _. b( r2 e$ i! r {
/ o( B. _' B0 M perror("malloc fail");# u" F/ i0 A8 b6 M% r
return;* s7 U6 }# o* z4 M( b4 k
}; Y g. \7 ^( O5 R
2 a) X/ n; y' [, `( u
int gap = 1;- h. j+ z. f# [7 Z9 ?/ a
while (gap < sz)* A$ c1 O" }. U1 j# e: G* u2 F5 B
{1 `2 d2 O+ M& m. }
for (int i = 0; i < sz; i += 2 * gap)
/ \/ X! P' r( F f6 @ {' P: Z% f% ]1 O! f
int begin1 = i, end1 = begin1 + gap - 1;
% f5 k+ J' {& h9 n9 @5 G& u2 r4 n5 P, ^ int begin2 = end1 + 1, end2 = begin2 + gap - 1;0 u$ y' ?5 F" A2 R8 h6 T
int j = begin1;
) P# i7 A4 m* l" u% ~: n( h% I' N6 r' J: M6 ^4 Z- T+ R$ G& `
//归并) ?7 R* _% A8 |1 G3 f/ a
while (begin1 <= end1 && begin2 <= end2)
5 {- J3 Z- G7 n3 q0 \( } {
0 _* ^! y0 y$ z# P; {: X: j if (arr[begin1] < arr[begin2])9 Q# |# B3 e/ T0 S& S5 @! ^
tmp[j++] = arr[begin1++];
% n+ T% B) p: Q& ?- I else + U: }4 E2 B$ u5 [. o9 C3 q
tmp[j++] = arr[begin2++];
3 @& Q; i9 c6 S) w }
8 ~- j4 p' L5 A' E! w
5 r, i! n. n2 E while (begin1 <= end1)- y/ H; O0 @2 |1 A
tmp[j++] = arr[begin1++];
- k2 ~/ b; D4 r( ~! f6 x$ h while (begin2 <= end2)
0 h* [5 h! w, q w0 V& H6 t3 a/ { tmp[j++] = arr[begin2++];3 ?3 ]* k) b% N. `6 \
; Q% A' E( W: P9 F7 p2 N3 R- W' A //拷贝回原数组——归并哪部分就拷贝哪部分回去& P1 o' f. t: ~6 o7 E
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));0 z( x4 Y- s/ g2 j- ]5 G ], t
}
3 G0 t$ A; K; `$ t( u8 A' {/ x0 W gap *= 2;3 `% \( c% N+ I, C% E9 f$ C
}
: }0 ~1 c/ X( A( s$ r, D* d, |. b
7 `- |3 P2 ]) A2 T, _+ H}. o8 B! r( j' J' x/ T
4 g$ V( }; t+ W' W9 z5 v, d18 ]* X9 W/ ~" D! u% Q6 [
22 f7 P9 H8 M% V
3- k2 e( J) b p8 w$ @& J+ I' N
4: @4 e* m- s! l& R: v3 C
5
. X' ]& n9 E, c8 v2 ]* o6 f6
5 b9 y) Q: [ @ c7; Y& E& ^7 a+ Z3 B
89 r( X: g! N A
91 h0 t) r. M! e; z/ M$ x5 S
10
3 j- ]/ J5 B' v! K* E11# w; m" r5 ]% u1 u# A: z& }
12. J9 `4 B7 V; e; N
13
+ i; b$ Z7 f0 O# C! n14
, `# Z$ Z( s& Y15+ y8 R% A; W. c! R m, f" E: L
16
8 O1 W! }$ i5 q172 _ ~2 t' [, }5 C9 }2 Z
18, K$ e1 t' x. r1 l9 ~! ]
192 J! ?0 y, }1 R3 g* N
20& C$ b1 F! M, I# f. J/ Z1 \& ?
21
, E5 N! B. U7 `/ Z# N2 a, J22
* x- o, j; D. y2 b- Z/ s! Z: @/ s236 T, u' F. S. o% P6 S# d2 Q
24
\/ f3 W5 s( M" D25
3 i. v L9 Y: q' W0 o# z6 q26; P. u+ N9 f+ X4 S( a# g
27
5 i. P' i+ g" H$ e28" [& {- f6 Q! I' I
29
" l1 z3 [6 M0 [) H/ F302 s0 M' {, o( \2 ^" F( r
31: l. p g. O1 ^: u4 |9 ~! v
32
0 C3 ?. W3 P1 m; T33% b" e! q5 h% M
34
' y( @, C b( f+ W. A35! d: q9 \) q1 I$ V& v
36
" C+ ]: s( Q% Y/ s+ Q37
! V2 I$ @6 I7 t38, d7 p3 Q) u# N# ]) S c* M
39
# M7 {9 r+ X9 U8 `; l( `40% A u1 u. W* L4 d4 y+ @
41
' T" h: N, u' [5 C边界问题" c: _1 o6 c0 K/ r+ i6 W
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。8 O1 ?7 i& G8 H7 b2 u/ m
! ^* b5 l4 n, d; O举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
. q; \; N/ W8 K- V* N* G* }6 l5 Z4 L$ H, }" w% @
- r; G+ [4 g0 Q/ g, z5 l
5 U2 X( W6 N% _5 A' Q8 K由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
& L$ m& h$ \: S( ?1 M; ~. I
Q1 q* D z, Y4 @5 h9 z/ w2 U第一组越界(即end1越界)3 V& M7 @3 k N* E# Q0 |
0 ^/ u8 L, x/ |8 q# v. T" c
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。! _; z- b5 W$ S( W' L2 t
' n8 {) Y& d) g" W2 o: ], ?3 M
第二组全部越界(即begin2和end2越界)
* ?; ~$ _ X- K, g8 Z8 J9 i- s
$ Z, B1 _( \" C8 S- \. ~9 N0 y应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。: o. g4 I5 v" w% ~: C# }( }. M0 O
1 p2 R$ n/ q, l第二组部分越界(即end2越界)( A' e$ j" e8 E% A7 C
* a6 T$ W, e1 I, M1 e+ ] p应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
0 R$ m! g1 ]4 V1 B
# z- W1 m3 N9 E0 k6 G0 t8 d4 f 其实第一种情况和第二种情况可以合并为一种情况,原因:. b) i) `, @ I* C
! `3 [- E# L. g K6 J end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。0 e) s& m2 U; f+ Y6 e1 G
3 _) _/ f# y, ~$ F 拿两个数组试一下:
! J F' i* p3 m7 B. L' @
( O- |& p0 t! u" W( v9 g. y: T3 v5 }( o
+ w4 U% |4 m% g5 d; m# s
% {# b1 i, }9 g- `& N" _0 P, F) ~, `/ W3 h- X
代码实现) {' `" `- O3 Q, O9 k* c
" m0 d; ?4 R) {5 `& `! K- c; o
void MergeSortNonR(int* arr, int sz)0 ? z! p$ S" o4 Y
{
, C) p+ ~9 o0 H9 h k# W assert(arr);
3 J& e+ V$ b* V" G: K$ V+ n
& d7 H- z; x# l6 w, M int* tmp = (int*)malloc(sz * sizeof(int));
/ ]) A. w A; d+ A if (tmp == NULL)
' T6 g' Q, g2 x; o6 I* ]' m2 e {- G. r! ~, ~$ r0 K7 m9 v4 s* d9 Y7 L
perror("malloc fail");
( ^4 d! S0 T8 j! }4 t' @; j% T return;
; j4 a5 Y5 Y/ Q }! Z3 E! P! d7 u$ A" Z A' l
" d! ]( ~& x6 w# \( q$ H) c, P
int gap = 1;
" i5 n6 u8 k1 x: n- M3 B* N1 Y while (gap < sz)
_5 l6 m: L- d) `: J* i {
8 @2 J5 b! [7 z# n' n+ H for (int i = 0; i < sz; i += 2 * gap)1 Q( G, W5 T& S: R
{
' \+ S; k. Z/ W$ L$ W F% C int begin1 = i, end1 = begin1 + gap - 1;* h1 i: y; V+ N3 O- p: {
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
9 A9 M$ `8 a; T+ f9 E7 C int j = begin1;
* c! Q" B0 g& k* m+ ^* X+ R! L. V //越界检测( {. {7 a+ q& v8 M' h' e7 R
if (begin2 >= sz && end2 >= sz)
( O/ a0 J, ~) W1 t break;
# C! M$ t/ T7 E6 {0 U: X if (end2 >= sz)
# P; H j1 W" y8 }; q end2 = sz - 1;
0 i- m1 }4 p' c //归并
) C! K0 v3 z* F/ ^+ B while (begin1 <= end1 && begin2 <= end2)2 V3 L1 }0 a7 W+ n
{! V; D2 l9 q4 T0 z0 l
if (arr[begin1] < arr[begin2])( E' q) w. n' h- I. \* \
tmp[j++] = arr[begin1++];- P; [/ d" i: S2 }7 z1 R) M5 e
else
! |& b+ U% A% R. @ tmp[j++] = arr[begin2++];
9 {6 E) j4 z3 f, k# x: @0 m }0 B$ g# }% C' w5 H& T
2 G6 e. w7 ]1 @) U" \1 N( x
while (begin1 <= end1)
4 A2 J9 Y% y" |9 A% h+ z tmp[j++] = arr[begin1++];
" Z4 k0 I) i$ ] M8 \1 y+ H6 `* r while (begin2 <= end2)
7 E/ L4 y/ Z4 g tmp[j++] = arr[begin2++];
% y7 w2 x' |* w2 m) s( U7 m8 b* Z/ _$ ^1 M# K7 t" A1 D) i
//拷贝回原数组——归并哪部分就拷贝哪部分回去4 ~+ f/ h! b+ m7 ]! h
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
3 ~9 j/ c7 b1 Z. a" v2 ` }7 V; ^6 n6 J4 e9 E- h5 h) y
gap *= 2;+ `! p+ h" r/ c" G: k* \" l) X* y; ^
}; t( G& v B! x: ^- z
8 R3 ?1 b2 c4 k8 \5 D$ O( Z
}9 d6 e( b0 z& }( H) J6 k$ ?7 B1 `
( ]' h% K& W/ h6 F5 B
1
! V$ O. v9 ~( I2
9 r9 ~7 I q# Y& N- ]3 |3
( z) q1 B' R; @42 f- f/ ]. ^6 O. c7 R. x1 {. J
5
+ R' `3 k, [5 y+ C: L6
, L6 Z9 r4 S& q; U. y73 i& Q4 }' }+ {; b$ U' V# i4 G
8
5 C& @$ X; e" O% _7 G; Z# H) _94 r- n! b4 S* N" H- O0 h, j# _
10
0 T% z) S" y, J% }11
9 `7 j' N! V+ Q, Z J125 v. N7 v; w5 U( W- P4 W9 j8 B$ v
13
9 Y; \6 I% t6 l X8 j j4 R140 a. G2 B6 V3 U! M7 M; ~! c/ A
15
: f* P: S! c6 h( w- w1 H+ w16: @/ z* T2 q& B# b. K/ W: P" h
17# s$ j1 ^5 K! ^+ Q; l
18
: w) n) U6 [6 H# T0 s" e0 O* t19
. t7 S; d- n. f; w8 ?% z20) B/ V U6 W* i$ v1 o$ f$ f' F
21
6 y+ r1 H& ?1 W) [( T" h+ [22. Z/ i( k l6 B4 @9 K/ I5 f0 ?+ ?# _
23
1 j, ]9 }7 U: q+ X+ H0 Y24
# B U& G% ?5 v; j25, F2 _/ a9 o2 M- S% R. n3 U1 F
261 ?7 y& r2 H$ D- L4 J# p
27, ]: v$ A& E/ w
28. q) ^* k9 t# e3 O/ O1 N
296 V8 j; q9 k" N- T
30
( v7 L# q6 c* P" L31
( {/ C/ X2 a) @: f4 z+ D32
2 d6 o6 e9 L! f- ~! `/ G3 f33
$ f7 J4 Z6 ~: p* K) S/ \7 n7 M$ F9 [34) t( ]: b7 R( ~% d* F6 [/ D B
35& b1 e) k) A% B) J" E
36" `5 d2 A3 T+ |1 _6 _8 m$ _$ b
37
; k4 R7 {* O8 M. _38! o5 u0 s8 m$ O3 D
39- | D8 {& t: Q* N
40& r+ o5 e# K9 w; F# ]3 |
41, M* j: O2 I5 {; Q
42' Z# ^; ~1 n& m+ i+ T1 h$ q8 Y
43
/ m: I( f. Q8 ~- Q44 k. ]9 j* m0 r
45
- C7 H. N/ r; ]( G# ?归并排序的特性总结:
' I/ O, E/ f& w" R3 x4 @
. n; y) _: H$ Q% E归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。1 } t6 V+ v- @1 D3 f; p0 J
时间复杂度:O(N*logN), V. g, q# c" ?6 A7 e+ z; B* t
空间复杂度:O(N)* D3 C9 ?, y5 ]. d1 d2 g
稳定性:稳定
8 H- C/ r: n4 _1 R8 k* b& F" b* p" g# v4 ~
————————————————1 L% H/ X$ _: E
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。0 M9 j6 ~! M1 ], V
原文链接:https://blog.csdn.net/weixin_61561736/article/details/1267966571 v7 Y8 F( R( s; j
- i$ r9 \, r' \( O- t, o
! ~& O0 @; f7 m0 t3 D4 J9 x% r" J |
zan
|