- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 565754 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174949
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序5 S0 h/ j6 _, }+ ?
n0 ~3 Z, s/ D+ p4 ?' C. a前言, \4 q/ w1 [4 I. \8 X
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
1 d u$ w. j. o7 y- r
7 v3 s, t' z2 |6 }1 h6 R归并排序0 m5 l- c7 n$ T* d2 N. ~7 o6 Y
基本思想
# x9 P: C! g) J5 l, ^ 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。% N; ]* d0 X$ x) J% v
! B; l0 M+ k; T$ N( {
: s/ s: ?! G% g5 l+ i3 T
6 o$ t- M5 i) ^ 合并的思想其实和有道题目的思想如出一辙:
# y7 l2 O& a6 \8 F0 H- W1 {7 N' p" q/ [" q7 q
6 b0 I7 H( ~; `6 }7 C
) V( z( j U. ^( @ 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。) X) N$ u3 T* F3 S. l. m
7 A3 R3 s0 a& F/ d
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
) |/ e8 K: B+ {- w) o* C
; v& Z+ C$ D0 dint* merge(int* nums1, int m, int* nums2, int n)
' H+ p8 L6 l' m. u' R' e) D{
! m7 Y. w# p) E0 o( p" N' C' p int* arr = (int*)malloc((m + n));
" g/ _$ Z( ]4 R& r- C3 m; r if(arr == NULL)) c6 D; f6 O( e/ W6 U4 }4 l
{
8 M' D* h0 Y1 a3 k J% l5 n perror("malloc fail");
/ A, H: C8 b } y+ F S4 O return;
& V- H" ?8 t0 p }# |+ j( L% c7 A7 h+ j
- E5 {9 e& R7 |6 f" O
int p1 = 0;
* ~4 [/ m$ f, S' X' g, i$ h- a int p2 = 0;( A- h: N% ?+ V( f$ A) g; p
int cnt = 0;5 f9 i0 e. J3 C5 B1 B! y* k' q
while(p1 < m && p2 < n)) n; s( n; J' @8 X) g! p1 X
{
+ w4 E% J3 N+ V: x/ P c if(nums1[p1] < nums2[p2])
" n, k2 u3 }9 s {, X5 [1 w4 c1 i1 M5 ~
arr[cnt++] = nums1[p1++];2 b/ `% E! s* E5 }
}
2 Z: v. V9 s- N( g6 Z else
& w% w+ }% X: J0 P+ W5 W {: R! I1 R6 f% K6 h
arr[cnt++] = nums2[p2++];2 h v [$ X O) s5 J( _
}
0 }0 Y7 r6 O- |" J. O }
( O; t& Z/ S/ {0 Q- G while(p1 < m)- H% k0 q5 |; A
arr[cnt++] = nums1[p1++];% a% v8 _, C' Q9 O
7 y/ r6 x: B" l+ o while(p2 < n)/ b% B& s( C( A5 }) T) V- r1 k
arr[cnt++] = nums2[p2++];# L; e( d# K P' j- [/ y& e
; p6 O6 _3 b% K/ N6 o7 C return arr;0 w. x: G6 n+ v
}$ K, Y$ ?" n+ F2 I
, s# s+ ~9 |: e5 r
1 o# J. a) g6 {( g8 X
2
; Z7 q3 y* D7 Q: a3( q1 F! I+ y# p3 G
4 p+ z; n! L9 j. n! r0 w8 Y
5
, }, S0 v: B( Y* c6% B) e* ?0 w+ |9 o- T- J; C* g
78 Z5 O# t. Z v5 K, F9 w
8; w! J0 ]3 U" w; _3 b) ]/ V# @
9
/ U5 O& U$ G2 G& w: n104 @4 g% b8 d& o1 K: l9 b
11& J2 F+ v5 I3 h$ y" ^
12
; F6 b& @# K/ N3 C13$ e: S$ A4 I/ c
148 A. S5 @6 ?+ K$ _9 ~
15
; K* n- l g4 y& S+ `7 ^5 b9 W16
6 Y x" J1 S9 w5 E+ y17* m! T: S( V! v5 u$ j5 s# E- C( c
18- K. L ?) Z. ?
19; M0 ?4 M/ m" V# E1 b v5 H6 B. F
20/ N1 ^* l5 \1 z2 N) B
210 @2 S& \7 v7 U( S& X7 j, H) p
22
8 K$ l1 N, }( K2 ?4 X23
6 j; E+ k; A3 V24( k( H0 K" D8 V
25! l6 B l/ `& ?7 s: z ]
26
* c. N8 |3 }, Y7 l' R% k8 W* O27 C+ G! o- I5 J
287 M5 h& C$ P( b+ U
291 Q3 b1 O7 _" X- G
30! h" T' w O4 Z1 w& u* q$ a, m
31( ?! ?5 ]+ @, p
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
+ F7 c8 X, i, r7 N% N1 P( }. ~6 Z
* p, ]! Z* L# X* H, K3 p递归实现' f; y: `" h. m! T: u# M, `
通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。; `6 c* |' w5 X. \+ I
& i! l$ u/ u' g9 |7 Q/ M' i5 |8 i4 p
( W) G7 P! v1 z' z6 O
" f8 |1 T# [; m+ s( n
% E% P- L0 A$ ^. Q
void _MergeSort(int* arr, int* tmp, int left, int right)
$ L# ]7 k) }5 ^" ^9 T+ S( Z{
8 k7 {" {' O! q0 ?) X9 M assert(arr);$ @- ]6 A) \( s% q0 _3 H5 K( i$ }
, }; R+ t( {- Y if (left >= right)//递归结束条件不要漏了/ O- i, O: U2 Z# p5 L5 N
return;
0 n3 a4 ~! R( K" {2 [ x7 k; h6 A) J) p( t. @( }2 @
int mid = (right - left) / 2 + left;
& q1 L1 p- A- o- w
8 G# o" O( d2 i //划分左右子区间[left, mid]和[mid + 1, right]
( Y( ]% H$ H7 H: u0 q _MergeSort(arr, tmp, left, mid);
4 V3 n- _9 |1 V" Y; k _MergeSort(arr, tmp, mid + 1, right);# ^, z$ h/ z/ x! `/ V6 \
2 L7 |/ F4 E) @0 y4 A: P //归并
' [" v2 v' |8 b$ @9 t int begin1 = left, end1 = mid;
$ I1 o% x8 U. J) `0 C6 ` int begin2 = mid + 1, end2 = right;
" N% U! L# m8 S i int i = left;! l1 B! y2 r4 m1 }
while (begin1 <= end1 && begin2 <= end2); W2 w) v9 g3 V5 R0 @1 f9 x, \8 |% m
{) [6 ]/ L( I s4 I6 T" `; `; W: y
if (arr[begin1] < arr[begin2])
& G: g3 m# G' s0 Z6 H& f tmp[i++] = arr[begin1++];
6 B& j7 h. C* g: Y. d else
& q1 b8 J+ z/ D8 n tmp[i++] = arr[begin2++];: J! M: U3 u. ~, F( Z, w1 P5 Z
}& {" P0 E/ S N; o9 U
% C5 f6 H% n4 O3 c: s, M while (begin1 <= end1)
6 w& w( H* K& B" {0 n+ h tmp[i++] = arr[begin1++];
1 \4 i6 P7 k5 } s( m2 ` while (begin2 <= end2)8 H. Z0 [$ Y1 ?7 P' q! X- f8 h3 X1 i
tmp[i++] = arr[begin2++];! R8 ~0 @* E+ ~
8 J9 F2 E1 L% m' | //拷贝回原数组——归并哪部分就拷贝哪部分回去% c0 ^: L$ Q6 L6 x1 A
//而不是拷贝整个数组回去. x6 q9 `' [: L! q6 l2 {- k, t
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));. W) D$ H$ |1 g7 P& q9 r6 h7 l
}
4 s/ ]" B: ~/ z' p: `4 w# A/ e; }
6 \* w: E! R+ L6 |8 k; Evoid MergeSort(int* arr, int left, int right)
; k: r7 k. ]2 A4 P{( \$ ~" ~. n) h
assert(arr);
4 k5 h f' \; O: t) R7 c
9 d7 A! K1 r& n, b+ a; ~' X4 e4 U int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
4 s- G3 q. G& w# r$ { U" h7 G if (tmp == NULL)
- G, M8 l4 Z+ y- B# [# B$ y+ S {
. _! d' j% {# r5 L# |( w9 W3 L perror("malloc fail");
5 {: n$ A" u# P5 { return;) c$ I' ?1 n3 S a
}8 {' l7 U7 k/ H2 @5 T% M) L+ F) H( E" j# A
8 U. Z$ u2 l3 H, F9 L+ ^ _MergeSort(arr, tmp, left, right);" Y9 X& h# @5 K7 D6 q
4 L7 J6 ^6 U7 D" ` free(tmp);
9 H- k; k3 u+ O) k; i5 Z; C7 } tmp = NULL;9 P8 `2 Y8 A; ~& i( a
}8 [3 p3 P- J2 S6 E3 f) j
6 I7 V7 m' {) S$ R1 O1( o: {# a( w, T" w( `5 t7 Y
2
) O0 O) D* ~2 Q- A0 J( H3
7 S/ g5 V( E' L% u R; j; W, d$ c, b, I4# O1 d+ r; ?9 S: Z% x
59 a; E& j7 R' F# S( g
69 K$ p: w7 T: M3 a8 g
7
" [% n# S6 o' [7 z$ C( b8
% k9 h' u8 u! f2 e, J+ d7 W9
. C$ w' _* L% y& p7 W+ f; d101 p( S7 M2 y7 X- L; I9 N
11( W2 W( J6 T" r6 V: _+ E3 R
129 J( J! Q- ?4 b/ V: s/ N+ q
13
+ J' h0 Y3 M: E5 D# \- P; n14
, Z; v* d1 ^+ c( \% N( c153 I9 `8 G) m5 \& o, _. }7 z
16. E; K4 C8 q$ I/ U. @
17
0 P) l, S! t5 q! r18
" R6 F* T% A* _% H7 I7 {19
& Z) U( ^, i0 _% W/ y& V207 _/ d2 D" P4 \
21+ n% x8 X6 K* Z8 n% t
22
, P& X# Q: e2 @" O( @23
6 Y$ |; \' Z- E5 V f248 Y$ R' _7 o* r9 c4 d
25
/ E# m, g) R; |' p+ \4 y6 V' q r% n/ W26
! I: e* Z9 q9 k3 b27
/ M8 }6 j% @: h$ {& ?; T4 A28
; ?" e7 X! e% |& w+ E# d2 k29# Z$ a4 V2 c8 _8 j( j9 x' K: s) n
30
$ U W8 @7 k$ J6 W6 D( h31; S/ |4 L% X% T% ^) ?6 g4 k: z: E+ |
32
$ [8 \5 i' Y9 T7 Y& {1 H33
. M# f/ q* g- E' g9 \6 b e34) p& e+ F) [' K
35
" `* n5 J/ j! R36
& I' R" O0 u# e2 h0 U/ J37. X8 S5 Q7 m" V0 c( z
380 b. V; y4 v: V$ ]& M- @
39) m7 M4 I+ w6 e3 |
40
& L# t* ?- y5 q+ J* h. Y4 g41
: J# O" y8 P% f: o- @9 `3 B42" L X0 z5 Y5 o2 q; D
43
' e0 R/ S. ^! z; Y( v. d44; O8 K' @3 c! M
45
( i; ^5 H5 x( J- }' {" c' u46/ M# u1 h9 l. ~4 s% _
47
8 K$ D& H: _( r4 J/ l9 h488 E1 m$ T h& J8 z
49$ k8 U. [6 u7 G- P N0 w/ {
50! }1 b5 h1 x }- O6 g$ p: S
516 k Z3 s5 n- T: `7 j
非递归实现
& n3 I1 V5 a r' v5 a; @ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。6 [; D0 j% G4 l, d4 Q
4 t( ]" ?& F7 A' h/ t2 `+ `3 s
8 ` `- M+ Q Q: }* M6 w ]) d7 t! e; V! O2 s1 Q
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
, H' o8 g) S: E" t+ m' H0 N* o3 Q) `$ Z: C: J
还要注意区间的取值,每个区间就是一组,就有gap个元素。/ i$ Q( L0 C) Y w
% D: N5 R* r8 k) A, w( g
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。6 F- d0 k2 K; e- }
+ h& ]6 ~3 w: l# c# ?
代码实现! T9 M) L" V. o* Q; c" L
9 w' @, ]1 K; Ovoid MergeSortNonR(int* arr, int sz)
' p3 N% ^/ o$ b: }8 X" y! B{7 i! Q& O7 g$ I+ B& q3 E% O. w, ^0 s
assert(arr);
6 `9 }. R' w3 U0 S2 n5 T5 y" A F( c
int* tmp = (int*)malloc(sz * sizeof(int));" M8 M/ K# m% u; L" s1 y) N
if (tmp == NULL)4 ^. m- _5 f0 F0 K
{
' M$ I0 [+ K- q8 q# Z7 k" R) e perror("malloc fail");* `2 }; f1 b) d; D. P0 M& V( X! W
return;
; k, f) ^: d J5 D0 c }1 e# D3 f* }' R: K9 w
1 I; o4 G; S7 W/ u3 |3 t* Y
int gap = 1;
f' {2 j; {) V, d while (gap < sz)7 X2 w t9 q, N/ I* J. l
{( d& m; ~6 S+ ~, n$ P3 T( @: U
for (int i = 0; i < sz; i += 2 * gap)
$ n( V3 Q3 D) e$ a {
+ S" O/ m5 a" E! S, [6 ? int begin1 = i, end1 = begin1 + gap - 1;
, R: Y& t6 C* J: I int begin2 = end1 + 1, end2 = begin2 + gap - 1;
. L3 [# h- s+ A int j = begin1;/ O; b( ~6 B. e- I6 O8 j
6 B# I2 J. g% f! D
//归并( @ [8 G7 T, P# z: i8 U) A
while (begin1 <= end1 && begin2 <= end2)$ T3 S R; k' `. K+ F' q% r5 b
{& h) r6 B" [% Z V, ?
if (arr[begin1] < arr[begin2])
. Z n7 P3 p$ v5 B tmp[j++] = arr[begin1++];7 `1 ]& x" M) t( w& c9 ]$ Z/ Z
else
x7 b5 K! I! n# D1 x0 _ tmp[j++] = arr[begin2++];
. k# G* q& f! ? }) t' Q% H% S# i! q
* A. J0 g$ w0 _7 l while (begin1 <= end1)
' W; Y# J1 A/ i- w. ~4 e7 g6 m+ U tmp[j++] = arr[begin1++];3 t& w/ {. n+ A1 `& }+ K7 p$ u. V2 I$ n
while (begin2 <= end2)
7 y4 m1 N6 p7 D& ^. d& d3 M tmp[j++] = arr[begin2++];
: D, c; |! ], n0 [( N, O+ V; `$ u$ [9 ]! l# r
//拷贝回原数组——归并哪部分就拷贝哪部分回去
! f7 ^- c7 C3 w memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
4 l- g3 Q6 j5 j$ J& V8 x }6 B/ [' J& k$ ~% F# A, w
gap *= 2; a h! f4 X; Y+ v/ Z M; [
}
* J/ `( t9 x% P! u& q1 K; G* d5 w4 @% d, m" w4 I" a' f( B
}
* G* o9 ^% j7 k. n6 }) }0 n
6 f# K, s4 ^. P1 V! x6 b4 u% {1
2 {/ d" M2 I, b' B9 G2# J( H! A: u* L, v$ e
3& k& R' ]5 K, q- Q3 U/ }4 x
4
8 k+ r" k! W/ e5 ?5" R* _- M9 N, I" ]/ R" F9 z$ H1 e
6/ a% K5 j( Q8 E
71 _9 L7 Z7 }6 }( j
8
2 \% F: {+ H$ r9
4 w% r& k' k4 [0 e6 |10/ H. ?( O9 Y0 B# s/ a( Z; l
11
# V# d+ N, g) s j, D2 J12
% o: ]5 _, H3 `: P0 E9 l/ f! s133 z& q. R, J3 {; O1 m) H
14
% G3 u# }! e$ n( W: Y& T# |15, R* W3 q# o" g) e
16
' U$ x9 _" H! |) y( `17
9 N- F+ J8 m! d+ Z% q- e18
! w/ P5 \. Z* q2 ]19 a' A' i: d0 r8 {5 ]% t
20" }+ }& E; l6 \( r/ p6 }
21
# T8 k4 @3 @# H224 r+ e) x1 e& K. _* i% p
23& R2 O* v/ w7 f3 W/ W. I) m7 W* v
24
6 x* J. v. ], ^8 }+ A25* H( r L) n$ r4 J" U" l
26/ Q9 T3 {0 R8 n" b( ]5 ]4 k
27: b5 G' T3 z* W# k1 v4 x
28
) N, S8 J2 f" n$ r7 G: B3 L29+ d" }' ?. i! s2 C( Z% r
30
' E( V3 L" |6 x- ~1 _$ a6 d4 F* i311 y( _2 t$ J' V
32
: C* q, L. l; R2 Y33! s2 I' n- z; e e7 a2 e& C" P, i
349 W! F: U8 A! b; e9 }: j& W
35
" B: A2 J7 D2 e# S! G36
# ~1 _% Z$ V; Y# ~8 M37( R% A3 J& W, E A: i4 [ M
38
- M; Y* I1 Q+ W$ N: s2 n$ ~; ^% `39
" {0 R" W% V5 m404 P% z* H' X1 g" N+ ^; ?% }
414 Z4 a' d2 e$ Q4 t) D) ^
边界问题% p7 Q# y1 [0 B9 T* d8 f4 A
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
! v) `, {9 I$ }! S& n) X& `3 K8 C
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:* } n% l' i4 k- P# e
; p1 e" M( i5 w# p. A. }. H: I
& S2 h$ B! j# ?' a( V" |0 W, D4 v+ {& V. Y) x* X& Y( A% p
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
3 L9 j3 {* x" Z6 y$ z5 |/ b5 h5 D8 p5 i8 j G7 D5 H
第一组越界(即end1越界) Q4 A( A+ a1 f& }1 e& E
( N, m: O- x# Y3 e" H) E; K应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
f& g0 v% i' ]: X' G6 y
/ A8 N& k# Y4 N. F) Z$ ~* A第二组全部越界(即begin2和end2越界), D- C' W; C7 r) }4 t3 P: U
0 ? S' }5 I) Z. e$ N3 D3 E/ D应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。; \- o7 L `7 V9 a
- ~, z$ q: k2 S" ]1 ~& v( B# [: C3 ^. D
第二组部分越界(即end2越界)' I( F6 T) o6 p$ ~7 P2 {+ `
* k' h3 }* _: x2 V* a* `
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。- } ^6 Y/ m" L# Y/ @; q. Q
: j1 Y+ Z: m! N' C 其实第一种情况和第二种情况可以合并为一种情况,原因:
5 C" |0 @8 O3 Q/ d9 N+ ?& d) |$ x
end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
9 F; L( @, j/ ~* _1 `) Y5 f" f/ m+ }( T# q/ Y4 r, L5 J" r% p$ C. B# p
拿两个数组试一下:
3 [9 b9 [1 j/ T$ |( |. P: A
) c8 Y+ p) S) G9 Y4 F
: j; G' ]6 }9 K5 u' `9 q
( |- w4 }7 k% {9 K" o# Q+ z3 W1 C4 N9 N
+ U! i' B5 ]! e( i0 @/ c' g2 a4 W- e2 V
代码实现2 Y) T* c- p8 R7 ]
6 f, I6 a2 k! L" l6 O
void MergeSortNonR(int* arr, int sz)
5 F7 L% z- Y1 V7 Q4 N{1 i) E8 S/ i$ A' ]
assert(arr);4 [5 C5 Z) ~( [- C3 X
7 k# z8 [' ? P# V, M
int* tmp = (int*)malloc(sz * sizeof(int));* D/ Q! g2 N- f4 G2 D8 G6 e, q4 t
if (tmp == NULL)- A* V+ C* U' i5 A p' b
{3 ]4 v/ R- {2 C' Z
perror("malloc fail");
: @ [: ]' ^' D0 X return;. z$ u% n. H" t) m
}3 X% D* z; Z" G% Y5 A! p
* I S; V, e2 M+ c! @
int gap = 1;
2 M+ h3 ~+ s3 g# Y; ?) w D9 C1 N while (gap < sz)
! Y" t. E' c. L8 M! a {2 \- a: A. F5 U) Q. j. V ?
for (int i = 0; i < sz; i += 2 * gap)
. g) O1 U( Z; g( A* b {$ ^% J4 V" ~2 H. z
int begin1 = i, end1 = begin1 + gap - 1;9 M. ^, o6 h7 m0 P4 ~* [0 z$ O5 w. J
int begin2 = end1 + 1, end2 = begin2 + gap - 1;: b. o, k- F/ ?* x
int j = begin1;: A; i& B% [1 s: k
//越界检测
2 @1 y& H9 {* N. a; ^- h" A9 W if (begin2 >= sz && end2 >= sz)
3 [ X7 c9 B% ?6 S7 F2 E break;
5 {5 c( g# ]1 [! Z if (end2 >= sz)* N7 X8 a% R8 f o+ Y4 U8 y8 P
end2 = sz - 1;
/ P# I4 Y& @$ L //归并" ?& ~- \* Y2 f) R! G% S1 R
while (begin1 <= end1 && begin2 <= end2)
- x4 J8 t( ^3 g' o" F- F {1 D1 a S% m" T( `
if (arr[begin1] < arr[begin2])
0 b) j: k9 {# K" Z: t; \ tmp[j++] = arr[begin1++];$ s" H& X$ M; w2 B
else
. {5 |7 G, |* P$ o' _3 r tmp[j++] = arr[begin2++];
) N7 J7 ~: V/ ?- l* e }
' u% L. c& t, }3 m0 f: k% R1 L* A( n5 d1 ]' W. |' c% x
while (begin1 <= end1)* M1 R+ A m% v$ u4 R6 k' S
tmp[j++] = arr[begin1++];# b* L$ ^" q- Z" A: O! B& r6 ~
while (begin2 <= end2)
% c4 r. n5 m; `( ~- i0 o tmp[j++] = arr[begin2++];2 r( l: _9 |& s
0 @0 {9 R, c& V4 l
//拷贝回原数组——归并哪部分就拷贝哪部分回去" M* v) H8 p) E- |# C# o A
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
. Q1 y+ W( e+ z# c }% l c( w: X: Y9 D0 p! |# d% X
gap *= 2;2 q, b' s) e+ |4 Q
}
4 q, N' C4 s+ B" d- d7 V2 }: a
# a7 r) o3 A9 n}
* T6 X' p8 F% V4 f; y3 _/ w( N1 H* P- e
1
6 G/ c: h0 M m+ e( I8 ]1 |) v2$ I! E2 J" d* e- S; u$ H- `
3
6 v. |$ r) e, [: L! x44 Z, a7 p* t/ Q
5
1 V& s- p+ |) F6
, z; `; l% t7 q; Q7 ~* z Q7! U# N! i0 h3 I+ ?. _- ?
8% g, E) c# f e
94 \1 y3 c1 m4 E! S
10
7 }3 t; H8 l7 j y, S. q8 x115 V" h: ^# `# H4 @6 m; Z
12
. @" x) C0 I- Y D& f. N! I2 }: Q8 d13
. o# G: p3 @6 r/ |* ~) s3 p14' A3 q2 U/ [0 O# a$ z
15: {9 i& }3 d* D3 p
167 q3 g, P9 N* A/ V2 H/ ]
17! l& o: K6 b7 |! A
18
% ~ ~+ S1 J) T2 |5 [; w19- O4 W0 l4 c' w1 o! O# Q- X. H
20
/ r; ~0 B4 }7 i, f211 e" s( C6 n4 r3 M
22# y3 P/ W R% `) ]+ B2 {$ H7 g% I
23
+ p( X# \, ~& V3 E* q; {# g24$ g* A+ r/ A+ f! `1 K. X
25
. H) Z- M. t4 c& y265 K" T) e5 A H% K0 e
27
8 v2 w& ?- i: C: l5 O28
; l+ x8 J$ y, r+ B4 }29
2 e# G# B0 C( I30
( `+ m5 G2 [" C3 d) r3 i+ o31) o* G( @% `, S& @2 S( _
32
1 f7 A1 E7 @: g- Y33
! x& U* \( k( m& q: |( d7 U' O34
5 \6 f# H! L4 V# n; T35' r4 `, A* u9 M' C1 R
36$ O. g0 n! x# h( q$ r
37
) U B: u0 X( T" q9 g9 c38* T: q* ^+ e! M% o7 D# a" ]
39; g+ C: Z- }$ Y
40
g/ e! B: @+ V/ t418 a2 f: n) L+ J7 N' w
42
4 D% | L' B0 j; O43
8 S m1 S: s. v44' F' Q5 m' d& D9 c: t" \( Y; |
45$ a. c4 d! E" N' h9 L: |
归并排序的特性总结:4 l- M7 Z* |- \
, ?" P/ E' _2 E; e2 I5 U/ ]9 j0 `. ]& `
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。2 `& Q; p' g o5 ~
时间复杂度:O(N*logN)1 h9 s; c0 X6 A# a; y
空间复杂度:O(N)5 K% ?% r$ i+ S
稳定性:稳定
/ t$ b! t. P4 a# K* j1 y% C1 @* ]6 R' U
————————————————
5 p# h: ]! X4 Y版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
. d/ {* h" P) X* C7 ?原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657% Y4 ]$ S& P6 C8 B! ?- w
+ Z1 F; X* X" S' a
& q' [9 L$ |1 A- m2 c# X& L
|
zan
|