- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 81
- 收听数
- 1
- 能力
- 120 分
- 体力
- 554085 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 171598
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 18
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序 f* E- }/ {/ c0 }7 q& h1 ?
, D( G5 T8 }- U/ a
前言
$ M8 ^4 R/ T- Y4 A- Z) Y8 M) ]本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
/ _) [" d& G! E5 B* i$ T: M7 X) u' f
归并排序0 p; _5 X' Q" E, J) c+ j
基本思想 C1 r8 v2 d, Y! v _* p
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。( U1 I N0 h; L2 F; L6 Z8 m* H
0 a |- g2 ?' B- _' C8 L% Q T# T8 V+ d/ e8 j7 b+ }
8 O3 c# j8 k3 N5 e5 ?1 D 合并的思想其实和有道题目的思想如出一辙:
1 I1 ] g8 {( g5 |
; Y% p* e, D* S0 K0 u$ W
" K2 [! [0 R+ M5 N
" [, W: u) s6 @& |# I ?* g 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
+ z. m' ~- ^7 C$ d) n+ h# c7 |0 |5 f! X; m8 w+ `
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]9 F8 J l A/ w; C& H, t; ^
; s( i( P9 |5 _6 I
int* merge(int* nums1, int m, int* nums2, int n)
8 s( h0 K+ i! O" s! q- k% M{
4 r+ U/ ?1 H$ \7 v0 _* Z int* arr = (int*)malloc((m + n)); R0 ^! r( k6 M
if(arr == NULL)8 h6 @8 E, S& S7 s$ g
{
# J! L! m, a- |, h& N( } perror("malloc fail");
* w6 C3 s2 W& I2 N4 n8 @ return;
r- ]# U! P2 E$ [, t h# }# e% t }- u/ i) j8 B' F/ D: t! b9 E/ V% d
* y" ]. t& ~' Z' n& m6 \
int p1 = 0;
5 v+ w1 ^# e3 k/ ` int p2 = 0;: [$ M6 i8 Q5 V& D, {
int cnt = 0;
U1 a1 U$ q% \ while(p1 < m && p2 < n)
* w9 ]) Q+ f6 [2 n8 T {% V6 ?# V' n: C' h4 j
if(nums1[p1] < nums2[p2])0 H+ I' n# k0 \- I7 I6 D% z
{+ S7 v8 o5 F% v* u
arr[cnt++] = nums1[p1++];
) F( A: d1 U9 ~) N$ ?# b6 Y }
+ s, G. ~/ ^, C) c+ t3 U J4 P" [ else' e5 M7 f ^/ e# Y4 d. x* b
{+ Q$ w- d, t2 o5 W
arr[cnt++] = nums2[p2++];; `+ }7 ?' U: ?' @" d' u8 E
}
. V; h2 y8 I/ B/ O0 {+ v }& E& R) R; E' K/ X" E% x
while(p1 < m)
2 ^" G0 `. k- S6 _/ t# D$ a arr[cnt++] = nums1[p1++];! Z: ^4 d; ]5 ^- K& f. N
2 j8 V" Z, X$ K7 n, w' I9 p. I! ? while(p2 < n)
9 x; d- {! |+ @3 b2 s& g arr[cnt++] = nums2[p2++];6 k h5 e6 j9 B3 P* [$ \- [/ a
: k' x! U5 b5 F9 d2 U
return arr;( W" b, t% e n2 q5 ~- v
}: ?$ a, V, G1 c& ?3 F+ H
6 O- B- I7 I- J! |: Y
13 _0 k/ [& x: G: R* z% x6 y2 a, m
23 ], ^! H# R3 \' T% d/ j" x
3# d! v6 z( Z; w6 y# Y! A! {; @0 G
4( r) H. Z, g7 u
5
& F. b* o- W; \5 e6
1 K# L4 j1 N7 K' |7
6 W( D) k/ o1 T2 t% J8 X88 n' ~! M/ v: S0 e- {( h
9; ]( t! J4 }/ U0 \4 _5 G) K
10
& M6 n2 ^' o) B( Y; ~117 S4 g5 n* w; f9 x
12
5 O$ P+ i: k+ v3 L! L! }% \& l13) z t. Y( w- n9 i; d% W
141 T" c$ l' |. V! b6 p% ^
15* |% i1 Z. Y) w$ f! U
16
' D9 O, M5 H& j0 i+ W4 e3 U3 W) W17! `$ S; _2 c' w+ b4 q+ D
18
6 u9 q6 j) f) w3 T# r# G& v19& d( L4 G+ _6 C+ b6 q# B! ]' ]
20! y8 q5 x+ c; r3 l" F2 @( D
21
s" O/ }8 K, ]9 J+ n, G$ V. ^22
, f0 k5 o( L9 Z1 Z" ~8 f23. A; D9 l S6 A
24
$ j: v8 b0 R+ g/ F2 M9 E, n2 ~+ C4 \25- @3 g/ y; C2 |3 P
26
6 ~$ p7 E/ ]* i27
% Q* [4 }) C, e: X& j285 c& k" L' J! N) Y( {! O9 b) @
298 X8 F& c7 {1 M- g# ^+ R8 J& G
30
! b3 m! J, v( ^5 m0 Q! e. _! `31, X P/ \. l! V2 w& X
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
4 ?4 K2 C! N+ z& _, J( x4 R+ o5 c/ s' j$ J/ b0 i. W3 u2 N
递归实现) o5 J7 |1 G3 T/ _4 z( V' i
通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
' H1 y# ~, u! J
* F4 n( X8 L `4 r
/ x( A% P. z" O; t% t
# t) g+ ^, j9 H. F
) v9 d7 i1 z+ @/ b5 N' |* v$ ?( g! u! U0 [0 Z
void _MergeSort(int* arr, int* tmp, int left, int right)
! ^5 p {! a' \2 e{4 `. e- c+ \3 s |* F6 t2 D. n
assert(arr);
+ }* Z! L2 z, U" U8 y O) }, h2 E3 d+ w# P" ?( |0 y! U
if (left >= right)//递归结束条件不要漏了
6 s w( O$ ]) F! ~: g1 d return;" i- Q0 u7 M& q& `5 T. N
) p2 @8 i& L* `5 N9 l9 @ int mid = (right - left) / 2 + left;
9 x1 {$ U1 h# B: A8 r) o( s* L+ N, v4 G: u
//划分左右子区间[left, mid]和[mid + 1, right]
' s# C6 X; H( w( }: z _MergeSort(arr, tmp, left, mid);' G6 S; |9 j) U+ N
_MergeSort(arr, tmp, mid + 1, right);
/ f I3 ?* V4 H. U7 F4 g
* l2 {- T2 _5 X0 d //归并
' \( B3 R6 ]* M- S int begin1 = left, end1 = mid;
2 Q1 Z. C7 g( f5 \) n$ v( S int begin2 = mid + 1, end2 = right;
) P7 V7 q- p, A4 s. @ int i = left;. j! `& S8 a0 s7 ]+ T+ ^
while (begin1 <= end1 && begin2 <= end2)
" i/ t$ W5 T1 O) J' A, Z5 \ {% z, `* a& [' ~/ s. g
if (arr[begin1] < arr[begin2])
( G$ [; r2 r8 U k+ M4 N tmp[i++] = arr[begin1++];
% M5 b" r( j! U a" s else
, n A- v7 x, ?! i. D8 t. W+ s tmp[i++] = arr[begin2++];
% [7 `$ y) S, J- P1 y2 h. w }# b5 d7 d" Z; I/ I
( ?( K+ i6 {) b/ H$ K( ^ while (begin1 <= end1)
- p1 ~5 l' ^$ ]7 k$ ] tmp[i++] = arr[begin1++];3 G4 H8 _1 \/ O4 `* p
while (begin2 <= end2)) h! F" w i) f& a. J Q: v$ W4 j
tmp[i++] = arr[begin2++];0 P( B8 [. @7 p5 X# ~
: N. h* d; i' n+ J$ k
//拷贝回原数组——归并哪部分就拷贝哪部分回去
2 a5 |1 T4 {& h //而不是拷贝整个数组回去
; L1 j. _* S/ \# G+ m* [0 @ memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));$ E7 w9 I% J" ^
}" i6 t+ y* M) I/ [$ Z& Y
$ n* V, A9 P; S4 w! O& T9 r( U
void MergeSort(int* arr, int left, int right)
. W+ a# P6 G9 p, M1 x3 y% J% V# O{( K* @2 q6 {$ }1 T! _
assert(arr);
7 @4 T& N9 L3 ~- E5 e0 h: S- }% ?3 U; X2 l( w
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
) X& i( d" s2 [ Y: Z" b% @ if (tmp == NULL)! w% J8 q8 m0 V+ A3 ?
{4 m3 t- s( l" }# O$ m& z3 g
perror("malloc fail");3 S8 |# k5 l# k" R& j/ D
return;
) g1 E$ S- f2 t }
, J% ^8 w0 U ^3 ]% J1 Z! C5 \
- R# F ~- d+ l( _/ ? _MergeSort(arr, tmp, left, right);: }, N N) a7 L+ A5 a' I
9 m/ ~) } K0 ? free(tmp);/ g/ }+ {- {: x0 Y7 b& v' J g+ n8 L
tmp = NULL;
; c8 ]( @% a: d( L2 `}* i3 e' W; a# H. a
; ?8 z; i; J6 H$ v# z$ L6 \; h
1
+ o: p5 a% b$ o3 P2
8 W! }& S7 c0 x r5 I' ~& l6 b3
6 ~2 e( a! F+ P( j) c% c4" u: W8 j) H1 {) N1 K F0 O: h
50 P+ X4 M0 h* M3 ]' D7 L5 p, J* b
67 d- Q8 A/ _8 \5 E/ v+ r# @
7/ J+ {6 r" Q Q( ?0 k* ^
8$ }" Y: T4 o8 t4 C r$ ]1 a
9- H% K' F5 [0 ]: Q; `! M
10
/ J/ a+ R2 \+ g" U- Y11, w% r9 d+ o3 d! }# x
12
* T1 s0 Q2 p9 Y% e/ r2 p13
* W2 ]" I1 n1 B( S( p6 u, H$ w: B( S14
. a4 {$ s% K# u3 p15
( ^9 a2 E$ o" d" Z2 I; B, s; K8 t16( b" @ f2 I: z2 }
17
2 `" Z3 q# {, x" u% J9 V2 n187 Y) J( c! i, R3 e. G8 @3 E5 \# @: |
190 Q; B* r1 i. \
20
2 m% Z3 X. B& c# F( Y9 T+ m/ Y21' ?0 U* x9 ?) w' q0 V/ w2 U6 ~
22
% q5 J# W/ E2 W! T$ X23; ^, }8 N m8 `3 Z9 @" S" ^
24
7 _ l' @, c3 z# G V2 E( }7 x7 K25
( C. w" B( a5 ?4 X26' z9 y4 X7 f. ^, ^. u
27+ `: s0 D" |1 Q6 H$ s
28% ~2 t; N) l* t) _1 J
29' d1 G1 h+ B9 [; A/ x% s- {
30- n* x) H8 e- t- k* m. ~- R) B+ p
31
' z/ A+ C9 A6 c( c2 z328 v& J) w- ]# ?# B7 E @5 N
33
9 l/ U( @1 [( O& S34
9 _7 r+ ~! e* E7 {35
/ n: I/ s6 Q! {/ m7 B8 ]36
% D& a/ z/ M' K. r) {37
3 O) @/ ]( X& V- \4 Y38
! ]- v( F6 j3 Z# B' |395 Q( e( G: ]$ x/ ^2 Y; ^
40
! A! h7 n) }% L3 {" r& q41
K! {( V1 N/ }- M" m422 N. `) a' C+ @) r' P# k' S
438 n3 a9 w+ m$ z9 \ O3 `7 {
44
2 b( J/ [5 g) n7 X4 u457 l' K6 R3 N& Y2 g( ^
46; ~$ W' s# L3 o2 k, D
47% o: }4 v2 }5 I, v, ~8 ]. `
48
" y5 `6 s2 k6 t: X+ b49, ~3 o! B- X* o
50
2 V0 d$ l! }9 W8 Q6 E0 O( w, ^511 n4 h3 F( ?- M4 {- r. S5 N: n3 `
非递归实现
: b" e! I7 k$ i* `5 q! y8 o 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
/ X8 |" T5 P L& v! T5 B2 `+ W* t6 q* ]8 O9 k; Y( e
0 J8 g* p; ?+ F( I, O* p+ F1 j& F7 z0 [9 }
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。' i3 E" S* {& L# H3 d) C
4 V- n2 O+ s$ e+ A 还要注意区间的取值,每个区间就是一组,就有gap个元素。# [% S- E2 t* z' I. _9 d# B% P! Q, f
2 _6 N2 B& v# ^6 f. |* E3 ~
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。" T* Q& e% K7 K6 R g( Z' Y
1 G2 ]# t4 o- |代码实现- |3 Z+ M9 j' l8 Y* e6 q' e: ]; r
7 u3 v6 q) y1 ]. W
void MergeSortNonR(int* arr, int sz)" ~1 U) Y" _4 G8 n
{
6 \8 p% S, w4 N2 {) X assert(arr);9 m) M3 y: n5 |& H
, I6 x$ a/ A; P# K3 g# q
int* tmp = (int*)malloc(sz * sizeof(int));8 c2 [2 k2 M& `2 y5 b
if (tmp == NULL) W" v* o' ^3 ?& w5 n
{
7 J- H1 P/ {. Y. S, j+ f/ ] perror("malloc fail");
, J! r. D% c" f9 ^9 _ return; u9 k) j0 K+ A+ J2 }. ]& U1 E
}
- `/ q1 w" g6 ^9 f/ b H) x/ J1 D* l9 q4 Y$ f; p; |% R0 m
int gap = 1;
: k. s- Y/ @! `( r+ i1 @. n while (gap < sz)) K- X: }* o; c9 B, h9 f j
{
# B; E, L8 T8 g) b9 T for (int i = 0; i < sz; i += 2 * gap)- w$ i7 P1 S$ u Z
{# O; W# Y8 ~: a3 A# i J
int begin1 = i, end1 = begin1 + gap - 1;
, b1 g. S/ E) `, P int begin2 = end1 + 1, end2 = begin2 + gap - 1;1 ?/ B7 d2 l- j$ f5 }8 \
int j = begin1;# H: O0 z8 `: D% T9 u1 Q
# K. l( f1 W8 |' U/ ^" d0 `6 \! c //归并( ]' n' {' { k; _' A! t
while (begin1 <= end1 && begin2 <= end2)' N$ X. v' R! I1 ]( P* |1 S$ t4 D
{
5 \8 [4 Z, B% S$ e; q1 ]0 t if (arr[begin1] < arr[begin2])
1 ~% D" w3 f; N3 S$ {# h3 k2 `- b tmp[j++] = arr[begin1++];2 p% B& T0 \9 f; ^% _; q4 V
else $ J5 D* E0 T. A/ o
tmp[j++] = arr[begin2++];
}/ A! @! c1 P6 c }
7 Z% l! m' x* s% G+ ^
" K- t, p% g$ ~ while (begin1 <= end1)! q, A/ _5 r: W4 T$ w
tmp[j++] = arr[begin1++];
* J, T3 G% ]6 m7 C7 \ K while (begin2 <= end2)
, [5 @+ p" S+ \9 X' S tmp[j++] = arr[begin2++]; j+ H# x1 l5 S1 O, D
8 n T( K; r# J //拷贝回原数组——归并哪部分就拷贝哪部分回去. W! }, u6 Y& G0 Q
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));6 }# g0 c" b) d- M, l
}; H8 B& y- G/ P5 G2 u) X
gap *= 2;4 \0 R, ~7 m- a
}
3 W. a$ a& r9 Y2 y1 }2 V, J _6 H3 d% }9 O1 L* I b5 w
}
' {6 i! d8 T2 r
8 E- P, x1 O3 C' K. T7 y18 E# n# b/ V9 C, T% G! X$ i) j, J
2
# s( Y# A* R; j- Z. t31 [: K9 l) Q4 L$ I' H5 w; {3 W: R
4% u% Q7 H7 S+ ]# `& p6 H( S& R
5
. J* T# Z& U; P) R4 M. e" L6* k5 k* a- i- Y; m
7
2 @+ V/ x, R+ B- [- K; Y9 h6 L- Z8* E6 j0 @! ^5 ~+ v1 O0 Z
9: Y4 ]1 C) U0 B% Q$ M6 t
10
" r2 F* @3 w( z11
% r8 U7 ^& M/ ~' U2 S12
+ I- G/ ^% K! Y13
/ _& E6 B6 ?% \# r1 t! M z14
2 y! c& d" ? u153 R6 ^0 Z. u: R) }0 \9 [( G
162 H& ?6 ]' J6 @( q q$ y k! q
17
7 x0 y8 i( b$ `: W18
7 B& @( t: Z% [! Z& ^& P) g M197 T7 O3 X1 c6 ~* B) E
20) Z* [( J u% a: T8 x
21
1 q/ S4 E: u( }& ]22# W7 s6 R$ m. Q1 G. y H% N( j, @" k
23
* h) j+ |8 _2 \2 V; H) w24
6 A( ]8 \ y; W+ [0 d' U- i25" M/ s T6 D; _
263 \3 S% R9 U% D8 _4 q
276 O2 p2 N/ ?0 B- b- O7 M' z
28
& g) \' S6 N, N$ |2 W- {8 M299 L4 i! I# d0 P+ x9 z0 X2 ]: j5 W
30& V- m2 H9 `" a& v5 }4 C( ~8 k
31
7 q: V' V8 c( r Y: Z32 \% t8 C! _+ C1 i: V w" j+ f
33. E+ }3 j5 |7 p3 r) X* A
345 Q' H! i' s8 x0 y' _; o- `
35
* ]$ s! n! s! @4 r, y- c% ^36
4 z' `" g' j1 ?( x4 C: Z37
3 K1 ^& |( P7 S2 Z' H38! w+ N9 Y }$ o- d6 E
398 V( ~& c/ j& s9 m# l. A
40
/ t% d$ @# R$ q: D41: Q/ I+ I: k9 |6 ~
边界问题
6 `- H+ E# B' o0 l: l* Q 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。, D+ D: v/ v+ O: K$ U6 p+ h z
* Q0 P, s5 j7 x3 F
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
9 A* J8 E' D6 A- {
; k! b0 i* ]. w' g2 }" }( Y* B
% v' {! N/ d* S% c8 V ^; ]; y# [( L( j; p- c: q* l, b
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
: b6 w% n1 G& C/ S* \4 I/ I* \ n+ t n6 a
第一组越界(即end1越界)
+ l, {$ b3 z3 {; S& I8 N) s* ]* p# I
; b: q \- a. P; U$ T应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。: g, ^7 |( W! h# n. [. V
6 B4 T# p) d# q4 E5 N
第二组全部越界(即begin2和end2越界)
/ z) o- _( s# e% j) R _/ e0 k0 n& e
% V q0 e0 {& R& w0 L$ v/ C# g应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。( ]8 s7 n( x1 Y6 r
" y4 s$ i' C# l3 G3 [2 H第二组部分越界(即end2越界)
9 g T9 j7 P/ X3 X9 ~. H; [9 B7 d5 ~6 f0 C: @4 f) h2 ]
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。7 c3 y5 U. J5 g$ `5 z% n7 k
O: U4 U0 b& z; m, i& F9 ^
其实第一种情况和第二种情况可以合并为一种情况,原因:
8 ] m3 L0 x. O5 I' h R0 z( C5 i q1 d6 k
end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。7 k* g% o/ h# M( E2 ]; h
9 }: W7 U; O% C
拿两个数组试一下:
# k/ I* x0 P( J: G$ h3 r! i8 c; M$ T- k1 v5 k& W: Y
8 L& c8 O6 s8 W4 E4 Z3 p! i
( R, c" t1 y8 ^% g+ [' T$ _* I+ c e2 q4 O6 h, b
7 B6 y7 N4 p& ` h. s" o# I代码实现
r' R$ t+ q- B) p& G
. b) }$ o8 R) L. ~$ {& z0 vvoid MergeSortNonR(int* arr, int sz)
! g; O* E8 f: f; ^{" Y/ @1 j, X+ a% ?8 T% A% L
assert(arr);
+ _9 H& I# S- x# I t
; I2 t* ]6 K; ^ int* tmp = (int*)malloc(sz * sizeof(int));. d) z! e* |! O' R# n
if (tmp == NULL)
4 G3 @" L$ E! S9 Z# s0 A {& h8 l% U$ ?! t3 s* f5 w
perror("malloc fail");! j% M/ G! E6 v. k: o- b7 R
return;
6 s. S& C$ d5 V8 \" ]; w }
; C* n. p; `4 |! O/ |* b
4 ?; H6 }3 H" p9 U! E/ f int gap = 1;" G2 E" S9 i* F+ U" q1 f! c
while (gap < sz); t7 d# _. M, E$ J& a
{3 s( E1 D! L; B
for (int i = 0; i < sz; i += 2 * gap)
) d' L4 T1 X3 z$ F# M {
( k$ W3 ^* ?+ v; X int begin1 = i, end1 = begin1 + gap - 1;' L& c) Z6 C- s$ C& E1 a. n
int begin2 = end1 + 1, end2 = begin2 + gap - 1;' |, v3 d, s, ~+ ~
int j = begin1;
$ J5 k- ?# Q | //越界检测
& ] [: [" a5 P0 {# F% A if (begin2 >= sz && end2 >= sz). j( D; q. T8 p: V5 ^
break;+ h& p0 X" I* U8 `2 l3 k
if (end2 >= sz)
% p1 T y6 W* n0 l! [- z7 I end2 = sz - 1;
* u% \8 o3 E! j/ t. k //归并/ d y: C* u/ H& [7 s, w
while (begin1 <= end1 && begin2 <= end2)
' Y6 q: c0 [/ E' A {$ _/ }6 f3 R9 m; ]4 c5 @
if (arr[begin1] < arr[begin2])
$ K$ r' V. D' q8 D& a tmp[j++] = arr[begin1++];- M, L" y2 t) N0 b
else
7 g8 M5 ^, \) ~! }7 \2 m tmp[j++] = arr[begin2++];" }' }# \6 e# y
}
# h! s+ @6 H7 v0 ]" ^2 L* N4 }+ m
4 G9 [; t+ b% D8 Z" y, `8 y while (begin1 <= end1)
; B4 V8 g4 P5 p: ? tmp[j++] = arr[begin1++];) G+ I3 S. M: y+ P/ n) l9 W
while (begin2 <= end2)# G' `) F7 ~4 q7 \
tmp[j++] = arr[begin2++];# Q2 t, x, Q' b
R8 A. z6 G! t1 @8 m' c5 G7 G
//拷贝回原数组——归并哪部分就拷贝哪部分回去
2 m4 L; O# s3 @ z, K memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));6 z, q* ?; M5 A# U
}! z+ }( M) {- W/ Y/ E D
gap *= 2;
, a& D+ h. j( F4 F. O% }. q }
1 M; m0 D' l# u( A7 [* e
* o5 w3 z3 Y9 @- k1 _. B8 P}# Q$ ~0 l. w; B( {/ Y/ p
" R; M W- P9 I! o" `1. E; ^! R9 Q) G% V5 O' u) @8 ?
2
. S. w0 W% Q3 {0 B! w s3
# }/ ] T* Z( K @5 z$ C) A4: F, h, y8 I4 Z- ^/ R. K+ [0 E
5
3 y* U2 {7 o* F( a# g, J6
! c: g8 R$ f1 ]1 K- j) {# T9 J7. @+ `, p: v0 t1 c# X$ Y' g" n
88 n- e: J" ^8 V: b* O. {
9
* \+ s4 M2 G' a( M! T0 h7 z10
: U5 y* W* J/ f8 A" @110 r; u; S7 e! M0 Z/ e. e
12
: H1 G# O( ]8 \) `& I8 L13- c' L' D6 q% d- j
14
2 z5 O- v+ n, o15
1 a8 ?$ F' N5 z: d16
% O) @6 @# F5 S% F17
( v: b" O" w! r1 h% y18
/ _; a& O K, @. c H! U9 n193 w% B: L% h& B; c5 e4 K3 G; \- G6 m
20
( { q4 j" i" S! D7 S21
) W. Y5 F, V W6 m22
5 L% F* w% H# w23- Z G# }" \$ C$ F
24; J! J+ g$ `) W0 L; F
25
- e1 S7 o- l+ Y: p3 a% O6 G26
7 b- M3 }4 } r; N/ h27
1 x& ~+ I o. [) P287 m3 g( ^8 L2 I; s
29
6 B, p3 _; e5 U0 x1 c; @300 _# s8 w. f0 y, Q. o {$ L1 j
31; V. n) b" q% C" K/ n4 ~ x, y" A& l
321 ~" w' o% ~% \0 c4 A" i: R
33
! ?! x$ Q5 i0 Q: e34
- E5 @" g( @. L6 _! [* h/ {5 W7 d35
2 C& W+ v/ d+ S0 r2 |36
3 Q: V- \' h' C) s9 L: [. s37
" @4 @; j- O: n6 @381 R/ q1 l% e2 M" n
39: y3 {" ^5 T8 M( A+ m
40
+ E. C' H# Q3 G- d" T41) @$ e; C8 E6 _! C: ]/ R5 {
42
6 s! p; ~; I" i$ w0 o% K43
]: P. z/ d; W( |. R7 p44
( r! B/ P1 e+ U! X0 y) C45, v) A* R0 ^4 c" r
归并排序的特性总结:
7 H9 u; n1 r/ } {. B4 g/ d
T1 j- d2 R/ p% y! c归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
: [! K1 j, M* T8 b& n; ^时间复杂度:O(N*logN)
3 ^; a J! ?* o空间复杂度:O(N)! x3 A2 |+ i0 M! P; C
稳定性:稳定
$ n/ { N) q3 ?7 k2 E. I9 f8 m! O' c1 o) i( b) ^ {
————————————————7 _+ E7 N- f' W- R3 w
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。" K* u7 |: `9 |, H1 c
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
! X6 h! r1 g: l( s& o- L0 p+ b9 Q3 v; C9 n. p+ _4 a5 R
5 o8 }% I' K- B& S$ T$ N5 U |
zan
|