- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 566251 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 175098
- 相册
- 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 J+ O% x) h$ }$ g# h' l: r5 z8 I4 U8 K8 I9 L/ d* L% e+ j
前言
$ m# X2 J" l" W( p9 F) J: y* t本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。/ A( M# M& o4 J: ?
D% ~4 W8 ^0 E! R& N6 r- h归并排序4 n- S P3 m, j/ _; C, \
基本思想$ ?6 l' Q( g. {& I' u* |
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
i# n0 i3 {+ n$ S3 y1 r, l1 L+ k; b
7 y5 e. s, _; e$ Z$ g( B& e9 v/ W8 Y, A2 U
合并的思想其实和有道题目的思想如出一辙:8 ~9 C4 j# J' R% `& u
* L: @: W: m1 t* H, J# e
- U: b8 k& S& }6 `( h m# M% m7 x/ j1 h& L( O8 A3 b
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
4 ]! i1 V- T0 H, U \
+ v- F7 x( y; ~5 l$ ^[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)] k! A. `5 t$ a9 q l, P
' C/ b) g+ m, ?' E! y' h
int* merge(int* nums1, int m, int* nums2, int n)
; l" m, `; O! c! X( e7 B+ D3 |{1 U( v5 z: @* d6 f+ ?( Q0 m
int* arr = (int*)malloc((m + n)); p% l: b4 G$ y
if(arr == NULL), P0 O! f2 G% \1 A. W$ o, L; M1 X
{
0 E9 J, c0 g- J" {' w) H; P; ? perror("malloc fail");" B5 k6 z% `: I. {9 A) w G" g/ p
return;
; x- L# l4 [0 B& F }& E' T& @/ f; G5 d3 u2 {: P2 r
- X4 m# H6 D( N2 i1 V2 g
int p1 = 0;
2 J' [) y; P5 O+ f# l7 B' @ int p2 = 0;
0 q5 G$ n% S( x0 Z! s int cnt = 0;# z" S3 ]( n7 x! [! N
while(p1 < m && p2 < n)
$ y, { b" s% ^# U, @- E' J* f a {
' O0 {' [9 ]+ e) t0 [ if(nums1[p1] < nums2[p2])
6 `* x) L' l" T/ R' y, J {
3 |; q4 L; V, ~( L arr[cnt++] = nums1[p1++];/ r: S9 [) C6 u
}
' ]. A9 x3 o: H/ D8 Q$ r else
1 K; k: R# n: m$ {+ w y {
" _; ~" O* {! C arr[cnt++] = nums2[p2++];
/ _! @- p% w/ ]2 [ K/ ^ }
0 g- K: B: K; P; C$ E% \ }: y. \9 [. I/ d3 R; r' L
while(p1 < m)( j: D# V- G, _
arr[cnt++] = nums1[p1++];
# l( l% E' v+ L! G+ t; F9 K5 h) H3 v3 @3 S# X$ a1 W
while(p2 < n)) Y' }6 z) d6 a; S, j5 C
arr[cnt++] = nums2[p2++];1 @' F6 m: [ v+ i0 W* J
1 X. Z( [2 K( M% d7 f% i return arr;
& H; i; I0 K( t/ g& r* |}; G' `6 }1 W% \$ V( L
6 z9 y) {, H6 C6 Y19 \, T) ?$ R* c. U; a3 l: W
2! }$ `0 e9 m0 A& c1 `
3
! k6 s& P- ]( A6 C4
/ q! i5 a, W& j0 \56 Y4 I- |* ?0 r: x: t& u h
6. H& p; | e! x9 o: W7 W& {
7
7 y' _9 L8 ^( g( R0 u, R8
) R7 V9 U, M; R# o$ K& N' U* U3 S9
8 W6 H" D3 J& B/ U3 w5 K; a10" V: \5 W; b% j. G6 J% b5 e O1 `
11
% I9 \# d9 o; l) w- w+ ?12% g6 j( ?2 h- B2 t1 }9 P
13
; c) v( z: [/ Z) _14' Z6 Z0 {! L( ] t5 m
15
1 o) `) a/ K& r( u- ^) Q I16
* w$ Z8 P2 y$ e5 v& } q3 F) L17
- k# m3 G7 |) H2 M6 _0 i& F, |0 o18
8 x2 y+ W0 n) P! s0 a19
$ G7 ^0 s3 W5 ~7 e8 P20
4 D" O# k/ W; k& X21. F3 q/ j1 \" `/ Q( D1 O7 z
22
7 n/ H- ^' b$ t7 w* U& P23; `* L2 E/ |& M8 u* g
241 K3 o6 D4 q# c9 P) K8 C
25
3 u" ~3 P5 ?5 l6 u26
) [* Q+ c7 e7 P- ~27
/ n# o% C0 a# D28
) \- }8 k, M9 |0 [( R2 z29
" d& F* {5 D+ D* e30
) f5 o! e) [6 i3 N% [0 h3 f5 F312 }4 `' G3 v$ L
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
3 [" ~% D r! Z8 Z& x3 L& Q- _4 }/ ]8 K8 t. c) C
递归实现
5 @& b; x4 x" b+ L3 | 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
. i7 G6 e# N4 z; U( }& w0 c$ [; b O4 W7 R& h/ u$ Y4 e2 O0 }
, d1 F' ?+ C6 s( `+ P' K
/ b$ i7 l- D0 o) J
+ ]8 A7 i5 i9 e
1 L8 E* Q# i9 \' X& x& C% Avoid _MergeSort(int* arr, int* tmp, int left, int right)
7 S/ Z: R" c/ A% V% b: ]) n{8 o4 U0 J1 r M' A
assert(arr);& y! l) [" q, ? {
$ ^% _1 x2 D3 h2 y2 a2 F% F if (left >= right)//递归结束条件不要漏了1 X0 P: H8 ~, Y
return;
. c! i; V% }/ i8 |) z: i8 w, ~
" Q' v' I& r+ l/ f4 l7 ~. I int mid = (right - left) / 2 + left;6 Z( O% ^, Y+ `1 B. I
, A% Z9 q: j3 F //划分左右子区间[left, mid]和[mid + 1, right]
5 x1 s* E0 Z) @% w8 u _MergeSort(arr, tmp, left, mid);& ?( J0 V- c2 ~! H' ]
_MergeSort(arr, tmp, mid + 1, right);3 d4 Q8 O) ^2 {$ v1 v
/ d7 ]- H7 ~; ^- R) J7 K
//归并
6 U5 h" R* O' S int begin1 = left, end1 = mid;+ o2 P) r6 m9 _% \5 E0 q7 P8 S
int begin2 = mid + 1, end2 = right;
# ?: p& Q1 q5 | X0 h1 I int i = left;, l. A8 p& b% d! g9 _& t! S
while (begin1 <= end1 && begin2 <= end2)
" J- A! I- F6 o& S2 N {. h! ~! U2 T* w
if (arr[begin1] < arr[begin2])
- K5 j5 Z0 c# p tmp[i++] = arr[begin1++];
7 T7 }/ H0 j6 J- x/ H6 C else
4 E0 g# |( e* r& I) I& q tmp[i++] = arr[begin2++];
& b a7 }/ w$ ~ }% _9 W- ]: e4 ]! N1 [: j2 N) i
( y. Y' `3 i9 u4 A2 A9 S
while (begin1 <= end1)" Y# l. l, U3 ^: b( @
tmp[i++] = arr[begin1++];# m7 Q0 K$ _0 }+ ]: k7 Y! g
while (begin2 <= end2)
9 x; e1 O- S6 P) N- A* B tmp[i++] = arr[begin2++];9 [ S, a5 @8 H* Y$ D8 w/ M
5 F9 D& Y* \# _3 t; r1 b# @ //拷贝回原数组——归并哪部分就拷贝哪部分回去0 W+ X G% L0 U
//而不是拷贝整个数组回去7 I) h1 E- Q9 s2 v( W9 Q
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));6 n0 j" N+ h6 n' M V% J h3 D
}3 `9 a A* E5 \! A. v" b q) Z% ]
8 M9 T' C( t) X) }9 H% n* c' ?void MergeSort(int* arr, int left, int right)
: ?2 x+ W# _/ u( g{
! D0 ^. T" a5 a5 m' D" k, P assert(arr);
" D; U! {. s P
: T" r; J. ], [# w, X5 ?9 G int* tmp = (int*)malloc((right - left + 1) * sizeof(int));$ r r! A' ~0 g0 I, {
if (tmp == NULL)2 u. B7 }- B. Y
{
. S( ]- Z& g0 l$ m9 B perror("malloc fail");4 f& H% `! e! t) x5 x" Q+ Q
return;/ w' r$ w9 c2 e1 D4 v
}/ f7 z& k1 O8 u: V8 {2 D
. k* A& w% y, Z/ J
_MergeSort(arr, tmp, left, right);1 ~' b4 f3 r/ l( U( O' t
$ t5 Y2 N0 G4 H
free(tmp);8 Q+ `1 C6 @% M; w# b4 L% u3 h. A8 m
tmp = NULL;+ j7 G p2 \2 ~
}; z4 ?+ q) }7 O& m
; t0 W N5 J. B& N
1
7 p) J7 e$ H9 ] I6 ^* |7 K6 U3 B2* i: w* T+ p5 f" \- R8 {7 M
37 \8 N- S7 h- J0 ]2 \
41 [8 G0 L% \7 r1 N/ Q) q. H# M
5( W% N: R1 y* _0 x* \: t" a7 j: K1 P
6
' o+ h8 a1 a' @+ i, H7
' o% G3 |" i7 n0 \# Q' o8
4 u2 V5 g6 R! ?: q, G+ O/ w5 l9
b1 x$ k' v1 i9 E1 G6 i" V10
! |8 d) f9 r6 J( A! C11
) z& P# ~4 \! |1 u4 e/ D; C( e12* ~5 V9 p7 O/ }+ l7 a9 Q
13 @, ~" O3 t: [) Z9 N4 U% ^
14
" @$ C0 \& k& N t6 o15& r# n1 `: ]* }* S
167 N2 ~: V3 s9 j7 U; w
177 o& D$ w$ W H9 ]+ O0 ?9 U- i* L
18
w$ g; B$ @) s% T! N+ P5 z6 v19
1 q2 M: H3 k2 O20
3 j" J; k6 B9 b$ `: r. @5 y21
/ e. m; u3 k% X6 }22
' g% Y0 F J* E9 N. K23
* t! o, }+ z4 N8 Q8 i246 L! w4 A# w( m% H. |6 C6 n+ \% f, R
25) a3 @! R4 y* d, X! \
26
5 B3 m' p, _* E* Z2 A, E' V- r272 ]5 r4 t5 b. D; X
28
; k; D1 C |, w5 J7 l. y& J293 @0 n. i9 |5 |, U* M
302 r7 i. t% d9 S
31
: y Z, n" i" z' W322 \7 {5 p$ J7 H& ^) l7 e
33
$ m, K2 z0 X1 _6 Q3 y2 r343 C9 g2 X5 h' C p1 k7 o) U$ N
35
. N# }; @. N6 v& N, s2 J36* V O9 x/ k! W1 y2 r- {
37
) J6 E9 J! O7 I8 e+ t% `: R* {38- \( D; \1 `1 }1 l% r: n2 x
39
4 P, c$ w. w# |, e1 `( [! a9 D40
; f7 s( R+ J( X0 Z6 Z v413 i! v$ D! [) B) a7 L E, m5 c9 N. b
42 D: q( g/ ~8 r% D: I
43
* ?- g7 f9 C1 P& Z* g, s44
- H- `+ w- R3 s$ v$ I% u45
& @/ E1 v5 x2 j5 e, P% w, o46
2 p" `- V# N4 A+ J4 i( {47
$ M8 ]- ? }& B# a48$ P/ A- U! R! p. w. ^% k! W
49
4 ~9 ~+ M# {3 \4 n50
/ @$ T4 N$ Z! `51
: w8 S. m" R, k非递归实现
" U+ ^2 c r$ o5 ~) ~7 o) j 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
% Y( e- `+ u0 b2 I% o" c( R, m
, ^& j8 w. Y+ R1 c6 Z/ f& v; I) p# i) G, }. y
" X' X; t j! L, X/ `4 e; ]
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。9 P1 @; M! @6 B6 D
5 L+ T' [% I! Q* q" ^. [- d 还要注意区间的取值,每个区间就是一组,就有gap个元素。1 r8 \% g( C) ^# R$ |4 E' |3 z
]8 `( ]% A& x1 v" S5 N' o5 X8 Z
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
! b) L2 @% B% }3 ~6 `; K6 P2 C9 r9 h' k: V5 q
代码实现' ]7 o' |+ K+ K# T1 Y( y
9 W; I$ K0 f. a
void MergeSortNonR(int* arr, int sz)
. s7 v0 r, ?8 S{
' P# c7 `! @1 a" \ assert(arr);
: B, K+ s) V; I" d2 {% I2 [" `1 w: D$ N( a3 Z o
int* tmp = (int*)malloc(sz * sizeof(int));' ]' W* x" s/ f
if (tmp == NULL)" _2 @8 [$ C# ~! d/ r. c/ I
{* c( ^9 {3 g* v R
perror("malloc fail");* ]6 U" ^8 R! G5 d. i4 o! `
return;: `" u! e6 r2 d+ g0 A
}
/ v: c. b& C' u$ R8 K
# o7 N( I4 G# `( b6 Y int gap = 1;
+ L: a% u( W: y, t) w9 _8 g5 F8 p while (gap < sz)" w: \$ M* U. o3 C
{
' i2 s- }" [. r% z- x f* R for (int i = 0; i < sz; i += 2 * gap), K0 V# _; ~' l- \+ n ?$ I
{
7 j; c- R- P- F6 b4 H; F5 |4 o int begin1 = i, end1 = begin1 + gap - 1;
. y& ^/ _2 v- m, G9 r6 D( ~ int begin2 = end1 + 1, end2 = begin2 + gap - 1;8 B2 W& ^- \4 s# r }
int j = begin1;
, ?9 f5 I1 l t) e
, _* `9 z0 L; ~8 O2 R- D, f //归并
5 y# n( d3 Q, q z while (begin1 <= end1 && begin2 <= end2)
% ?8 O6 s3 I: [6 x9 Y, e {
- V, |# g: K E) ^8 ? if (arr[begin1] < arr[begin2])
- F: l' d- a$ z. ]- u' R tmp[j++] = arr[begin1++];' M' R- U8 ]2 n2 l) y. B1 q7 x
else & V$ L1 W) ?$ Q! ]3 c" m
tmp[j++] = arr[begin2++];( W3 K4 R1 p1 I: Y: q
}
7 X) v5 c) {. q! y& C: q
9 I* C5 U8 q( N! I5 u while (begin1 <= end1)& _! y/ F8 l2 }
tmp[j++] = arr[begin1++];; m7 B. G8 }7 u& H Z) P9 \* K
while (begin2 <= end2)6 z- N7 T2 C, C5 a0 u5 }5 q
tmp[j++] = arr[begin2++];
1 r" y. W& G* U9 P2 G
' k, b% [/ ~* i* j //拷贝回原数组——归并哪部分就拷贝哪部分回去
7 l, D8 E" Q9 z x/ l memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
: {: q4 y; R! U6 g! R6 A" d p }4 V6 g4 c5 s" y4 V: e9 ^4 _
gap *= 2;
5 I2 R5 {) t* s0 q0 \% ]: i }/ Y7 F4 i8 M0 ~: F, N
" [% f* K" T4 K1 |}
2 C7 x5 l" k8 X+ C& {/ V# X& C' f% w5 p' P7 h1 h2 _- _( O- y, m4 D1 ~
13 |% ^0 v z3 {* T, V2 ~. w* `' `$ Y
2
! t! r2 X) k- W0 \3
2 y, S3 b4 ^- j2 R& X+ \4
+ i+ |( f7 d6 h- `2 y5
0 I2 ?% @7 u4 {! S+ m, |3 G7 x6
$ T/ A+ b0 G2 ^8 X9 Z" z( f. a7! R/ s1 A6 A9 t6 b# D7 C G5 u
8* b) m5 D W8 L/ @7 ~
9
: O, L2 j. [ k: t/ r8 Q0 I; v10% G8 Y9 o$ k- R5 d% v* u; |
11! C2 q4 e4 n. H6 S
12
/ i5 A0 L+ B4 H: x! V13, q4 E! N1 f, c. `% T; Z. ?
14
( a$ [; }: g8 p+ E+ n2 ?15
1 }" |1 J/ y% _6 \4 V* G! g16
: L3 I- B. z) r- U5 f% M172 g! K1 l/ c. W( d( ~6 a
187 u6 P2 [2 v& m) O0 v. A L6 ?
19
( O+ I4 g, b6 _+ Q20
6 T% R7 z/ I, w/ i% }2 a3 G21
% ]9 ]0 `- J9 a. A6 C5 ^22
: V5 W0 r2 G3 n, s$ \4 e230 D' y/ |3 I0 ^: J# b9 P, G! P, \
24
0 d- F" \" h* l, V1 ^25
+ ?0 c b. f% ?5 n26
) U+ j2 Q$ q% Y: g6 \! h! w276 ?# {( y( z, |: n# b: d; U0 Y% t
28
) ]9 \' k i+ P, B$ E29
- P7 M# @( z o% ~0 n! i30
+ k* B5 u3 G1 ?9 U31% w N9 s% d" }8 u+ ?
32) B; O+ G1 w% Q4 K. {1 x! F
33
) W. ^ x, z6 x3 f: @$ l34
% ] e7 O* U& \2 |5 o4 d7 j35
, B3 @3 R, j. J) p360 m& g6 o7 a) o, ^1 o
37
. c K5 m' \- d. z4 z38 w* Z& d5 [" [$ F8 r
39
* D& O8 x6 @% [( C40
9 N9 `( O$ o2 Z2 G" q41. D4 _7 O/ p# H, i" u. J
边界问题( r. X! @+ H `
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。5 l- Z$ r# ~2 J" L' M5 m' Y
: h1 u7 l- i2 D3 q- y, ? w举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:5 O) J6 w# Q0 j5 l
) l% z7 K" K: E7 R# Q* @
: H. ^/ j9 k% K0 ^( @6 E9 l5 N1 }# G) h8 E
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
! R; e# ?5 g/ V. p8 y
, f- [) Z% U/ P2 c3 d) N/ i第一组越界(即end1越界)
4 | w( U7 }- Y _7 ~6 T! g6 T; i+ B& o: ^( Q5 [7 X
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
- P% q6 c; K; J! q! o. W' l' X% U8 x# i+ ]6 y M' F* F
第二组全部越界(即begin2和end2越界)
1 {- ]8 y1 D* [3 x7 z0 h0 G0 O7 R. \( j& M
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。0 Q/ @/ I) G, [( X, w
2 B( e6 x' o; s* f0 v% @
第二组部分越界(即end2越界)$ H' r% b- Y( v% U. z9 j
2 @3 L$ k$ `' R" a8 E/ x j6 C应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。( ?; {& \3 T* |- H/ y2 T9 t
1 P/ o" [, X* ~5 _5 s. P
其实第一种情况和第二种情况可以合并为一种情况,原因:6 h+ |/ r5 O$ U0 m- \( H, S3 E; P
- |& i, U6 ]: O5 i1 @) N7 o end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
( B& v" n b2 v ~" O- l
$ U& K/ D, }6 _4 h- Y, g; o0 c 拿两个数组试一下:# X! u( V: T$ x9 N+ h) [, r( s' Q
8 d, H. L2 \: {7 K) ]8 { o1 p; B
' H( c) O5 m! m* k# m3 a% g2 v$ c
0 T- [: g# M9 K0 C. A
, O. \6 n3 p# ]2 Z/ C N8 l
; ^- x% \( W n- H8 z; y/ X代码实现5 e# B# p3 g: a ], R
! |3 C% c' r+ P# z+ Dvoid MergeSortNonR(int* arr, int sz)
6 N3 z2 ~0 ? _{
/ X% p, P- v6 f assert(arr);0 V; M3 r! u6 h3 o- {
2 ]% U' c8 D8 ~ int* tmp = (int*)malloc(sz * sizeof(int));* y/ M9 H" Q: z" M; t0 ~; u3 e
if (tmp == NULL)
7 w; _& L6 c. Q. c" N1 B; O# N {$ _0 u7 |! q5 Y; l" f6 s6 B
perror("malloc fail");* F/ o$ l: u: X& G3 J5 p
return;
: ^) r# D% g7 G }
" t, e' c0 y; J% I4 d: D3 ~+ ^9 j$ ~( t- o
int gap = 1;) I9 f9 t" A+ e) d6 y; Q
while (gap < sz)$ ^2 T( |/ ]) \# d
{) @. _" a0 x% G
for (int i = 0; i < sz; i += 2 * gap)
6 O. S% ]+ W: ^9 e/ C {4 W$ i1 [" `* z5 M8 a7 V8 P
int begin1 = i, end1 = begin1 + gap - 1;
+ ~* Y$ @: P* F& {9 t6 X int begin2 = end1 + 1, end2 = begin2 + gap - 1;
; w8 f3 _& K+ d" H1 J: J& ] int j = begin1;: ^: ?' m( y" B% [
//越界检测: u7 |9 U' J' }; e& B
if (begin2 >= sz && end2 >= sz)0 Q( L4 _& b: i* ]# w$ K4 Q$ n
break;
* V: G( f4 P' V( k$ j4 Z8 e# M# m if (end2 >= sz)/ e) y& u5 d# E
end2 = sz - 1;
: Q7 R8 Y- t& {6 @0 J, Z: [) n: J4 x5 K //归并5 F) i7 }1 I$ b2 ? _, l
while (begin1 <= end1 && begin2 <= end2)
: |5 s( I" ]/ e8 V* {( s8 P: ^ {
; L" E a) S6 h! {& ?+ `5 u* f( D( E if (arr[begin1] < arr[begin2])) t* X; g9 |5 m& |. I
tmp[j++] = arr[begin1++];
: f9 [8 x2 W5 ^" n( e- o else ~" f7 n. J Q! O
tmp[j++] = arr[begin2++];
) z& L# W: R5 v/ L }0 \+ y" B3 q4 F, d1 n+ L4 i" V8 ?
$ {8 @9 ^! w1 ~ while (begin1 <= end1)
- z. g4 ]2 b: d3 }5 c l, ` tmp[j++] = arr[begin1++];
/ J( K( |7 A' `) z while (begin2 <= end2)
) k' [% X# j0 W0 U) t tmp[j++] = arr[begin2++];
! ^/ v4 u9 ]4 Y) z9 e3 `6 t
5 I5 P- v s' ?2 ^" Q //拷贝回原数组——归并哪部分就拷贝哪部分回去4 I# G/ r! ?& H& p* S9 v
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));# g7 {! C5 ~0 l7 r
}2 j* ?% c6 j9 B3 y) @# l
gap *= 2;
0 E9 h8 S" L( j: p |% _ }
" t+ i; K7 m# J m& C" a; W8 y, ]7 _3 R* Z: q9 G1 H# G8 m
}
% ^" q! d* P4 i) D; W6 B+ i9 |2 d% S9 K+ u m9 B
1
: y, e' g1 p9 f: V2
& k* {7 S/ r8 E# j% L3; M% ^1 E9 \: S9 j' h
4
9 y5 ] C) ^; [: H# I55 ?" G, q( w/ x; K
6
" y. T c$ @" r76 c4 M$ p7 `; J/ T! X6 i
8
* T% O+ U7 F/ L- C% W( y9) s& \& n- C; W, z0 Z1 \% o
10' `# f3 X3 Q9 ^( ]: J6 ^: k
114 g5 d/ s7 M; S5 q ^! {4 N
12
1 ?1 o7 M4 G1 K) i0 g% r8 p133 ]& T8 B s/ g! C
149 Y5 J! z8 q0 L% F& s5 I4 F" f
15/ X# ]5 \0 ^' i/ Z; }
16
6 K( `. M1 X# ?0 x* k17, d7 h* L: L7 \
18. w9 g+ r* t' a% C7 B8 S
19% v3 j6 a# J. x) g
20
, ~/ [( l2 C* }2 L8 e" N21
( t8 [5 p* I/ G6 A* t1 z22/ g& V7 N) S9 r/ e7 K; R
23
) f5 ^* {% c$ J1 C" Y% ]. H247 `3 |$ F0 S2 _1 S& b* Y3 }
25; k5 M9 r1 l, j+ K8 q, i: a+ `! c
26+ e" F6 A* t" E# K& ~* C2 W; G! O
27
: h. J0 b$ ^5 a28" W$ I" U3 v7 {8 \- V
29
# U0 X- ~3 Q3 L) [' T) a" V30
7 n$ x* w+ m3 W+ L G3 v+ i n31
( @8 c- D2 y! T( L- Q32
5 g/ a% }& y7 s0 n" q33
; M" q! l6 J H34
, G' A& R0 N, P% ]35
, d; I# c' o) \2 l36' y- X( y9 t o) M& e
379 q8 w- L0 Z: G" \
38( H3 t& t7 @/ c" O) M+ s6 }+ q: X
39
8 a0 C; p" b3 z4 s9 s9 y402 m( E, o/ F+ y: C/ h9 O
411 q, A9 K% N W4 @! i$ Q4 j
429 C1 t( G- _* V% g9 [
43# g- k' Z- d7 K# o6 r0 I
44. ?4 h$ |7 W5 M
45
+ L6 q& ^- }) |* ^; y* q, p归并排序的特性总结:* r! ~+ Y& u) J& X2 y+ u2 r# g
3 q# u f$ c) d1 Q( J9 u% z5 F
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。. P3 o! Y1 m& ^: V1 y% T
时间复杂度:O(N*logN)
( }" @/ |9 g+ j. q空间复杂度:O(N)2 p) L& t, A3 j! O6 Y- I# B: Q
稳定性:稳定
9 H, i3 m. o( t5 S5 ^
z; E* O5 c9 _0 h1 I6 y6 V————————————————
' ]% l& X* }! j' z& G, [版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
: z+ y P% i% J! N6 ^原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
2 A! N0 O5 |3 k$ W T8 x+ t. U% k/ }* j/ |- r Z! P
! o% y! q& g9 I" d7 g |
zan
|