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