- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 563413 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174247
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序
- `3 t8 g2 A* X8 f+ S# w' A! V* A0 K+ \3 r$ j5 t4 ~5 H0 m* u- \
前言
) {0 ~. Z! B d本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
$ j8 B5 d$ N7 e9 {; k- b5 `# T$ H4 X& n" [: k
归并排序: p2 X. s/ {' N# Z8 e: q& f5 V
基本思想1 L) p5 a4 M. q9 c( G V9 x
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。3 h0 G$ Q/ \+ R- m. b7 l6 a
0 g" Q( g* e0 c3 Z; W! ?
( C2 M- v; m* a H0 Z% \
: x' M" O8 d3 U" W; c 合并的思想其实和有道题目的思想如出一辙:) p: V* x9 U0 g, y9 D- p' X
( B' S) ]2 ]. w3 a9 ]
4 _% ^5 i) a7 T1 M8 Q# \' K5 x: W( o9 ]* A3 h( x- Y3 A: w8 i% d. n9 T
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。2 D+ `) g- u3 d& Z( p+ B
% y, X- D( w! z; t
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]9 N( l) p5 J$ F# P
; Z1 _& ]" M5 E4 a& qint* merge(int* nums1, int m, int* nums2, int n)
+ S- P7 B/ \0 c; V9 d% E" o F$ U* s1 V{5 C- h$ `5 I5 L) K/ J6 z
int* arr = (int*)malloc((m + n));
( O; v4 V5 b6 G' D y' _ if(arr == NULL)
) C: v3 |; G8 D: p6 G# @: ~% n {+ L) P; C: @/ w: ]) E; d
perror("malloc fail");* [$ T: u: B+ Z
return;
% t1 v0 e0 I2 _8 ^& B. D3 I }; z( P# q! i! I0 |9 r" M2 W% k* R% L
- @8 D6 I: {) [/ F4 |0 D1 O int p1 = 0;7 c* X+ x0 v2 W8 ?& B
int p2 = 0;" R: d& g. t5 \4 _5 L, e
int cnt = 0;
+ G0 W9 O5 u$ O l4 `, ^ while(p1 < m && p2 < n)
2 g. K! i, {" ?; a5 h) U& x {
|- e$ d( o) k; b1 x if(nums1[p1] < nums2[p2])1 k# G, U" s* W+ f* S& U/ M0 g
{
" _/ s4 ~- r+ W; K( ^! {5 @/ r$ W2 j arr[cnt++] = nums1[p1++];
- W% |& v+ i0 R3 W! Y }
. }2 P- u/ u7 U/ J' `" i! } else
: {( m1 [0 q0 O1 i1 w" h' p {5 T+ g% e: z) ?/ R" k
arr[cnt++] = nums2[p2++];& R& |; B( [9 h* p1 ^) i
}5 f# S" A4 t! Y/ ~; d/ H! u
}
. @% |, Q0 F* x; [5 b while(p1 < m)
5 j; k r, E0 i- \ W ^% z: S, @ arr[cnt++] = nums1[p1++];
z9 z" _. \5 P) U- c6 K r" D& M: ?1 _4 s1 c0 O
while(p2 < n)$ M* F: \, w7 q5 I0 H
arr[cnt++] = nums2[p2++];
6 F( A1 D, |0 ~. |4 ]4 H: R1 N0 k: K3 i$ }3 ?3 A2 }
return arr; e2 z7 A/ e L, r! o
}
% g% h0 s8 v1 c" V0 t: {7 S1 K3 Y/ @/ y
1, X* @& T# P/ C. d
2
[- C0 y7 t' i: u+ t/ f; w. ^34 _$ u+ t m9 Z1 `, F$ ?* h( U
4
* B2 H$ h$ P& F% V' Y# R5
$ O Q2 w p: _& u6
& f7 }# h3 c: \1 }6 B, g: h/ o72 o2 A$ V ^: z
8
4 R6 {+ h$ K0 ^2 D4 q/ Q* T% V9
) G2 U1 Z2 s1 ?( @# l108 w. @) F0 S) s) I
11+ t9 M# V- [1 v/ u7 N6 b/ N
12
5 T+ x ]' K3 M13
/ U& Q6 N6 f9 k8 K14+ z0 z7 v9 y# M/ i
15
% w; q1 Q6 c/ A. z/ M2 o16
. ]) q$ z$ h& b) S1 c, r17- l- G& F: o- S
184 P8 S# u# Y; p
195 F0 z. N$ w7 o" O% B# I$ p
20* Z) }( C, ~5 Y0 A' }
21
7 c7 c2 J6 u# S. {! S) b7 I3 r22
9 r4 u4 G" n+ G: f" F/ ]23 f8 U7 u# q/ G3 i: j. h8 F; S
24
9 Q8 ?0 f# P0 S$ @, r+ m25# J* k k8 C9 M" {2 x9 V
26
& X3 t# D' M: B27
7 [5 O' V0 j/ N2 l28
/ v# D: d9 u% S+ j# N295 H% T9 B7 I+ w& I! G
30! x6 l F: w E) I) G2 T/ N& v
317 F8 C( |+ Z0 G' u8 j4 u& E* p
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
: ?, L" G$ O. }& B7 p& h2 G! L6 |' O" M
递归实现0 v; z; [/ l } k) _/ l5 d
通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
+ r4 _: Q6 {) e& @+ l
9 U/ }1 d" S! ?, z/ q" U- Z8 V1 Y$ ]6 c% z/ L3 u
4 Z2 m$ a4 d# \( K6 O1 S' J! X3 t# B3 e& ?% u0 T
9 G/ g% m; s G4 ~7 V* w! Fvoid _MergeSort(int* arr, int* tmp, int left, int right)- H9 e: r4 D3 M& m4 [
{9 \9 Z3 t6 F9 P' o
assert(arr);$ T( O9 U# n7 g/ h. A3 U5 ~
2 i5 h" j! }0 I6 [3 C* g* u
if (left >= right)//递归结束条件不要漏了
) C" E4 M, d1 F7 P" U& \1 c return;8 G2 r6 {2 S, ] `/ L) P5 X
! R/ O4 |) w# `' U Z# K7 ~* e int mid = (right - left) / 2 + left;* L3 C) { ?" @9 z! c+ y
. @; W! W! \1 E6 n9 @: u5 V$ l
//划分左右子区间[left, mid]和[mid + 1, right]5 N- S5 }' Y. A0 p3 \
_MergeSort(arr, tmp, left, mid); A# z$ m: P. f7 Y7 I2 v6 `, f7 q
_MergeSort(arr, tmp, mid + 1, right);! L/ |& I- h) Q; Y
! k7 q/ D2 ?- X" p# Q4 Q& O$ u //归并# O6 l* O: t z- g
int begin1 = left, end1 = mid;9 a# D6 V3 b/ g1 R! X
int begin2 = mid + 1, end2 = right;
& y% B' o6 w0 N# J$ a4 t int i = left;# M h( o3 |% Y5 f2 c& P T9 K
while (begin1 <= end1 && begin2 <= end2)$ j9 m: H% Z' A! @! D
{
. k) z4 ?0 e- r if (arr[begin1] < arr[begin2])
8 N8 @+ R) i% O; u q tmp[i++] = arr[begin1++];
7 p5 j6 I9 V, h# } else1 `& e% n& p# K8 V% w4 }
tmp[i++] = arr[begin2++];
, N# M; \& ^5 N% j# z1 B0 W }# H: _- i5 l! Q! w% U; n' y
0 O# M& |! X/ v* m: F
while (begin1 <= end1)
1 K6 H' \0 @8 ?. J5 w& ?3 M+ Y tmp[i++] = arr[begin1++];
- E" ]3 d- ~, v9 a; \ while (begin2 <= end2), f- D! q% k* m: W- M. y6 d( h
tmp[i++] = arr[begin2++];! H$ t5 L4 D$ D# x
1 ]0 b- m$ t: T8 i; h$ P //拷贝回原数组——归并哪部分就拷贝哪部分回去 i+ W# M2 T; b# L5 S- F! b0 v* h$ q0 Y
//而不是拷贝整个数组回去( o2 p8 q6 }5 n" y, W
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));( ^3 q& S$ @2 C0 B
}- q2 w# K6 t2 z9 w8 W* A* k0 u( R
+ [3 D% [7 i% W7 |+ g" A, E0 L' J f
void MergeSort(int* arr, int left, int right)
3 I& y6 u1 ?( x0 L- d, o{9 ^0 @- O/ }2 t/ z% X
assert(arr);
U/ X# h8 X# ~* G# `2 @
0 a/ }3 O' x' J: N- k8 B int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
( A( i* }- e$ X4 j! ~ if (tmp == NULL); u0 q7 e* l( E- L' O
{8 c9 F' n# Z9 f, t9 Q+ l* b
perror("malloc fail");
3 u, @ |! R) [: M( |) D return;! P, j: U4 [( \4 u' \5 r
}
( \ L! P2 x* P. f6 {, r3 y" ^: o; O* `7 g
_MergeSort(arr, tmp, left, right);! N P% {/ L5 y
" ~. M0 H: S8 x" w& a5 U- \
free(tmp);5 T8 @4 o3 [9 [" H5 O: m6 c
tmp = NULL;
9 d; @$ J% p& E0 X' N6 @}
/ @0 w+ R+ B; M' z) L+ g" F
) v( i! F/ ^$ {6 p$ k" Q& F7 F; j @1
$ V0 }$ N& r0 |& z6 m21 |* e; B% s0 i: H$ I/ I0 J
30 q9 d) E4 h* L
40 h; B; Q3 s" N+ F3 ]$ K1 B# u7 i
5
2 D+ {2 Q2 j4 z2 e6
' J1 v4 Z* g* I) v7- b1 H- I) k( |1 ]* \3 v% d; K4 G
8
: W# x) S$ Z" g" `4 t) l( m9
7 ^: D. I; u+ f) W10
, @5 i, S' t. ~' O; p11/ ]& o( | P0 _' @
12
% J+ ?5 w0 ?- n# p' W" Y" W" s d13
% s/ ~, r9 k- M* O% ?$ Z14
* ^# M w8 g; a15
8 x- g/ B) m( R" W* ~) Y8 K* {( U7 a16
; `1 k1 P! I9 _% Q$ a17& G. a# ~ k- V$ W
18
6 p, J, S/ U! Q. a1 X8 Y, \19
; K& Y) u5 w: }, k" _. x20
, ?4 G' K6 w3 D! N3 ~3 T. `211 Z% j* }6 ]4 T! ]7 r7 z/ x
22& K4 C6 T& r5 ~* W
23
! s$ t2 l9 J' |5 q7 h W/ r24
# y; r9 o+ b: M6 T25$ G0 y3 u3 Y2 X1 t' s+ Z
261 _4 R9 A" k5 O: d- x
27
/ \! |" T# k! }1 v4 \8 l28
1 v h2 z" Q; _- Y8 r29" C+ A4 B# h. h' U1 H
30
9 s0 ]) C4 K4 G) |' V! x4 C! p31* j: F8 p" m0 K, O) Z* k
32: I L9 N6 Z9 }0 c# J0 H' I
33% G) u5 a* h" N$ q8 v/ P
34
+ u2 D9 i3 J8 ?6 n35
$ l: A8 Q6 G8 o1 B/ N# h, U1 d361 k. }/ m$ N, z1 [ q
370 g# [" q1 ?) C& k+ S: E! p+ {
389 _$ V" G% q4 _
39
. }( a9 A$ I+ F- G" C0 k I40" a, ]9 i/ x3 G+ C2 l( w9 Q6 {
414 \( Y' m/ O' @8 \: R
42
k0 i2 @2 X! _. W436 A2 x- O0 J. K$ p4 I/ R% J
44: c1 t; @3 i- S! ^
45
6 v C0 o% p" O6 f* m4 W( [6 f46
: c. y* {6 R: z j; o0 i: h47' L0 W0 W. T9 h6 s. o9 y
48
9 l; ~, ], M( G- e' q& K& x49
8 s0 _& T% A* r! j% Y9 O50# S* B% u: g: Z. d d
51
1 x! P+ p3 W7 j* m非递归实现
0 W' N- n4 r. S5 t2 b6 g+ h 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。 `6 a# A Q* p- m( i
% q @, f! |) Z8 U3 l
- c7 C' C$ g" p: X! x. | z
" Z N F2 M0 b 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
/ A2 G8 _( R9 `% ^" S4 V( `1 e' G7 g/ c+ A. t( D
还要注意区间的取值,每个区间就是一组,就有gap个元素。; w [' H+ C* e5 F, X; ?% g) Q
5 U% u* }" k6 |0 H! Y5 l& Q 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
! G: A8 w0 t0 u8 P& A0 c, [2 k, U5 H* H4 ~
代码实现
" H" n' E b4 ?$ {
7 K9 B9 Q2 s% _( ?void MergeSortNonR(int* arr, int sz)
" A6 j% G e4 n/ ]! |% T' n{
3 ~9 t4 L9 V0 X% o" m' f assert(arr);; H- a) ], \# b9 ?/ J% i
+ q" B, d" M, T3 e' E, X0 t: G3 T int* tmp = (int*)malloc(sz * sizeof(int));! j7 G( N9 y+ u' s2 _+ m
if (tmp == NULL)7 ^8 }/ h2 }( \; H; g. ?7 r+ ?/ O
{
* }8 T* v$ O' L) K0 `( o8 O perror("malloc fail");
1 g& \4 p! z/ p$ y4 K. X return;4 [, A8 c( u5 T. I# X
}) N" S7 ^, | f# [2 M/ ~9 X' Z
/ r6 y5 k5 X, \" J0 s
int gap = 1;
2 S/ ?8 o& j3 m% o) Y3 a while (gap < sz)+ w8 h5 P$ A% C! ?/ P2 {: Z6 p
{
3 U8 d7 F/ O8 r. f' ^ Z9 f for (int i = 0; i < sz; i += 2 * gap), G7 @2 n/ T4 D4 g- g
{
) Q6 Q% e5 i5 U7 @4 H int begin1 = i, end1 = begin1 + gap - 1;) l8 [! @" ?$ o* F; d* J2 C
int begin2 = end1 + 1, end2 = begin2 + gap - 1;' k. h0 k- e& ?8 _
int j = begin1;7 R7 u% B# ~) n
- `5 Z( V5 h; H9 {# U
//归并
0 H4 Y# e# k. ?6 p9 u0 P while (begin1 <= end1 && begin2 <= end2)
! f8 z: L) y$ q7 ~4 Y, y0 p {, p9 `, T: i; R5 k, ]
if (arr[begin1] < arr[begin2])1 V8 N9 h3 N! N6 e% \2 W+ B
tmp[j++] = arr[begin1++];
0 x l6 P4 r$ Y& d0 r- `& m else
3 d% f6 f6 S& ?2 R3 p2 j tmp[j++] = arr[begin2++];
9 ^5 o6 i( ~6 Y- A4 R. ]( H }% [; M7 k7 ]6 m
. Y, i7 ~5 K& J0 J6 D# U W while (begin1 <= end1)
: B" Y2 r5 t+ o3 }/ r1 ?0 o tmp[j++] = arr[begin1++];0 O! C# |2 {& y/ }- s. `3 }" e \* A
while (begin2 <= end2)
) A5 {) A/ F0 _# D1 g/ q tmp[j++] = arr[begin2++];' z# k$ c# G1 |
/ D! n7 G3 T; A- z4 k5 d
//拷贝回原数组——归并哪部分就拷贝哪部分回去
- e' M5 p9 p: n1 \3 s4 @ memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
h8 L* i& |/ g& n1 d% l }/ E; E9 l6 _1 g' X! c; j
gap *= 2;
9 O3 V; D2 Y% a& \& d }
* C" {6 T: \, i" B$ r+ s( B$ O: j# R! {' a' {! `
}
% F( c9 E" r) Z; l# w. Q& b
8 B; Q# K% m5 f1
8 \# i8 B! g4 o6 ?4 e/ L8 |7 D! l4 M28 p7 \' v2 U p9 ?0 P* u
37 a; l- U. q3 h; s7 u4 N2 [2 L
41 c# l/ ]( `0 `# a4 L7 D
52 |! |! ~5 _% Q
68 M* { K/ C8 c% n8 d4 L
7, a8 p. i+ Z9 Z. s9 n
8
0 ^5 q1 u$ k3 a9; Q8 ]# Y6 D8 M( }- [" |" e9 s" x
10
$ F# _( m, ?+ `/ R" J! }11
7 B; C. |" Y- W( N6 ]9 V2 _12+ @1 Z6 S6 x4 F4 a, f) Q
133 K/ J+ ^1 f, c, c6 k: }$ @
14
# X1 g/ R; D# F P6 s: p$ x151 N1 s3 f! ~3 Q/ ]0 g0 u+ p
166 v# x/ H" p& K, i; k2 r' Z# Z; G
17, G2 N: l5 B4 F- a9 y7 t5 s
18+ ]( u3 M* T& m6 w5 L7 Q" v* _
19
$ q: e/ m }+ C2 ~5 A+ W20: m- v# w- M: B% p, K
21
! m( U( |; J- Z7 q- u( p229 N; u3 D3 o0 J" z( I$ F
23+ m9 k" u" M8 l4 d, h" m
24& A+ S( ]* g& {4 ~- f9 F
255 l- L; }6 Q S
268 H @# C: I- y7 y5 C! i z
279 T9 Y% [- Y4 @: L. A6 V' K, l
28
, o I( i: b( N& e3 d! g6 E+ S29# o( ^8 O8 w) ?
30
) a# C$ U9 O5 s; A! o31
- ~5 c. U8 F) V6 @$ h, P, J c323 H% a' E" `3 N' B/ u" e1 K! l
33
/ o# ?0 ^6 e5 j8 p+ w343 S) l7 ] S2 n1 I! O: X) ?/ F
35! Y- x! t6 R( N6 K2 g
366 n( @8 v. t, ~; [
37 @+ }" }- m& k3 ^3 ~
38
' x5 w" H% c/ \39& s9 P. W- o( r6 w7 G; h
40! L q& d( H: F& h
417 t9 T7 n* d3 n/ H6 i
边界问题
/ S; S) T$ |% ]# D* k 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。3 ?/ U$ {+ Q# X
" `! O1 k6 _( N! G- y举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
8 Y: m/ f& m0 p2 M" e5 q. _7 v) r2 j; x- I
& n* y$ H* X2 n% o3 e! G
# c" W# T v/ R* x: q6 l' N
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)" k2 L9 l1 K: z) A
8 j6 Q- ?( w6 Y9 }# W
第一组越界(即end1越界)
0 w( ?2 K; |5 F' r9 u4 `. R/ e1 ]' X/ v
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。, t1 \: E" g. b' y& k% ^6 N
& \' F3 p1 x# ?0 y第二组全部越界(即begin2和end2越界)
- T- e% E4 Z( X5 R$ ]& {9 e2 M9 x9 e+ T
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
( q. Y; Q% w1 \( x5 J* k' P
- U0 ~ ~7 B* l# F3 L- G第二组部分越界(即end2越界)( ~; [2 N' |% A/ }! g: Y z$ N9 r
2 X, L0 l9 [/ }' {2 l应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。$ |8 e7 S& v. D% _, b- S
: X1 ]. A% j; B" t- s1 M- h 其实第一种情况和第二种情况可以合并为一种情况,原因:
/ _8 _4 w: k2 |: q0 ?2 C: X; d+ `5 l. k
end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
* M2 G$ l6 N' j( H: m0 D, Z+ r# L0 K) c1 ^
拿两个数组试一下:
, |, V- v* E# Y- D" \3 I* B0 `! M% A
m3 L9 y3 t6 @0 f2 ^' N) t: y
- z; L* {6 E9 g+ U
6 j0 }. _+ n2 C3 V/ D1 v
6 T" u9 E4 ? k' ^& E' V# _: p/ c k$ d# b& k9 L# n7 a; n
代码实现0 K" \' `& y6 @; h0 U- i, k, U
* _7 A$ R6 m$ tvoid MergeSortNonR(int* arr, int sz)
, `; F% A+ _8 K' U6 @5 w. C{
" `7 p. Y* H! r3 R* d assert(arr);
1 E7 v+ E: {: ]: ?( ~! x8 ~$ v( ]4 P" V3 O
int* tmp = (int*)malloc(sz * sizeof(int));+ ]/ m( _- Z# y8 F! r. ?
if (tmp == NULL)
& W7 r) h5 J1 Q `) G* g {8 Q' |7 [/ Z; w( g X7 T( v/ K
perror("malloc fail");
" L2 A- o! \$ X" Z; v( y( n# g return;
. A' \- b+ P/ g" N- Q3 W }: `. ]* K; k) C! r* w0 I
5 a6 O& K; J2 `% f int gap = 1;
$ j& V4 [- z- y5 v/ f. G while (gap < sz)4 N0 m1 t- S: @1 i1 L
{5 P/ o/ k8 B, q- M" C9 e( }
for (int i = 0; i < sz; i += 2 * gap)
; n* w3 _2 Q- \2 ~- x7 m: s: o/ o {* ^( @1 ]4 T6 I
int begin1 = i, end1 = begin1 + gap - 1;1 {! [6 D* q* G9 O6 O7 C
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
$ `) T( n% J: M: V( f6 J int j = begin1;
: v5 ~7 U$ [; K; U2 I$ v1 C7 u //越界检测4 L5 z: j" x5 f$ r3 g$ c, O
if (begin2 >= sz && end2 >= sz)
g2 F2 j: c S' ]& y break;6 g' U! ^. L' A4 A% c
if (end2 >= sz)7 b% ^+ D% S+ a7 @
end2 = sz - 1;
( k5 }5 {6 u7 `7 \ //归并
. A! k* ^' Y9 p8 X while (begin1 <= end1 && begin2 <= end2)
' l8 A' f* X+ M. W {2 N3 Y7 `7 n4 J. G% H9 j+ L* f
if (arr[begin1] < arr[begin2])
# i1 [: o' q1 }3 l tmp[j++] = arr[begin1++];! [3 ]& b2 Z3 e7 C
else * k# O9 } B" ?
tmp[j++] = arr[begin2++];" \" U! v0 p f. z4 b0 x# j- ^7 q- P
}
5 r R S( ]2 }% ^3 W1 E: y& U( [
0 T: S( M! l0 k* |5 y' [/ ? while (begin1 <= end1)
/ g; Y4 u7 p# h; l3 u tmp[j++] = arr[begin1++];2 |5 w( a) I/ O K( D: @
while (begin2 <= end2)3 \0 j1 q/ x, U3 U
tmp[j++] = arr[begin2++];
! j2 ^/ G$ H& s- m% d2 i) a, i9 m! {2 @$ S+ Y2 _ M( M# I' h
//拷贝回原数组——归并哪部分就拷贝哪部分回去6 r- H% `5 G# W
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));2 l5 u9 L- {: {" \6 s$ U6 |
}0 c/ l( v4 _+ i
gap *= 2;- M. H, C' `& o, Z
}
& p* ~( R* j3 U5 o. V
& T0 n, [- U' P, T6 c3 d6 {}4 ]: K, a' D- G4 c& O* @3 v2 q
0 d1 s$ [3 S3 w; x+ E8 a12 i( e7 C2 o4 ^" e$ g
25 l+ @5 q$ g; \5 [
3
. S' M# G6 s: `4
# l& D+ F& Q( ]) a+ R53 j! d$ ~& O9 c$ ^0 p* _
6
6 T; j9 }# r& Z- W9 d; p9 i7 o; F7/ P" D8 g/ a( ^" g) \ w6 ], K- V
87 A8 z9 C1 E4 S$ X7 ?
9
% o9 B4 i/ B; I) @10/ w" G; g& p7 ] H$ y$ `! ?
11
8 W* {/ j* ~2 V" B! A12% G- V0 |6 d# Y5 u
13" [' m8 v; t# n+ H; G
14
; N. }3 K' A/ y7 p) B15$ O; h1 y+ b- v" s. Q
163 h& U* D$ }* F V7 }( P1 |2 G
17
( Z9 a% d5 W5 @& J9 h8 T18
$ K! t2 P. U n9 f19# s) U0 |/ a& C; Y6 D) d! H
20
/ w8 V1 N& |/ p* _! M5 Q, R! x21% R8 t# S( }4 G0 f8 d N9 j
22
0 Z4 n4 H. `" S H2 O23: ?7 k9 j9 ?0 h4 V) o
24
, }1 ~( r1 V: ~- I& y0 x259 C/ C a2 I+ b
26
2 T( T! e; e. _5 ?9 e# B9 n& L- O27
( \6 P7 S' l9 Y8 n0 {8 c' I3 B28
$ v+ [0 X k( d- y294 [% ]4 A- q! g4 y7 a$ E
30. D( U0 ~& k1 t* v
31+ O2 j5 T& a9 G4 c
32* I/ m' E! y# m& C- y" {9 h @' K" x
33 M* M; W, t9 P) p3 I3 J/ y
34! @7 G8 ~. y, J: n
35
7 {2 R' c! ] x8 b36- D+ c6 R& x8 P& \8 @* t4 U- u
37: ?9 W; |3 E( r
38( O& k; s$ P3 t
394 |: u& |/ b. E( q
401 k: {! m% U0 P9 [# D- `
41' ]5 z- G/ m/ r# I, ?/ {2 w
42
6 w4 u3 s: p2 h3 w9 g43( a' N! p1 m. m
44# B& {& Z$ ~0 q7 O/ \
45% G; ]6 K- j6 t/ z9 Z
归并排序的特性总结:
( D' J' w6 J( H8 ^+ b+ C9 k" `
- i6 G6 Q2 M( x4 @% M* }归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。1 z7 ^/ `9 i; p. M8 ?' Z1 S
时间复杂度:O(N*logN)+ L8 c. p4 p1 G& V( ^% ^
空间复杂度:O(N)1 Q- W& t& z j, k, {: R
稳定性:稳定
* ~' e( p3 Q$ I( X/ w1 }+ j$ a* ^8 s9 ^$ b( G7 S& V; T3 w
————————————————
/ \$ X4 f% D6 R- x6 s9 _版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。3 g z o# \! }& G) Y
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
! ? A, @7 ~ Y N- b& `1 x! l6 r
' S* H+ @7 C0 j5 D0 w* V- f v |
zan
|