- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 563319 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174219
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序: B ]$ A2 G, n3 j
t& h z5 ~" p7 y; v& a. l
前言 p% d& U4 P; T- J& r
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。5 a( O3 q1 O& o4 `4 q
( j5 ~7 J6 M. F归并排序- o9 l2 S6 t! t1 r0 N7 E3 i$ E
基本思想
& m; c/ Q9 n8 K# z; C8 d 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
1 K: F- I6 Z4 c4 M) Y4 x& k2 J7 B2 p0 }- d, l- y1 A* Q
* o* _+ {+ {# a, G4 N4 s% E$ ]6 K s" G
合并的思想其实和有道题目的思想如出一辙:3 B3 K/ U) r- f2 A, f0 f7 C
/ U: ]% f8 A, D
/ w5 h) |' H0 W2 |: s3 i8 t8 U# T% E g$ ?; M
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
4 y" j1 N# \. \5 W+ n5 E7 [0 ~
1 {+ ?- j; f% u2 T0 j, M[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]/ M$ L" R# P* V
, u# }+ `, k$ \3 q9 ]int* merge(int* nums1, int m, int* nums2, int n)
+ Z1 h3 D0 D# @) s{7 S$ u* d" i1 w i; O3 }
int* arr = (int*)malloc((m + n));( L+ [6 a: a7 `
if(arr == NULL)
$ n) u' @: E8 B: `) W1 C. T {! J5 I: \+ E& X) k! d
perror("malloc fail");
$ m- L% _. ?. l' D return;# D* d/ V# b0 t& F3 H' w
}& x$ n7 e. @, t# \( H, B
9 h- O& ]' M H1 A2 U( d
int p1 = 0;" I5 G6 x) T& P
int p2 = 0;
- @: G s2 x+ @ int cnt = 0;
: s/ W$ Q! |9 e. l0 m- K while(p1 < m && p2 < n)2 U9 e. [+ @0 W3 s9 g1 B
{4 Y$ M: ?1 Z, Y
if(nums1[p1] < nums2[p2])
. t/ j5 w x t# X2 H$ [/ s& l {
' R1 f- H0 |: e: y arr[cnt++] = nums1[p1++];
0 `- A+ }2 s! L, o8 W* x }. g/ d& T$ _5 I! y+ M
else
+ L- g4 h* D# j, n0 M3 n {% c. J$ ~4 H1 f1 A* K4 n* P
arr[cnt++] = nums2[p2++];9 c7 Q/ f. M/ |0 t: S) S& q
}
& x7 l- U; l1 n v; [$ j6 [- | }+ J$ a$ T1 A! I/ X0 \6 J) q9 l% k/ ]
while(p1 < m)& U6 {. P+ E: n9 P9 v# {
arr[cnt++] = nums1[p1++];
) G9 J Y1 @" s- ]) F/ C6 l( ]* ^! Q3 x2 _$ S# Y8 f, m& |
while(p2 < n)
K1 F r1 e2 B9 b- F arr[cnt++] = nums2[p2++];4 q9 v2 P4 J, [) T5 j' r
$ t7 p, J5 ~* L
return arr;
. c/ T" c1 n; x" v ~' J}
l' q- F2 U( v) A- ?# L* E' p5 m7 b+ V1 M: F7 y2 o) {" }5 \ m
18 ]9 I$ Z! _1 d) B, {4 j
2! Y% N' j/ F7 h0 L4 y9 b
3
4 s8 @. @+ j8 b' {44 V8 l+ U* W; b( W1 X7 q
5* w' `9 V9 O0 I. e0 b% M8 _5 v( u
6
$ M5 u6 A3 H7 ?/ x: H0 H. h5 N5 u7
) a4 s4 d1 k7 C. {8% n' }9 I! U' T2 L- k
9% u8 @: W* }; Z: |
10' Z; m. C9 W- T) d6 @4 b
11% E8 k5 z( u: E8 {
12, J1 z: M5 Z. C5 a4 \ R% t
13
+ x* G; z* E3 | |* y' z14
4 R% a6 R% @% K8 C2 w& \15$ k$ h, s- m" H( `/ t: z
16
. r% K9 d( I0 ?' L0 ]/ S5 y1 e17
' h5 k3 J. N) V1 }4 y- |. u/ o18
. h7 K5 P/ m# e195 Y+ W4 {% Y9 i( i; y
20
# C" b+ r0 i4 }) `21) i8 A" p2 O/ E; H2 K7 Y' k
22, z* D# Q9 O+ ?: E% r; G
23
8 Z% B# B& T) D24
4 {: r9 \* c% I" g; o25. {7 S+ j% B* {. C3 X
26& Z8 e `* ^% y
27( Y2 D' x& l3 Y
28* |, h+ s+ f. o1 q
29
6 W8 S2 c8 ?1 d$ ~4 k. b$ |30 B6 q/ ?3 d8 R) u w
313 b' j( U5 K% [: T8 _/ t* f$ }1 X
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
, V v ^( ~3 S0 o( I s4 d2 P7 V, }, h+ y8 |, N+ a0 ` c
递归实现" t$ Y# }% [0 I% @& A, E7 l
通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
6 ]( {+ O2 L6 @. }7 W
W4 L9 T: Y% P4 B' }& f+ l3 `: n" H
. N3 e) _+ r0 b) t+ s4 d
) ~+ L( o* z- p. b, v. |
& A) i! G: ^8 q: @void _MergeSort(int* arr, int* tmp, int left, int right): P( H; i7 T8 y# j. l8 ~, U/ B
{' ~) M0 p f7 D, x8 a- ^1 j' f6 n& y
assert(arr);8 z2 F( \, @6 u
5 G v- B% c. Z$ j
if (left >= right)//递归结束条件不要漏了
; ^. l8 }. B' L9 o7 K. k1 G return;4 i; j6 _, P& T$ j- t' P
. X1 r' @9 H9 U% c$ W1 B! ^7 r, S
int mid = (right - left) / 2 + left;
' p4 |" H8 \5 t* e9 N- {' a+ j P7 D+ [3 w. p
//划分左右子区间[left, mid]和[mid + 1, right]6 Y T, o( q* k8 B/ D2 M
_MergeSort(arr, tmp, left, mid);
3 I6 [* t- ]4 W' A _MergeSort(arr, tmp, mid + 1, right);
! r$ a, m; Z7 T8 ~6 B5 k* s1 p& c2 l; j& S
//归并% y8 J6 s. \; O+ _( s& w) i( I) l
int begin1 = left, end1 = mid;; f+ |+ n& j( `. x/ i. P: l
int begin2 = mid + 1, end2 = right;9 x9 j- g: a+ @( g. m( W+ v, u
int i = left;7 c" l" e% S x1 l* S: B7 Q
while (begin1 <= end1 && begin2 <= end2)
4 ~/ v+ I2 J1 ?/ S {
; f! B7 Y* d2 |" G4 b1 D if (arr[begin1] < arr[begin2])
! K3 Y- s3 j s tmp[i++] = arr[begin1++];/ X* ]; g! [- f4 ]7 I$ n4 V4 k
else- D* ]% T$ B! L# t; P8 }3 b
tmp[i++] = arr[begin2++];
& @# a, Z: `* ?: N9 O }- _1 N1 Y9 \4 m. }! A
3 w+ n' V$ x# W while (begin1 <= end1)! l" e7 {" D) Y
tmp[i++] = arr[begin1++];
7 L$ M, k5 ~, d2 ]; f @ while (begin2 <= end2)% }4 _6 ]4 Y+ L% K
tmp[i++] = arr[begin2++];
6 i; F% _! ^/ E* Y( ^* q T/ S4 M; `
! C# |' ?3 x/ k O //拷贝回原数组——归并哪部分就拷贝哪部分回去
/ ~8 j: b7 g5 `! V' ] //而不是拷贝整个数组回去* d' ^& g( \+ m& K2 j& v7 W
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));& u2 I, l+ v$ _. `6 a1 @' j1 S
}" V& u* n8 h5 z
' A8 O1 M( o$ r! I9 Xvoid MergeSort(int* arr, int left, int right)5 N! j/ Y; x. |4 v- P; b
{# }0 N1 b, ]* p K& C
assert(arr);
# y/ o* J2 j* \ V& }+ m
0 x/ E S' a/ F1 k) C, ~ int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
+ H } I" ?" P6 L' U+ s+ o if (tmp == NULL)2 x) O; l+ K3 D9 |/ ], q- x4 Z
{) L) E& G1 N+ t7 Z* l
perror("malloc fail");& b" z. A5 K7 _
return;
5 g2 V% d* e. Z6 R1 ~! e9 P% o }7 D: k3 \, J' H5 S
7 A# z' i/ Y$ g- J( i# ~
_MergeSort(arr, tmp, left, right);
4 n8 L* u; \+ \ D6 ?, O# ^3 o# M' q, {/ X! T8 `
free(tmp);
- c p& ?* w' b tmp = NULL;+ q* p7 L1 Y$ Q& }! Q: I9 S
}
. Y6 `0 n( C7 j- ]4 e- n7 w# p5 i, N, K3 |3 z
1, Z; j3 Q$ x5 v! n
2
/ x/ M% {1 z2 x" S- u: T3
+ `7 B- I6 O, H' ~: L. I7 O4
+ T1 j* P& x' V5
. U! i5 X! t* D5 \- \$ M; }5 q. B' x6& H+ A" c' t! g) w+ G2 v4 ?
7+ a. ?/ q, ^5 ?5 f0 A$ K
8! B6 u- C! Z# X! b& H% S: t; I
9; G6 p9 p7 U! z. J5 R; m4 M1 b0 Z
10
$ o$ F( a( f4 A2 a! y0 v1 _11% V4 D6 J0 K$ u% a1 I+ E
121 _; |" ^ E& U. |) p3 a
13+ i# B; S6 Z) ^' Y7 J$ L2 V4 i
14
/ c1 b+ C$ e" j9 ^2 D$ l15. W L& c% X9 x" L1 e) H0 z# y
163 Q; A3 T2 F0 V4 B7 `
17
6 t4 Y) ~7 z: ~2 l& V8 A$ J18
9 D+ G3 a; P! O* P& I; e2 w19
O3 N9 O7 h, p! D1 N: T6 z }/ Q0 |20) J' a* @- k( A
21' \# c7 T% P1 Z; L* q. ~* A
22
4 _8 ?: u. }, T4 c o23) L" A. h% o$ q
24
+ [1 C% a( t+ _5 \& A. D25* ~! n1 [" W0 O3 |4 P5 M
26
1 s* U' t: Z7 q5 e/ P27% z4 R% j, ?: _4 u7 L$ o
280 L6 m3 {2 b: F5 J6 U7 J
29
, ]5 F3 O+ z: c" f8 Z) _. i8 {30
8 w& w! y4 m# s, @9 T, S# j313 Q% I# T3 S& X$ T
32
0 J6 p+ s% D' T9 k6 u4 T7 ^# B0 s: ~33! v8 r; [% _; f) `
34
# |) Z- \7 U2 l# G8 _7 [. J354 d, J1 p# u1 C) y& s5 b! z
36
6 p' R" R+ a f& b9 D0 N4 {37. b) P' k2 L, T
38
8 K! m, ~' _: W39 s, `1 @: V. P# P; L- ?8 U# h
403 c8 h( D( _+ D- C
41
" J' `- E3 O$ z/ C" L; j42' U; s6 | k1 l9 Y/ a. N# p( [
43) ?( [! c" F. R6 \; N9 N$ q
44
# v+ Q- c: ?9 R: v9 }- o% p3 S3 u45
! A k: _0 g1 ?5 l& x469 O6 g* N% ]. b/ K
47
" V" y9 E, h3 B! G y48$ B3 \2 {: O! I1 Q
49* C2 b9 N2 ^% \6 _
50; d- x( b6 S" C& w
51
( w9 I3 P& }$ n" h8 v非递归实现. s2 l p% Y' o
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
; ^) L( j1 w: y" F, t
2 Z8 Q/ H/ O8 N$ w( j7 N" h
+ Q6 j( o$ R% H5 k8 O
2 U7 x+ @. }6 k 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
5 [' `+ n) i8 @. k( q5 l1 U \9 p" g0 O" A \
还要注意区间的取值,每个区间就是一组,就有gap个元素。
0 _$ i2 D8 \# j* g' k$ P4 e9 R' f9 ]2 ?. L3 Z
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。2 R' d. |7 {0 V( u1 t
( q0 k+ w4 _+ W- x }9 Z; j代码实现2 j0 c3 S8 r" T
6 X8 O% H0 N# x& e! pvoid MergeSortNonR(int* arr, int sz)
6 x' D' Q. d5 j% E2 v{
8 s, O5 n/ r3 ^ assert(arr);
6 i; K3 d- }4 n9 V# f- G' V% s* S9 q2 q
int* tmp = (int*)malloc(sz * sizeof(int));& z! f, U( f5 m0 M0 }( m
if (tmp == NULL)
4 C0 E, C! L* t$ t {4 }' }. K# D+ z
perror("malloc fail");( A8 O I4 @) U
return;4 [2 m3 U" Q# s' W9 T, A' y5 y
}; {3 l3 L1 k4 v* {: ?
& W3 q \( ~ U* b$ H1 L' G
int gap = 1;
! H# P" V @/ ^" {& A y A6 a while (gap < sz)
- }# \3 U2 y, }0 Q3 V {0 v: o9 M6 \! x0 K9 F7 R% @
for (int i = 0; i < sz; i += 2 * gap); X5 ^' V9 b/ y/ w/ B0 l
{3 z, |- L+ f5 P6 z) S9 `) n
int begin1 = i, end1 = begin1 + gap - 1;9 F! b& z. e# T* l4 q
int begin2 = end1 + 1, end2 = begin2 + gap - 1;4 P. r5 W3 D2 n
int j = begin1;
+ \- S' j) Y" L- M9 i3 r1 Z7 q' t, n O; ^: Z
//归并: A- l; m# c& e4 v% ?
while (begin1 <= end1 && begin2 <= end2)
8 A5 v# p8 K2 Y/ C( n. j {
; B- [ k/ i& [: V8 R1 Q3 o" E2 a& m if (arr[begin1] < arr[begin2])+ A8 t" c. F$ h/ u
tmp[j++] = arr[begin1++];
% x" _: x! k7 Z) f' h% c, u else + M! Z" w& w/ r" p0 m9 ?- f
tmp[j++] = arr[begin2++];
! }. t2 }3 e3 d% [8 i: \! p% l* J }8 n7 s- `0 M+ a, o/ F
( j- \4 `7 ?: ^
while (begin1 <= end1)
6 c9 X6 d+ y& I+ [. a4 a tmp[j++] = arr[begin1++];
; g5 v3 g6 z- e8 A while (begin2 <= end2)
2 Z: n) e5 C& e1 P! A* ?( Q tmp[j++] = arr[begin2++];
$ s% p& L1 E @
/ t7 A' P: e. W9 t( N4 D2 _ [/ L //拷贝回原数组——归并哪部分就拷贝哪部分回去
, t7 a n& x/ v8 {1 u, s5 y memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
& V. T) M+ U* m) k }
* {- C4 r7 j) g2 G gap *= 2;+ u; L% @! y$ k
}
! r9 ^ a1 w9 s ~ s W1 x% X4 m' f& @
}
) K+ t8 C. `* j" z7 y
# ~3 T1 R9 K. a1 y1
( r# @9 z# ?5 y4 ^ q2' `# y) w+ F5 K9 ~+ q
30 O$ f2 ?0 o+ u; n( x/ x
4
, i) k8 X, I4 \& ^+ B+ v k# t# T2 e" S50 L0 m/ }, F" _& ]+ s2 ~
6
: b5 E* Q% F( q2 r3 r3 M: h1 y7
. J+ m" D/ U& v: L/ B4 `8
8 }$ r6 Z6 X* k! C3 T. p! i, [9
% J% ~5 B0 y6 ]2 \103 U N$ c6 p" q! F1 Y
11! n" p" W! F+ [# C( P, ?
12! V! i/ ?+ Y8 @4 u6 Q$ d) E; f
13
. z5 D0 T' `, a9 g* M, M14) C9 O5 ?, u u$ W3 T
15
6 @6 @5 d2 W0 I# Z$ o9 g16: c2 o; M) A( u( B' v* e
174 P$ B/ w: B2 P0 [" k: Z0 a' i
18
+ @# ]6 [% f. {, x2 ]8 E/ G19
) z/ _ p& p! n% C8 S! I' x' a20( _; f% I' m+ w
216 G* A% Y. d& e9 D5 o4 o0 _# I
223 X& K7 K% B1 K% f( {. A/ p
23' C O( c, [" I- Z: T% F! _1 v& V+ p
243 w) O( Y: ?. @/ d# I* e# N
25
5 `9 R6 w: L& n26
, k% A/ I9 ~ ?0 N5 A27
( o* V' w- J6 k7 I3 r1 a28/ f- U$ r; d$ t0 p
29. l& T% B. @5 W# B3 \8 ^2 d
30) p& m0 L! `0 e) j+ d6 _
31
2 v/ _( z1 t3 T0 x+ e. w1 w2 L) a328 V* V$ m& o! p2 E8 j+ o) U
33- F. r) ]% @6 ?/ M
34
2 R$ k* Z% [0 f0 L' e, _35$ L0 e4 c! e8 v* O
36
1 E" T& G& ~' {1 ^6 _0 G37; ^( K1 O/ n) N9 q. H5 k- ^5 [; [: K
38
& e7 d. ?" Z5 @/ G9 w5 _& c" P U& F392 `' P! z! N7 l6 O
40
1 Y7 t, i$ s) K0 N3 H" v3 o41, i- Y+ H0 n" e. ^9 z: f
边界问题; [) N L- Q, z) [0 m% j1 [
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。1 R* q, _' D- f0 ~; Y; i. {
5 w" d- h5 ~: r# _/ a举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:$ t6 ~2 f$ u( q7 B6 @
' k! c. Z8 C$ |; H- ?! F
1 ^7 x9 Y. r" o
8 Z3 S$ n+ {) E: M8 w
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)7 U7 W6 n% Y3 l a6 Q' a
1 J. `" u( b1 _" m R* s2 l9 T& p
第一组越界(即end1越界)
; H0 i( X( r( m/ L. I+ _; A+ }& k( \) @
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
6 c9 o% V9 d+ D$ \% p: w' E7 e
, t) S' u1 q9 I; ?7 S4 n( F& `第二组全部越界(即begin2和end2越界)1 U- e3 [7 l2 b, r
# {3 K7 `/ y0 F: |3 p0 _应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。+ N7 U' U% c3 q( h0 ]
. K2 Y. G9 }# u0 q+ \2 z% Z7 m% v第二组部分越界(即end2越界)1 |" y! [/ x2 p8 _
0 t+ |& {6 t( D5 D: y+ d应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
( z. w. O2 s$ v V4 j: b1 f1 F6 ?; ~% ]: H0 X/ e; J
其实第一种情况和第二种情况可以合并为一种情况,原因:
* O4 R; C' U9 z( D" l D. ?# C- W4 D* U. @. M
end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
9 }6 _' ^- m/ B: U! [ w( T
' o& d6 I) N6 P" `6 u- z7 Q 拿两个数组试一下:
- o2 t* U6 _( C9 R5 B6 N+ g
5 y& n9 J& m( t0 E5 K; i
9 Z1 D1 P0 ^0 C: V! P5 U4 r" z- j2 K% w T
! h! t, s0 v' m8 n8 E# y5 t4 d
! i% c) P+ V" T# `6 n" f' z* j4 _' g代码实现$ {9 a6 }5 v5 w% k# z
% F, ~0 W% @! W/ z) R& Rvoid MergeSortNonR(int* arr, int sz)) L/ f. e# W2 N u; ^2 B
{# H& z4 {4 k! C: A
assert(arr);0 e8 H+ |( E! X1 {+ Y
1 _; |( V5 _ l/ S, a' [+ X
int* tmp = (int*)malloc(sz * sizeof(int));$ W% Y- V9 T3 E$ r. m) L
if (tmp == NULL)
- A; K; o+ P$ p. n {
: T. o/ G% f$ ]: b( Y3 E perror("malloc fail");
3 Z2 a7 b# P V! H return;/ O' S+ y6 }! E* M- ~& \/ B7 T1 ~" f
}
9 z5 V! ^- g) R7 P% J" @8 ~- c0 x5 G( k2 o1 \" [
int gap = 1;6 `1 c# p- h1 Q; S2 T+ i
while (gap < sz)8 x4 k. S2 Q2 G
{* m4 q7 G+ E' c y' i# T
for (int i = 0; i < sz; i += 2 * gap). b- B# v% l- \
{
& X C, G( z9 e/ ]! f int begin1 = i, end1 = begin1 + gap - 1;3 Q' @% J; e" s. @( d2 x
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
" {$ w2 p# B* A int j = begin1;: r' ?/ P0 p5 X3 a) [( W
//越界检测
8 g7 z$ b" \! g4 _3 `; f if (begin2 >= sz && end2 >= sz)0 f2 @$ L2 t2 K) t3 c; k
break;( E" R- N$ n) @ m& A
if (end2 >= sz)
2 E$ H8 y5 M, A6 [# y: }5 u end2 = sz - 1;
( q$ S7 J) R+ X1 F* i. V //归并7 z3 B6 {8 |+ j7 W& g8 M- C
while (begin1 <= end1 && begin2 <= end2)
- m3 g4 I; `2 t b5 p {) x' b! B$ x" W$ V/ V
if (arr[begin1] < arr[begin2])
! T$ e- `) F+ U: I4 ?" r2 r tmp[j++] = arr[begin1++];
: b5 `+ p8 @% p0 |0 M else
0 j% k- ?: w# L3 Z8 z9 t) x% n } tmp[j++] = arr[begin2++];
( J' z: H0 K. d! p }
7 _& D. P8 u+ Z) Q/ w/ Y. h4 M1 d3 w: T
while (begin1 <= end1)
1 D5 s* l+ z- | { tmp[j++] = arr[begin1++];/ A+ w' `0 d( y0 f ~
while (begin2 <= end2)! T; J3 O- e& M8 C3 x! |$ A
tmp[j++] = arr[begin2++];$ f) J+ V: V6 W) f' h
$ m/ I. l* s# ~+ n' }# g# J- X
//拷贝回原数组——归并哪部分就拷贝哪部分回去0 d Y% J) z$ `3 |
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));% e* F1 j/ b7 G- E! y w) M
}) J" Z; I8 I* f8 @% ]
gap *= 2;
# W7 {" U( C8 ` }
3 h; [% U) M M$ R& `
3 O% _9 E) M: f9 e, o}! G& M7 X3 u! |% ?
3 N m8 O8 v2 {- t4 Q5 C1 c
1# i6 g$ i! v5 j* a; \
27 `) }+ m# n; B* ~4 @ h
3" H9 S0 Z. o) @( |7 l3 Q2 t: M
4+ K6 N8 Y6 M" O, m, q
5 _" n$ @/ g9 I) U% x8 K' ~2 R: P
6- C% H+ @7 r* Q$ D5 s# U
77 K0 E* m( t1 z8 M
8& J/ v7 [4 V7 P2 D
9
) A* c9 M9 h& |. o, V" b' ^0 U10
" E( K; G+ E( g: g' E113 v8 K6 z+ d/ H# t. ]' Z
12
$ S V# N5 T" T* o13: f$ v( E! t! B
14
9 |8 @! t' o. ~! k15
) J C% T, c4 U0 [16" _4 i6 p7 L4 U" r U0 k
176 @8 X( _ F4 }3 W4 w/ U) g
18- d3 i2 m/ c9 Y$ M- o
195 C# o/ x. `: D* d$ y2 K) t6 N
20
3 J! ~8 Y! ^8 H! Y21& _( A; }5 ?! _: k* P2 [
22
7 T0 b# n+ ^4 m& u7 a/ C23
7 `' f# C+ c% K1 j; ^. F240 j" w0 R( S% D
253 l: L; p; ?! F5 M8 Z1 P' J2 T
26
( C$ y4 u% K+ r% ^5 p8 {( H, J. ^27) F; f4 b; }/ M4 ^
28
# T% u6 G3 ^! |29
# f: g( t1 u" K }30. b3 F! J* I" Q3 O
31
9 E' C% v6 B8 l! [: Z0 _323 a* H* u) r, W
33
6 z- p5 ]. ^" [34
- m1 d( v+ t9 k( C35
7 Q6 d5 e! @- K362 N. C# i0 G6 {' c; f$ F
37
: z: R3 @ D$ R6 R38. ]1 Z1 r# v5 b! {# A& f$ _$ f( w
39+ e+ n( z) I5 S* Z6 ?, l* q
40$ M, ]% ] H* d, S0 Z- \& F
41
7 m- B, B7 ?6 G1 j422 }% {5 h: s$ u
43
7 z5 ~2 A7 h/ E( X44: R, P4 ]; L* c. y. S
45
2 ]% i& Q$ ]3 ?0 k4 J) }归并排序的特性总结:
. l' m2 |8 [, Y' U L3 v, a3 Z, M0 y
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
& c1 _( c! v4 K2 M* _/ K/ Z时间复杂度:O(N*logN)0 O# T/ M0 ?' P [, `
空间复杂度:O(N)
- L( V( w# m0 m$ a! _+ @' V' t1 m稳定性:稳定
! U* |( e; k N- K, M
% s8 ^- U; }# P% c0 Y————————————————
1 F l) c6 ], U+ ?& N4 z版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。! L, [0 K3 Y5 H+ ?$ Q# w
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
. X4 e* c, Z* @ f
s; G* c, h7 N, c" M4 p
/ U/ k! ~# E$ L4 Y* @ |
zan
|