在线时间 1630 小时 最后登录 2024-1-29 注册时间 2017-5-16 听众数 82 收听数 1 能力 120 分 体力 569615 点 威望 12 点 阅读权限 255 积分 176107 相册 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 U; {4 i( q! E5 a8 E, Q
2 @" X2 E" B; e5 C7 S% N A7 u
前言" V0 v# y1 ]7 W, b9 ~0 w% k$ L
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。 Y& P! y+ [) f4 }3 [
6 C9 P2 o+ I7 z$ M& M& ]+ H 归并排序4 X( x7 q& s/ }7 J% ]9 Y
基本思想: u9 R/ K. z$ V7 x1 p9 B& T
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。* y3 P# S* V& `5 {
1 x( z. A) I- A v; k2 V4 H 7 F- z; h2 O7 a) @' C
) N$ ]5 ~3 ~7 @. c: z" ?6 ~
合并的思想其实和有道题目的思想如出一辙:' a7 T( }0 b6 l; C6 Y0 r
& f$ B, d0 n5 j8 z/ s ; O: x% ~) X+ W; X* f4 n- P( V
6 l7 l3 X- D' u7 N! N& { 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。1 P! }1 T- D( ]% R3 m- R
" X. C/ x I: u" P: s& J, F [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
' o# P+ s: @+ z: M5 e9 |4 K" V$ _ 3 O- \+ t7 Y$ r* K6 {
int* merge(int* nums1, int m, int* nums2, int n) ^5 B" h! e4 b& R6 u( n# e
{3 \$ q: C7 c" B
int* arr = (int*)malloc((m + n));- r, k1 A* |" z8 P) ?6 O4 s' A& ]3 m
if(arr == NULL)
9 P) Y4 D2 t% K) Z3 P d( T, {0 Y {
$ U5 p# P% O. ]0 F& O' y perror("malloc fail");
& a, B" N! D9 h% j. a7 h5 G return;* Q4 h$ s1 U* B# K2 A$ U8 B
}. F: ]& U- r1 x% k3 p$ R
7 z0 J4 h, k4 e
int p1 = 0; x6 e s6 O; ` V: R% C% V
int p2 = 0;6 n6 Q* x+ v" d) U! O
int cnt = 0;7 [/ D, P* q7 S/ k- `, o& G, c
while(p1 < m && p2 < n)
! W5 G( s$ a5 f {
5 W0 z& w: i7 I; X; w if(nums1[p1] < nums2[p2])
) n0 D: O' E1 I# K8 Q& j; L {
6 \1 B# y6 J" c7 [ arr[cnt++] = nums1[p1++];
N1 Z$ u! a- x1 Z5 m# e& f }
2 q9 @+ C) ^+ k3 ]; d3 d" o else
2 j. q2 Y+ _9 a" ~ {
9 f5 _# ?+ L6 H2 ~" l; b( A arr[cnt++] = nums2[p2++];. N& t. _ o8 |7 z U
}
5 X1 B, G: M5 Q7 }5 u) N6 {2 }$ l }* f s/ I" P- {- L2 z' Y4 O7 ~, h
while(p1 < m)
- s8 l* n/ ]% c( L+ L- q4 [: C& I arr[cnt++] = nums1[p1++];
0 e b- _: C$ T8 s / B6 B; ]2 c' ?2 P$ P
while(p2 < n)" K3 Z, R- l8 a! P+ s1 Z
arr[cnt++] = nums2[p2++];+ `) @9 G4 z; S4 Q& x7 f1 L- ^# D
5 t, F- c$ B$ n, t
return arr;$ n$ Q8 A- c D, Q9 U
}
* {; F2 k( ?0 a4 h. q0 p0 y3 X ( o' N' [0 n: U! ~/ a
1
7 o0 G8 b; }9 X 2
: F: U# G3 ^6 P! J 3% d7 H9 f& Y3 A5 h/ b& C6 m
4! P4 ]- s! M# T2 _+ D
5
. B1 Q k7 @8 T# K8 i. M6 p. |# M 63 n3 ?. P& g3 V% Y
7
2 f& |9 V1 g8 g 8, L2 ~5 F9 I, M
9/ Q9 B# J3 W1 T0 A; B+ O2 v: ^
10
2 y! w% k4 o, V( e* y4 m% e- B 11( H1 U% w0 m, M, ?" E
124 N+ q0 e/ g- D) ?7 @
13) L t2 _# h) h' ^- H$ i
143 _# J6 C4 j1 n+ O% c$ s
15: p: J$ \! g) Z; k& M3 |
16. i! S) C9 J _: B- c5 b& i
17
( [6 N) x* f5 w/ Q/ i( T 187 Z/ a) [( M( K
19. d" n2 F: ~3 `) A0 _+ K
202 L) O: e8 Q7 J( ]& _
212 W1 Q+ X. \# c9 d/ V; ?0 l7 f; V
22
7 f/ ] e1 ~' X, |/ Q. D 23
8 Y5 l9 i) {- h2 v$ R# W 248 E! `) Q' J4 N: ?9 u
25
2 e. j9 F' u+ @" G8 y# i" K) u 26% E5 _$ P J" g
279 l( G, s0 K* m: q* h( a
281 @4 x/ D9 k* `
292 l3 P; w$ P8 C# w; j
30
q {/ ^; X* H. X r, E2 I' U 31% G# Q2 V; i7 W3 g+ j0 N
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
5 S. m" n" F! i7 W , g' c z/ J9 M$ c
递归实现
+ g P) Z+ `- g& [- a# T$ D 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。: q2 P w; s& v; o: G1 o$ b# x
# m4 ~- z" E! A+ O( e% l1 ~
, _2 C; I+ _! P0 e+ m# A K* G . z& Q+ @$ _4 N* W# U& D6 L
# l8 n# K3 w; b% D' Z O
$ ]* m4 K9 X x8 J( b# U1 n" {0 F void _MergeSort(int* arr, int* tmp, int left, int right)
7 e h/ X) \6 K! X$ a% @ {; r- x6 v/ ~$ f: ~$ O3 s
assert(arr);
% Q' G* O% i& X: s& J1 Q/ u* Q* ~
( y! n3 A. }% F8 u: K# j/ E if (left >= right)//递归结束条件不要漏了
$ h4 Z3 C+ ]* U: i3 T; Z return;9 C+ v. U6 U2 A2 E; ^- W
4 S+ h5 P( Y! W$ ^; X int mid = (right - left) / 2 + left;
8 C# p* c2 G a9 ^2 S 2 z5 E1 x$ D- Q1 c+ U2 A
//划分左右子区间[left, mid]和[mid + 1, right]% k0 V4 f; w% F D; a* ^" D' q
_MergeSort(arr, tmp, left, mid);
9 r: \! n( U) y _MergeSort(arr, tmp, mid + 1, right);
2 L( K# m( I' Y ) ?& Y ~' p8 W" q- W8 g
//归并
m( v8 {- X. K7 m int begin1 = left, end1 = mid;
* a3 f2 Z/ `7 ~6 {2 ^ int begin2 = mid + 1, end2 = right;4 Y4 C6 ~+ I, n) E
int i = left;# c; C2 o6 c8 m, ?4 z, x
while (begin1 <= end1 && begin2 <= end2)
% Y. o2 r3 c% ?& k* e {
1 A7 P7 A6 x, r if (arr[begin1] < arr[begin2])
& R, _$ N" X8 [, G! t tmp[i++] = arr[begin1++];
$ K$ z; s. g v9 P+ X) v. R- L else
9 J* B! a! [6 {% O8 { tmp[i++] = arr[begin2++];0 L+ b; P# E$ P! V8 j4 P
}3 A! M, P m& |
2 I5 y- J( w) E1 y. P2 L
while (begin1 <= end1)4 s( C W8 t4 G
tmp[i++] = arr[begin1++];
3 k a$ n, C6 w V) O) l/ _2 e while (begin2 <= end2), q) n# S9 t7 A* y& H
tmp[i++] = arr[begin2++];
; g1 W3 x! F% d3 r5 C* K# k
2 I$ w; Q1 P4 w5 { //拷贝回原数组——归并哪部分就拷贝哪部分回去
f9 C+ y9 v$ ?: ^ //而不是拷贝整个数组回去
: t& F d, _6 a) j9 d memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));% f: v5 I: N- W3 L
}
; T8 ~$ {# E6 V5 M, q! q$ v5 C0 T
: T3 k8 a2 J) ~ void MergeSort(int* arr, int left, int right)
1 Q9 L; P1 ]& [ {* M! c! ]0 I/ y) x+ l5 I: T4 O
assert(arr);
7 d9 g; ~% Y) P6 i+ `& ~) @ " ?3 x' f7 R$ f) G5 {) H
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));- \ L, @+ g3 n) H
if (tmp == NULL)
" z+ U- L$ A, A' F& d {
: l5 C7 F6 g' e# X perror("malloc fail");9 v/ a9 _% X' l/ h& [( m$ d) v9 ~, Z
return;
) W7 }) E. ]4 M& b }6 J8 [' s: x' A2 X& o% S% |
6 u/ |+ J2 ]1 \9 t
_MergeSort(arr, tmp, left, right);# B. j2 I F; v3 }# m7 N* M1 a
3 \; r2 K W; _; W/ b" W" {0 ~. D free(tmp);
7 x& G1 W# @2 j5 }* I$ a5 A) Q/ e tmp = NULL;
# j0 f7 p9 K( V4 [ }! l8 @4 y/ m: r4 t& G" P6 a
) o3 C* @: n8 j) x. m$ } b7 w 1* D' h" x3 q; X" Y4 M" Z' T t
2$ s( Y9 s k6 X- n }
3: e/ @! k% C$ @$ [' s
4" U" G6 k$ W/ {+ r$ l
57 H, e& W$ f; z2 G, I( Z
6
% Q" a! V9 S0 N l 7
4 I% @* ?) i" r6 X" Z. I) ] 8
! h3 [5 h/ I+ k) ~: Z 9+ e. n3 B' k* p; m
10
% i" R R4 W B; C/ w! E 11
' ^# \0 u/ ^2 I; t 12
, }4 U. y- s1 c* Z# a 13
' W0 |6 a7 a$ [# X6 L# n 14
y/ p7 H& {. }# B* G 15" O3 D! p$ q! {, F0 k# }7 F
16
* ~% Y: M! ?7 ]8 u" k/ c; U& ?' [( g 17
! D* E" U4 q5 t! J0 z 18
/ H6 A- E0 \, F 19
( H* Y l4 T }7 C( _" r0 H/ j 20" a& q0 U$ o& R: U" f4 j
21
6 c- m6 c3 o( W, }; M) x& W 221 `. _/ M* x/ D% W; B
23
3 n7 m# T# i: [# Q" g 24
/ t/ A6 k- {5 h5 ?) w6 N 25
# @* V, {5 O' z; E 26; F+ \! F5 A) h: H6 G
27( f! W9 L8 ~+ W
28# m, |$ E5 m0 k
29, N B6 O0 h" C+ a* y6 ]# n; G
30! I- {7 Q" {+ l0 b& x$ H
31- o2 C0 M) b" M; y. N$ d/ R& U# I
32: I% u+ u, S' C: J. Y( H
33, D& O. |4 g: u2 H+ i: Z4 ^$ k' X }
345 J) p6 k. e8 k4 P. M3 X
353 C5 O2 Q' q2 @$ r9 S1 B
36
$ t" _" @. u9 b. q 37; q% p. j1 X: f5 c4 r
38( @2 U, ?; i8 f3 F1 I
39
# k) c4 O2 ]2 v: ^2 W 40! H* q. k; R: p7 u$ p. F& \* o3 c
41* S0 C* N" g5 _; \- m. s4 q6 @2 n1 @
426 z: }1 S9 Q5 G: y* Q1 |' ]
437 }6 d) A" Y7 J9 Z
44/ j, I6 v, @8 U
45
7 [( Q. V9 K+ k) Q( W. G7 V 46
# U- t m( i$ g2 Y/ _( k0 q/ o 474 T a2 O; ?9 M" l7 f1 ~8 B
48+ l6 ?9 c; a5 F- E% b
49
: u) u( f& [/ p7 P 50
, c1 Y( a, Y2 H6 |4 H 51
5 S& m% K. } U 非递归实现$ S- q% p! f+ F/ j+ p
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
4 s% [- |' @0 y8 x5 r$ V & k+ I, P$ J( v6 H
/ R. x3 X8 R! A3 ^3 Z6 A
9 Z+ i! O& g4 C# h
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。: s) D. q3 ~1 W: h n7 _& R: T
) |) \1 O: C& S4 f* t 还要注意区间的取值,每个区间就是一组,就有gap个元素。
9 v! B% Q0 [2 N( K2 \
! }3 y- F! @" {8 ^: N 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。% i$ [ n+ F( {- k4 O$ n
% g& \/ Q7 k; Z. G1 U. g% U 代码实现 \3 T; }2 `6 j: R% s! J! K- Q: [
$ l" D. p5 Z- I4 f+ v. d/ R void MergeSortNonR(int* arr, int sz)
. t- h& G$ b9 \' {- F) x# ` {
" o5 [; m9 K2 j assert(arr);. s+ [ }7 a. b8 D6 f' A( F, I
; e$ L. }" ~$ I! b2 d8 ?! e int* tmp = (int*)malloc(sz * sizeof(int));0 Y% A5 N+ ]; t- h) N
if (tmp == NULL)
7 M0 T6 t: _' }- _8 E! R( u2 @6 a- J {3 N/ J; K: f0 `( H5 [6 {
perror("malloc fail");
1 F* I# q9 B' K& j( U2 j" s1 g return;% Q% B# u# N4 Z# \+ p0 c+ }
}
7 k" ?5 q4 w( h* B/ B/ i O/ q- n& x+ \, W/ W
int gap = 1;0 H. [* w/ a9 f$ _: H. Z6 ?
while (gap < sz)
9 u' @! { e; `( B- z' z {
% o2 v0 J4 y$ s9 u* a for (int i = 0; i < sz; i += 2 * gap)9 M5 N* i- Y+ u3 D5 K# e- n7 T! x& r) b
{
/ C( E+ y- Y+ c. Z$ ?2 k9 j int begin1 = i, end1 = begin1 + gap - 1;
. Q; T% j: R) r5 I. j: r int begin2 = end1 + 1, end2 = begin2 + gap - 1;
7 Q- n' a4 W' G- ?0 H$ g int j = begin1;
" d) W# ^- s+ w' f7 P p
* C! s7 [8 Z: h7 I" ? //归并
9 i2 |+ d/ _% i, c- t( d8 J* C' c5 ` while (begin1 <= end1 && begin2 <= end2)
3 B( }$ J9 w6 R2 M {* q0 l0 C, A$ } z& g
if (arr[begin1] < arr[begin2])
- ^& G4 Y, f0 j |0 V tmp[j++] = arr[begin1++];
# q% D. L/ w7 f6 w3 X: j3 Z+ p' S1 h) t' | else ( \& W+ x/ D# z: e7 ~* o, n1 x
tmp[j++] = arr[begin2++];# H8 m3 n8 B( D1 z. l% \
}
2 t3 D( h' p9 Z8 ~ f
5 j% r/ y, P2 k* Z2 [4 x% ] while (begin1 <= end1)
# h! t8 ?# w1 |) X tmp[j++] = arr[begin1++];7 E( [2 p3 v$ m$ C) y& e- L6 o
while (begin2 <= end2)
8 Z. E! i* [, n% J$ _ tmp[j++] = arr[begin2++];. B6 l% d6 B! b
/ U/ R. H# b* T4 }, _& O) e //拷贝回原数组——归并哪部分就拷贝哪部分回去
8 F9 M+ z; r+ E. f) W memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
# W8 w; l2 P3 L$ @- r$ \! \1 r }3 C% j5 n( ?# P$ M& Z
gap *= 2;$ n: K' Y; V; c% f7 D
}- G7 q; B4 y g" c4 c
8 I4 Q- j( o/ h6 U R }" Q& ~3 \+ O3 q6 V, K- S
. \" O M# P x+ Y
1- E& o7 s; a9 |" V! Z
21 Q: ]7 k% q7 @$ y
3# |1 M( D9 c% }+ c3 v, v
4
9 z$ ~5 G: a1 S 52 e& M5 l; I+ `: s
6
: R9 v1 T. k4 W" [: K+ M 7 A& v! M+ }) K: A' K( _1 T
88 K5 [( Y) Z4 @$ w
9
( q( v( ^& J0 ]' Y. w. R: q 10
$ @0 `. u) w7 a/ `- ^; y, O 11 h G w8 @* F6 X/ y
12
, U- r2 p* E4 K+ u 134 p8 q: ~/ T2 O1 |) K
14
3 o3 {+ d. T# e, f 15" [& U, O! p: F2 P7 O4 I4 B
16
7 C' L0 j2 |4 S1 d4 o% N 17, i' ~, G: P+ ^
18
# q8 A+ |: t' v a( Y- a 198 h/ D- L. O+ x1 J0 N
20
, G# y, E& M$ I! Z 214 G" U3 ~) Q9 x" J+ ?
22- }2 J$ |$ ]) }" c" E _( |' g- T" M
23' }+ Y/ E$ V3 H/ s, d
24
6 H, A3 ]" f6 L2 a 25
# c% Q! }8 y( M+ @ 26
' Q: w# T( N5 z( H1 {$ E; a7 x 27
1 B9 m. `+ G# c- E& B 28
/ }: \ w6 M0 X) k' N; O$ z' A 29
3 a* s) d; r2 @( Q 30( }) k: j7 x4 t
31
8 A7 J T" F, S1 M! J. n& E 32% r) B- s8 L) f" U* S$ S" @7 p; i
338 r7 {( E, ]% n6 E- f+ \
34 Y2 l: g9 s: a* L
35* `% J; b D- o# D
36
' J; g7 @) `- N. o 37$ r1 ^; i- C6 \! I5 I8 n
38
1 L7 U# V. G: _ 399 h' O; i% k; }
40
) A6 d- B1 |( V; @3 P2 D0 |/ D6 E1 S+ u 41$ U% ~: L+ Z! ?* V- U
边界问题
* H& ?+ U- Z3 G8 M/ }0 s 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。0 b; w4 O8 L* \( R% j8 I1 J9 H
% c" c2 [, x& d# r/ W+ q 举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
( ]7 U+ |! j+ T/ V3 z* o5 @ e. Y 5 j: }+ f- k( P5 X+ ?$ g
4 R( {0 \! o$ \3 {1 o# G3 a
$ F6 r. n: Z' ~8 f% y7 ~ 由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)% a( h3 W' T# E W7 u
3 _5 H3 |! Q8 h
第一组越界(即end1越界)+ v3 c! J9 l+ v% l" N+ C& y3 T5 Q
& m& y3 i" _; P$ ^; G0 e
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。9 V$ m, x5 x% k+ e4 g @( Z: a
: p, \4 W3 U/ i0 h7 _ 第二组全部越界(即begin2和end2越界)
( {" Y+ q0 G6 i1 _
5 N% v# P J7 @! g/ A& k 应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。+ c/ \ ]( ~" g& _
2 o- U+ Z( ]: o& O4 N# V 第二组部分越界(即end2越界)
- n1 ^" f" Y' S( o
+ J- A7 |% Y) F( V% \8 i 应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
0 a/ J3 K, n% d' K9 C! e " J0 s+ |$ r5 A6 j4 _1 [
其实第一种情况和第二种情况可以合并为一种情况,原因:2 B" j& [3 ^' c
" a& I* l0 V: z; u, J _
end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。7 {- U2 l E: y
- v8 a6 U E* `+ {! s c
拿两个数组试一下:
0 [& Z M8 }8 @6 m0 p2 |( m! q# [
8 v1 s# x4 J) d7 P+ c& q 0 W4 p# {+ U9 z8 E
! _ A& x# m+ N- A, B
6 M- z1 r9 F5 ] u- w. z* R) f
. |7 y! i& E4 f3 \; A6 I
代码实现& u! q& G1 K) ^4 x$ O! F
) y/ D/ z! Q8 `* E( f
void MergeSortNonR(int* arr, int sz)
5 p9 S4 W( A% l {
- U: e; u; E- F! j assert(arr);
0 O( w! M: [7 w& |3 f 4 _2 {/ x2 m# g. \ \0 r
int* tmp = (int*)malloc(sz * sizeof(int));
3 H& H1 |. X& o7 B) | if (tmp == NULL) a' i* j4 f, _. z# g
{
: e. Y4 r% h% T. O9 a+ l6 p perror("malloc fail");
; ~1 |0 S6 }" O, r5 }8 X- X6 C return;
$ h! P1 F& Z; _# W; n) ` }
' ]$ W8 b- V1 D' ~# p* Y1 F# `9 \ , L8 h' a6 x9 T5 s: d E! F
int gap = 1;( ? X2 A: u" r& V+ H0 E4 C
while (gap < sz)
2 Z Y& W1 }) e {9 G. j+ w, i) W3 o& @5 B
for (int i = 0; i < sz; i += 2 * gap)
2 i, [3 N) T* E4 _- B {* p% Q# z- H) `
int begin1 = i, end1 = begin1 + gap - 1;
# q5 s' n5 P- \0 X& ~$ ` int begin2 = end1 + 1, end2 = begin2 + gap - 1;; c. }) p/ _/ G( |' l
int j = begin1;
2 M$ Q! O5 C2 J1 ?1 W2 B //越界检测0 [2 x! B" j/ U# A
if (begin2 >= sz && end2 >= sz)$ k" e; G& ~ L' T- d
break;
) d3 ?; Z1 E; j5 B$ d l9 j* Y) `8 c if (end2 >= sz)
% C6 _3 X& ~( l, J: J# X+ B end2 = sz - 1;8 p3 h F/ r% J3 A2 F4 X: A
//归并
6 g1 l) t. q# u2 Y+ Q while (begin1 <= end1 && begin2 <= end2)/ V2 z* K0 E$ q4 g8 P
{
8 d, d0 t J+ X: w9 j if (arr[begin1] < arr[begin2])4 q; N# v! L& L
tmp[j++] = arr[begin1++];
) G5 g! q0 G) q) k$ V, L else
: d) I# _3 C3 U2 |( m$ z$ d. R tmp[j++] = arr[begin2++];& k7 g/ s! e2 {1 X
}
4 n2 q+ \) F$ O9 X7 c 3 N- _# \( k$ E4 `
while (begin1 <= end1)
/ U* n2 \! F- J" [* o tmp[j++] = arr[begin1++];
' a! x1 j9 B) A$ p* a- z while (begin2 <= end2)
8 h# I7 Q9 B7 X! b5 a) x tmp[j++] = arr[begin2++];5 K v+ b! m" Y- \2 d7 I
( ^ s L$ l1 n //拷贝回原数组——归并哪部分就拷贝哪部分回去
. W) C& s6 @* L1 j, I' ?# [" ?& r% j memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
6 }; C) b; e$ T- X }0 r; K* \ A C2 I
gap *= 2;
B0 W x) f: x5 f; N0 w- a; f }) K7 s; Y- s, }1 @" c1 Q
: A1 o! ~1 | ]; t
}) ]2 E0 w/ v) k9 ~( [! S
/ m+ o2 D2 v6 m2 k8 X 1
. b! p/ z+ ?8 F% _, N, l 2/ z \3 |5 n b2 ^. X q' W
37 Q" n" o+ {2 G! X9 U8 O( b
4% p# L( h8 }: R# R
5
0 K+ k8 U, M5 ]4 w2 R% w 6
/ b* i$ [4 J6 o8 n. ~ 7
4 N6 z( Z) V4 o6 g# J 8) V% H2 B( |+ j
99 u: Q# y) X- y0 D+ P) `0 m+ B, J
100 ~1 m; R1 `% {$ G# j
11
6 d! y4 Z3 f/ ^ 12
/ _7 K) m& @) e5 p* t' j5 r 13
# d# G- ~: k$ t. m# {1 u2 t 14
( W: i! l) K* h% c 15" e3 ]7 b( ~& a( F/ v
168 Z" e4 n1 f! l9 ]" ]& f
179 p0 V9 G$ T6 u# f4 W+ z+ _
18
: {/ i' x- n; o( X 197 m4 G; O- y! d9 @, ? s, u
20, ~: |" X) [. R7 F0 g2 G. k
21
4 w& `6 ^) f+ f+ m8 r4 p 22' U3 G3 }, [5 N5 M l6 B5 Q, H
23
7 A# D& c P6 S& P( E 24, m! j! k+ ~3 n; b3 M N3 b* u
25+ Y7 f( w8 m4 R! S! a1 f p
26
, `0 ]1 m7 C6 J9 m 27
' }2 _3 a$ U: E5 s0 | 28( P! n4 Q2 [) y) c W
29
: s: t) a# e5 X* _5 E" L6 H5 r 30
. w# \2 L, i5 f9 p# B# D" }1 V 31
- n' o$ j9 Y5 } 32
1 {0 j- @7 d/ k! {* w- L4 u3 S: @ 33
6 d1 Y7 Q! _9 b( ^ 34
: K' b* e7 I3 \0 z: o8 k+ B 35 h1 I# ^9 ~( T, P
36
0 w) `" H% }+ ]9 n' o. o3 x 37& Z1 g, \$ F9 t
381 @! G1 T& j8 |" A
399 Y2 N! u5 V4 K6 ^
405 }" J6 q( S% r$ V- ?: v* Q
41+ N' q* }7 }; t
42
8 h# d. ]- T( o" [# `% S 43
2 o$ F- h h" |. l0 G 44+ n( R' C' m4 c# M0 |* g
45% b T8 y, }* l3 c# G9 T
归并排序的特性总结:
% S @) O& a! O ( s* o/ ~, `3 s) i
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。* [+ g; h6 O6 K8 u E/ c
时间复杂度:O(N*logN)- g2 C* I" D4 s5 O3 b K" Z
空间复杂度:O(N)2 { G( c4 ], D$ A1 Q
稳定性:稳定$ f' h$ F: U+ b6 d
! G& x2 I3 C1 W& t( p* ]8 p ————————————————; k& k; m1 y( J6 m* m) z7 {
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。2 v7 J& V/ R/ N6 \2 I- h, l1 X1 Q
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657% p3 A$ V! C% t
: K+ Z' Z! ]8 }
9 r% \' r$ z' i/ m2 a" y* L* e) n; t& J
zan