- 在线时间
- 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的排序算法】归并排序9 S+ g1 n; g1 _ a* W& N3 p; q
H6 c; G8 k$ M7 c" j' Z- k6 A前言
6 K; A6 t/ C- d本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。3 L' J& g3 K/ I+ Z7 w" Q" f% w
$ p$ i& B1 H! p" O w5 v7 ^9 ~归并排序
$ N* E2 [; F" J. q7 q; X, c基本思想4 r! d* _5 b8 Q1 y% c; v
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。9 q, `4 S% X2 M; G
4 B/ V( M# N. P$ Z: O+ L4 j8 i
: \; b& K2 ^' @, D
6 C4 l8 J. F* e& j0 H( P 合并的思想其实和有道题目的思想如出一辙:
5 ]& e" |) R3 z( k) J( s" z' [
1 n4 x9 y( q4 K% n
& v: E4 v) a+ o9 g( R( P4 r6 G! s7 N5 _* t8 @+ I' b
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。7 U. \4 c' X$ j# @- W
. s$ W' @& O3 l: f' g" i" K; L* B
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]0 P9 s8 h7 e0 t
( s. X8 V" m7 q& s+ h9 vint* merge(int* nums1, int m, int* nums2, int n)
( n& I3 c; K0 n- i1 @{5 J; t- L0 v& n! ~
int* arr = (int*)malloc((m + n));
9 m6 k/ b. r* |: b1 ^ if(arr == NULL)7 |" R2 D3 F8 p; L- c+ M5 D
{$ W* ?) |. L9 z! L
perror("malloc fail");1 [1 f& R8 P; L! t- X8 M
return;
9 K2 b1 h) A) \* C8 } }2 C" j0 n+ H9 C6 g \6 X p
7 u, n$ r$ ~5 _2 o4 N int p1 = 0;! W! V$ ]1 z- r' B
int p2 = 0;
, u- P" J5 p% w. R, z: ^# s int cnt = 0;
( h0 A0 z4 ^! y# Z; Q4 D& i while(p1 < m && p2 < n)
3 M0 s, b" G3 M2 C8 }6 G4 l {& [, @+ q, ^/ E+ K/ g
if(nums1[p1] < nums2[p2])) p1 @7 f! T2 @8 H& B
{
$ T8 y0 g3 a% r6 D( K+ w) y% z arr[cnt++] = nums1[p1++];
' E2 n1 g) @2 L$ V5 ^+ x |. Q }' X ~3 F+ e# ^( ]: V" Q9 y6 z
else7 j' b3 u0 Z. x
{
2 z6 K9 u n# ^) E! Y arr[cnt++] = nums2[p2++];8 a* V5 H' E& ]# c2 n
}8 \: g0 B6 B1 ]
}- x C/ H0 ]# v+ Z
while(p1 < m)
7 W) P* u6 U* h) G3 c1 h/ J3 \0 l arr[cnt++] = nums1[p1++];: L& n: W/ r# `+ Q
& z3 W5 C: r! B+ g, x0 R; ?! g while(p2 < n)/ G* Z+ v2 ?4 I, Y+ ]% d
arr[cnt++] = nums2[p2++];
' X( K$ N f; Q6 q+ C+ V1 [3 z6 c
3 m# ?8 @+ l: Q return arr;
& ]9 v9 I1 ^! z2 U, K. ]8 A1 q}% H6 ]4 L* d1 o
, n+ \5 o, Q. ?% G( f9 K. _( s
14 c, v0 A5 K; p/ `9 ^
2
3 a' D+ V: E( d+ W' U3' d) O) _7 A4 t! {
4
' N0 c' ^9 M2 n4 t56 P# t- S* [7 U
6$ o9 p: a* R/ x% a
7/ Z, C& Y. P% N7 ^3 G
8
9 ~5 k/ g4 Y G3 D/ Z% @9: v/ O: Q* m7 ]) a
10
- o' T4 t: q! ~, t- R111 ~) x1 \& d$ y' W, U7 m
12
9 V1 P& t3 E/ N+ g: s& f13
; i1 s: c, g, s2 ^/ q14
9 D, T; W. h0 @( k3 y151 a# t0 s( b+ f a( `+ n" e, S
16 b4 d+ K% T5 @8 V6 ]
17
# l; Q" C; ?# C1 R6 | ^( x/ M18
. t, @1 d+ \4 U192 h9 `8 V& f- M0 S7 T$ D
20$ h4 G! `% a2 e5 e* A
21* ~9 o. N8 B: m9 G6 v+ Z9 {
22
+ b; F! V! i3 G2 Y1 R23
# \: P* h/ o" X4 M ^3 ?2 i4 L9 B24
0 x/ a) @3 r( n1 U; J1 ^- \0 P25
! r$ k3 J+ X+ G/ ?7 v26
2 _8 n& ]( {" C: ^( O( Z; M273 {6 I" _1 h% t6 n4 V
28; M j/ a; b( x2 Z. q
29
$ j$ g) |# o) Q30
E/ z5 t1 c' ]0 B! _& ~31* @% d3 K4 z! d* l8 H4 N
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。; }$ `" i8 H& r2 ~/ |
% K* K( t Q( s
递归实现% n5 b3 O9 V* t( D2 O, @
通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。0 e, e6 H; v! v: l- h& p
) O, }0 Q7 Z! q; ^3 x! K- v
2 v( Z; `8 c, m- k! V
8 }9 I R B {. a2 f R0 F: |- x5 J5 F; N
5 e; g7 ^& U. z& @7 p" F& q0 yvoid _MergeSort(int* arr, int* tmp, int left, int right)
) _: Z7 g# J6 ~9 y9 c& z' n{5 n. E' a% u; c0 T
assert(arr);( x1 G3 Y1 ^: J2 ]0 ]+ C8 ?; U
- v+ W% Q3 k" p; F- o) Z if (left >= right)//递归结束条件不要漏了: c6 {! x1 d" g0 L+ D
return;& [ C v: ?# [9 O- ~
n0 j; e2 E; d8 N# i. P int mid = (right - left) / 2 + left;( z/ ^7 t% _" y- G
9 l4 ?1 K( ^1 z5 S7 F' j7 `
//划分左右子区间[left, mid]和[mid + 1, right]
9 N3 Y7 P3 V i7 u+ Z9 J" M1 S _MergeSort(arr, tmp, left, mid);# h5 m9 s, m- p( V( ~/ G" M
_MergeSort(arr, tmp, mid + 1, right);
. N- \' B# s8 m; \
3 P* [8 b b% K* O //归并
2 x0 }! D2 |+ Y( U9 A int begin1 = left, end1 = mid;. @3 m( p* t" Z. R8 `
int begin2 = mid + 1, end2 = right;
, _" w2 {, }3 U! ] int i = left;/ \1 _: K; r% |8 n4 ^) N* J
while (begin1 <= end1 && begin2 <= end2)0 C ]$ {+ w9 a+ n/ N) t
{
6 l: q7 s& `7 }# E7 I6 J$ f( ?+ b3 z if (arr[begin1] < arr[begin2])
) K% I% |( o. m; w ? tmp[i++] = arr[begin1++];
5 H) ~5 J! _4 r0 J: D( Q else
; P4 Z- b# l; y a- W# Z; a! G8 @ tmp[i++] = arr[begin2++];
" |+ ?, G' O, k$ o+ S1 A; Y. d }) D# @2 I/ \2 w- x$ A
0 I7 _8 X3 u9 n5 E; j, K( h
while (begin1 <= end1)
8 @- q: M" N6 w4 \% a$ z$ o7 l! L' G tmp[i++] = arr[begin1++];
5 @$ r* |3 Q7 X while (begin2 <= end2)
3 N" _+ u5 Q. ^. m/ N. F# E1 G tmp[i++] = arr[begin2++];
4 N% F) K: n+ e3 q8 g 7 ~3 F2 T+ e) k4 j0 C
//拷贝回原数组——归并哪部分就拷贝哪部分回去
* C0 w/ g$ G: b, z$ E; k' J //而不是拷贝整个数组回去- E4 F' j0 n j
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
$ U$ N+ n8 m. V1 B) V& n}
: l8 |3 ?) }) r5 i; ?" f+ u4 ]
, L9 k! n# i- o2 Jvoid MergeSort(int* arr, int left, int right)
( e+ o6 ~$ S2 U{3 X+ l( p$ [" ?
assert(arr);
& F! x6 L B: B' I1 F; X
$ O1 q! H5 T4 Y# u$ U( f) W int* tmp = (int*)malloc((right - left + 1) * sizeof(int));3 q2 G+ c3 v- {+ B
if (tmp == NULL)
/ Z& J- H; N2 f1 t8 ~5 Y: f {
4 w2 ~# e! B7 e4 ?% T perror("malloc fail");2 s9 {6 d$ {# z) b4 _
return;# }, ~2 Q5 _! n: }1 ]2 _! Y& A
}
% ~3 z5 g0 E/ W+ B+ m) c
7 ^& }+ c. m' R8 H) ~( } _MergeSort(arr, tmp, left, right);4 g% N) H! |% t0 U! j+ g( `
4 l# B% p4 Q, l5 P3 Z( @1 W e
free(tmp);' I7 }* Y0 \+ f$ i
tmp = NULL;* o; g8 a3 {! Q* p7 H7 T$ G( u
}8 `# c; t# V( _& A: r' D* y
7 J" m- V6 ] H+ p1
8 Z9 f9 [1 I- z6 S2$ T' }3 D# J3 ^9 i/ i
3
5 D. `) F- I% U0 r. A h ]4
$ i2 H6 h" m4 z) |9 Q7 D' v$ x5
; [" |: e. W* L9 p1 n6
F: e$ o. k5 `+ L' d, |2 O6 q7
8 l* K5 f4 {! ^4 ^ T" \8# b9 o6 _0 o* w( P+ c8 U# a7 |
9
6 {( j* P' b' {6 q/ ?. l10! n! }( d( q! B; J* N3 S, d
11
5 X: e9 W0 [" \! T L8 x, r# X9 F12
8 b2 \ ]1 v/ e) x6 [$ y13$ v9 C) \8 a" \
141 G( Z- m8 V3 L' D: m& v1 _5 d/ q
15
- D: L! n" j0 G4 c) M16
* w$ n. b, q- X- `17. o( {; ~; _8 @ [5 S U
188 s9 h; \4 _4 y- U( f+ K: H4 Z
19# @0 A3 |' b t1 ]; ]2 H
20
& n" B, K& S. \+ O2 A/ d6 g21; `) x$ q$ p3 B9 Z" q! E+ x6 W
22
. `4 S) ^! g1 B8 M' E( n1 [, q230 J, v4 _3 b3 |. F" c
24$ I4 S' u& [: {/ @
25
; V5 u" [3 L# b$ r! W/ P; g26
2 N! }9 `2 |( ?27! G5 b3 f4 A& G! U9 k- }
28
% |/ E, W3 S2 w& J( z6 W295 B! D7 F5 e) \
30
4 K' v5 U, u" o1 y7 j- x31
3 r* X3 {4 \4 B# x32! f; o, \) d) R3 k7 m5 i
33
, E# q9 {2 y6 s, L8 ]34
: Y: @' `# R$ ]7 f4 O- J1 D+ W35
- w$ p' k, F0 ^2 R8 n& ~36& e8 n7 Y7 P6 x
374 W4 B6 Q; r M0 Q- D4 U; L9 m8 [
381 t. t$ t" b- T3 b# w2 l
39& N4 l. y r, Q
406 U( F# j3 |! }$ {
41
7 I4 W4 w0 B- F- c5 J- @. m5 P42
. N; t$ J, {" G [5 r4 b# L436 b0 f$ M' X+ r7 C k
44- i, n! B+ g5 c R
45
) h" t+ E2 x2 s5 \6 w( ?46
, |. S4 t& a$ A& s- U47 D" } t$ ]; _ P7 Q
48
+ R, B( C, \$ E# o, l* S v* a5 O; Q49
; d Z p A) ?50& `1 F/ o" C0 t Y- J
51
% D5 p; T( v( ?1 ]6 D非递归实现& x' @ x9 C8 X2 p& E0 _
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
9 p1 a- X2 J- g. Q+ Y8 q8 N( F
& Q; ^ j ?4 V' H, ]" S. o4 z+ p3 p3 W5 V0 v# q
7 W" K' l% L/ q, v) V4 K! w0 C
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。 z. R( M7 o+ n: g4 M: z
- L1 B' X- G$ E2 Z- k) l
还要注意区间的取值,每个区间就是一组,就有gap个元素。
- g7 D: O4 A" R/ d- X9 M x, ] r1 `: A$ N# t- g$ X
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。' F* ?! J3 a" @
5 V) _7 G! i+ {1 i. g# N代码实现1 F; m0 J6 i& S$ m Y
2 `8 G" U/ ~" m" l, A" Lvoid MergeSortNonR(int* arr, int sz)/ v" e* P+ Z! p' g8 C/ R# ^* W- K& C
{4 P3 B! q* [' Q+ l+ n6 X
assert(arr);0 y) a1 B# W+ v; f; z& X
& C8 L6 e* L2 a8 \7 [$ _+ T+ `6 n @ int* tmp = (int*)malloc(sz * sizeof(int));" `, H+ V! b8 y: I1 [
if (tmp == NULL)) i' B7 T6 o: b- Q
{
. u+ t( A' K7 E, m" W+ Y perror("malloc fail");
; d+ w! F1 Q( R, m* I' O: h, W! x return;/ e, z% o* X( J" g; L- r+ I
}
" B" ]! e) B- K7 E2 M6 H/ S0 O2 c! v
int gap = 1;
4 x( n+ ?7 [$ m% H1 p9 x9 o1 W, N while (gap < sz)
% s1 q8 }/ m1 s# [ f* s% d: @ {
: ^4 P2 @ d" }0 K: ^ for (int i = 0; i < sz; i += 2 * gap)8 P7 h$ M! f4 U# K9 C( e4 S' N
{; u' k) a$ _$ F1 x- T% n) f. v6 D
int begin1 = i, end1 = begin1 + gap - 1;8 S, o/ R+ M, @" [8 O$ K* Y
int begin2 = end1 + 1, end2 = begin2 + gap - 1;: H: G$ t: O' ?+ O6 Y: Z
int j = begin1;
3 s) m+ \" _6 o
. _- Z2 p; i6 B4 N" V6 i //归并) ]2 u$ [0 `1 i7 I+ W- T9 x
while (begin1 <= end1 && begin2 <= end2)
/ W9 f( g' `: s n {+ T2 y3 a& a4 o& m* _
if (arr[begin1] < arr[begin2])
0 P( X( L! Z" J( `: W tmp[j++] = arr[begin1++];$ T" [1 K6 A7 a2 Q
else
5 A, y/ ?) V! x7 q tmp[j++] = arr[begin2++];1 [. v. U6 A0 {6 ^9 G, T/ b
}
$ k/ m# M7 k9 n. c# Y* m
4 p) n. F/ `( ]% N+ q while (begin1 <= end1)
' T2 ~ e# s/ p- \: v tmp[j++] = arr[begin1++];8 m6 @5 `4 _- L9 L
while (begin2 <= end2)
# h! m3 B- N+ m9 q6 u tmp[j++] = arr[begin2++];
+ K4 {3 F4 k& K# o1 c
4 y9 x' i1 W0 }2 v6 C( m& ~% P2 ? //拷贝回原数组——归并哪部分就拷贝哪部分回去
: m; f8 I$ N+ |* W7 c+ z% ]3 D memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));& ?5 V1 } U& j* ^- D" }) ]
}
1 m4 _6 i. F* H- x gap *= 2;7 D g6 R8 N5 V$ F9 g# j
}/ H1 G$ ]. L, V. u: s
* x" |9 ]* z$ y) r3 n. E q
}& P, O* x1 a+ V* W, j3 N; K
3 h5 W4 o+ S+ H% B* u1
% k8 ~/ h5 g% [( c& g2 p, r9 u2
4 t; L8 n7 u& r- s6 K+ K( r: U- z3
7 [3 q: Y. a' p0 W47 c. k) C9 l: @! @
5
1 l" ]# d8 g$ W7 y: _5 f6, _6 }3 j) R2 X4 E1 Z/ f
7
/ {* A( B3 r+ I8# v3 T" Q& r K# ]" D. S# I$ \# t( v
9
4 g) k/ ^4 X0 L. h10
7 M' M9 m2 I8 R! b7 W113 b6 \5 R: [' a3 s
12* j) Y4 I1 p* b4 H
13
# `( g3 f& Y" H$ B" ~8 U146 ]9 b2 ~+ t. V, O
159 h+ x9 q# ~ c3 t6 J. U* t2 I
16
6 h- c; a7 b* q0 ~1 ~17
m! m0 g, E/ o+ R' K18! }# b! y, e& Q7 d1 J
19
. B/ P3 |9 t5 t/ \( ?208 B. H" b! K d- L- ?
213 ?. M' J1 P) q- Z% ~5 Z$ P
22( U5 f* D$ C3 U$ s: q* e6 d! j
23
6 v% z4 e+ F4 `24
+ c7 Q1 [/ J( ^. s* f5 m" q1 O25( {2 _3 `. ^+ B2 \2 [, p5 ~2 K
26
0 p6 G: j% [4 F6 Z27
) p& Y; d3 D' a28% Y( {5 w) ~2 C# y) [! l. i
29
. Z7 x& f8 }8 _308 i0 S1 c+ f: l% j9 G
31/ F7 p6 n3 j/ c! A; N' P% @* E
32+ N! B( Z; Q, q
331 H3 b0 x& l0 Q& ]' f
34
+ `- ]6 A4 V7 k7 Z5 y& i) T4 r356 V) q# } O; V9 s; J( c
36
9 y2 }: u h5 y% s37
" M6 }5 Y7 [9 g8 h- x, g2 f! [5 R38# B; u( b3 q4 F( c3 c
398 C. G, ]5 H1 D! y+ |" }
40
7 Z: D* u$ T% g1 ?" |$ t+ F0 g4 J419 A: W* j9 l" A7 q, k- T2 C8 m
边界问题- } I* I) K1 V$ t7 K5 M
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。9 v) V3 H( `* }) P# v
4 Z5 r! ?. Q0 O# |+ @" N6 G% B4 F
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
0 v0 B' ^8 k( r1 a5 E* q* O r& k! E8 e: X" f
j# k& b- ^1 I, Z$ W
$ G' r( |+ W3 y+ ^& u" w由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
: Y" u* p' J i. E; `8 `4 \ _
: W3 h b" w9 P6 V, [( F. M第一组越界(即end1越界)
2 h' W$ H0 d& t8 @- f+ p
6 M) b; S& E$ T6 k- u' m应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
) a: F3 V6 x, @0 [2 c7 S: f5 _8 I+ D- `8 o
第二组全部越界(即begin2和end2越界); A. @! \1 m1 d5 j
0 J8 \# s1 f& e; }
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。9 \* Z4 ~6 K: ]$ q# _5 P
~, ~( d* q" `& {8 `. \4 O
第二组部分越界(即end2越界): \( g2 T0 A& M
* c8 n) R1 `$ m4 t
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。" n! i8 @ [7 Z! c" S
/ F5 P' n* k. u! _1 s 其实第一种情况和第二种情况可以合并为一种情况,原因:
6 W4 ?. g7 b# w2 G
! v% h9 v9 ^! L2 E8 l7 L: { end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
1 M! b3 J3 E( b: k; D& c6 f P$ S/ g) L3 w. D
拿两个数组试一下:
& J M/ I' z- {# E
! Z8 m) `+ F, z& m0 _" l' p; g( }7 r7 X1 _# |! W5 Y: U4 k5 W
8 ^ h V2 o4 |% T7 }3 w% b" {, t
6 c3 Q/ K4 O2 c$ k* A. q, B6 U" `: [9 g0 h* P" d
代码实现/ J2 f3 I1 n0 K; E7 [
/ D. w% l+ Q1 M
void MergeSortNonR(int* arr, int sz)
( J2 [' }# V, Y! E{9 i8 F' D' {3 A$ Q, l8 t
assert(arr);
4 e8 \" q d3 S" M. L$ G( @1 J; [2 Y5 x0 m2 p' v
int* tmp = (int*)malloc(sz * sizeof(int));
1 f- W5 Q% r* r& {6 ? if (tmp == NULL)6 N3 y" ]: ~/ X- y H
{, a' b. S3 C# W6 M( g
perror("malloc fail");. b0 _ @" p! r9 J+ @4 B. v
return;5 I; A" L3 Q1 m- c0 e! z( s
}% U; ^( h1 s& F. {7 e: J
j; g; Y" Q! d& X
int gap = 1;
7 @. C- @$ B7 o) e; W# x: T" b while (gap < sz)# f& O& G" {0 `4 V. u- ~) m! @
{
% h4 M% @4 E9 V for (int i = 0; i < sz; i += 2 * gap)3 \, F3 r( J1 [( j& W3 f
{
2 @% c( E8 X+ E T1 r int begin1 = i, end1 = begin1 + gap - 1;
* A% [# m8 Y% } int begin2 = end1 + 1, end2 = begin2 + gap - 1;& o4 d2 y' j' G; ~, ]: \
int j = begin1;' m1 [/ a" ?, S
//越界检测! l- s# ^1 ^0 E0 j) j
if (begin2 >= sz && end2 >= sz)
+ s# q2 n5 J* e _) L break;
3 C$ b- F: e5 I+ [, U if (end2 >= sz): n; V! ^* R2 k4 p0 V/ d
end2 = sz - 1;3 W7 v' b }! k- \
//归并
& L* h, O' [4 V# d7 c" ^ while (begin1 <= end1 && begin2 <= end2)
' h4 E+ r* { P3 K {
]- ^6 y2 L' V# q: f3 h if (arr[begin1] < arr[begin2])) ]8 \/ B- p9 X
tmp[j++] = arr[begin1++];7 R4 H5 J, x$ s; M9 t) a
else
5 m9 K& K* V4 _: ^ tmp[j++] = arr[begin2++];
7 W* ~; j, c6 \; W }$ R. I( s6 B) V( _; r0 Q5 b' }* H
5 }, b, X1 K; S( d5 U while (begin1 <= end1)! Y3 I( x# e! i, I. L" L0 u8 y
tmp[j++] = arr[begin1++];/ F+ n' f0 J9 k& ~ Q( d
while (begin2 <= end2)) S" C; J) A% n `+ D4 J0 j
tmp[j++] = arr[begin2++];0 w5 V' s& _$ m+ l8 l+ K
" O2 x" w& \3 Z, P
//拷贝回原数组——归并哪部分就拷贝哪部分回去
5 [/ \" @1 S* d- D' N0 v memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));. G' [4 _2 L# u& l, T$ D3 L
}$ w$ X, r6 Q6 H+ C
gap *= 2;1 B4 P2 x0 v: j1 U# a( X
}1 ]3 \0 i1 _% z, ~
1 t$ ^1 G3 H$ h" k8 }( O( W2 ?5 g
}1 [ s% }$ Q7 Y; ] J* B) _
. }. E! }5 ^# _: r3 E1% R0 [8 V: J1 w J, z8 a
2( W+ S$ `, T: V& k4 c/ v/ G, s& k
3
9 ?& o7 L: ]. e, P( L4
# O1 t& K/ V0 ], M" P9 U5
' m& L4 x2 k. a5 E5 d6
5 ~) G% L6 _# ~$ ?7: [: e1 u, v. Z- o5 }" \
8* [* e$ g' t5 e f
9
! ~7 ^. }; m2 G- ]10% L9 V+ N. G9 t+ V l9 q, x. ~( L
11# C4 v. X) B' f, T1 c8 l. _
12
2 Q8 y: h& P2 X: b, ]13
- Z, A, L4 S! B, x" o6 O148 y( t+ o' O5 `" S
15
" {) U% X, a" w5 `16' L5 l; o1 g, r* S! U/ H
17; U# Z+ a$ n. m8 B6 J( l/ g
18* S; O5 n, y2 O4 J; T
19
0 D4 Q$ ?& m. D/ O h7 D# ~201 z4 Z/ C8 s( z+ Y
21
; u: m$ b3 T4 L' C' D- m% M% `22
. U4 O# f% c1 B: a23& C3 p9 ^' r" r! p
243 s( [' d$ q: |7 z8 L' f
25
2 j8 j, V; T! t+ v$ Y* p26- {$ p. _3 V3 \. {: H) u
27* f. u* {8 H: W5 H" q# C; z$ W9 d
28
. S; ]: M% M( {29- h) ^7 I+ ~, t) U4 ]( D
30
% C4 P/ C5 X. c3 b31
; ~ C8 i9 n" H7 a32
. o8 m u$ K4 O( U6 A) }: r33
' d- R) x k) a- P4 v34
5 M% N$ o0 o! ?35
7 m! B! \- x* B5 `3 k360 g3 _# N; K) P' M) o6 B7 P7 s
37/ F0 `( q0 Q. C0 b" A" x% p6 \
38
9 s: O8 g9 e% G7 Z39
; h. K" l: p! H% `40
0 r$ P, z( D2 m: z6 G41; a2 J9 \ o# e$ r% p
42
8 J/ o- m& t. B) m3 U7 o43& ^. X: `+ q9 {/ @8 j6 P
440 E( ^) J/ Z. x0 B# W) r
45! x( }" @: H. Y9 G
归并排序的特性总结:* I. h2 v" T% @% R% q/ i' s
) [4 v# B$ U1 o: Y- B& W# v* \3 _
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。* X1 G- S' U Y" H9 j' k9 [6 i
时间复杂度:O(N*logN)
: y2 A3 Y& h" i8 b空间复杂度:O(N)7 l$ p: _! t5 g; J: \3 o# z: \
稳定性:稳定2 y6 T+ g) R. N" m; c
% v, f1 B) j+ S* f* @————————————————- }2 M: {# ?/ n x
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。; P/ F5 t# [+ H( K n! T, v; u
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
0 H' X# l( w) Z" j9 m
$ {) s! @5 C9 l C7 Q' z7 ?, ~9 Q3 J1 q P& V* U2 x
|
zan
|