- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 569710 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 176136
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序; T! u. G1 S5 ]. _* I0 x
* |7 T; p* Q: \: ], J; W前言6 S/ L; v: @3 V' h- R
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。0 E$ y4 y6 C$ p4 `1 a
. d* o6 f4 b5 j, A8 F- Q4 }归并排序
. R3 z8 Z I' B8 {% \' V7 Z基本思想
8 ?- q5 m2 U9 @0 t: U% P 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
n. q( @8 a- t8 l+ n, Y/ G2 _0 }1 L9 U
5 i+ E5 p3 l% ], j( i& v" P+ T8 e# C {0 w! _+ k
合并的思想其实和有道题目的思想如出一辙:5 ?% H, v& c1 b' b0 g( c
( z$ b% l3 @4 O) q8 Y& Q' P9 V2 M6 W1 X X" H6 f' _
; T* b6 k4 f- X7 A 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。* e$ ?% s# k2 m% K
~* ?$ Z6 j8 y6 F" @% c& P[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]7 z8 P, Q7 s/ w0 S3 M
- B6 P0 t- r- v3 ~ w
int* merge(int* nums1, int m, int* nums2, int n)
+ b0 K. |* H ~{4 _/ @. ]; v, o t7 b+ _
int* arr = (int*)malloc((m + n));9 w) V3 F' `# d3 M) m( M
if(arr == NULL)
. g3 E) w5 O& X4 k% R. g$ `% ? {2 O' r' H4 m* Z' R. V7 |1 k. U# f
perror("malloc fail");, d, \1 a& Q1 P f* _# }
return; x7 g2 F; E" X2 ]
} }+ s% B7 B z; w j8 T
! m) ^) l+ r. ~' P0 d# O int p1 = 0;( Z9 ^" p1 G3 ~
int p2 = 0;
0 u& ^+ ^0 k7 h1 m/ w int cnt = 0;
0 g' L8 g1 a+ H- l, j- q6 u while(p1 < m && p2 < n)1 l1 I, k/ U6 t1 H0 C
{; l+ S4 ]- S* ]6 X, Y+ m: S
if(nums1[p1] < nums2[p2])
' ?8 }2 v z; I- E* u% q8 \& z v {% M( q2 `" d1 v9 T+ f% B2 O0 A
arr[cnt++] = nums1[p1++];
' y% ~, F- E1 r2 F }
8 B3 B U1 }3 ~ else" H2 T) f6 G/ ~; ~) w4 h0 `
{. S& S$ j# N* ^
arr[cnt++] = nums2[p2++];/ W/ M2 @4 F/ X( v
}; I. t/ {! A' z2 R% z
}
[. A( ]6 R$ H$ R. X& t4 ^ while(p1 < m)
3 y1 M: r! Z+ l/ M- N, O/ `) @6 e arr[cnt++] = nums1[p1++];8 v1 i5 W# k: b6 ]: ^ I
4 V3 p; `. w9 X( ?1 F
while(p2 < n)' f5 o# D7 i, l
arr[cnt++] = nums2[p2++];( X4 y6 ?9 u* m9 t
/ p$ B3 ]; A8 b+ q
return arr;/ E; L# K B$ i0 |4 f# S$ \
}8 K0 I% ^$ A" B& n
& U$ h4 W( p+ n# [/ ?9 }
1
+ E- K. v1 K( D" e- l6 B/ w2
; y! k5 g6 P$ x9 k) M1 S) e3
1 T6 `' ?* v7 X/ S! L, T4
) `6 M9 S; ]( M; N$ I( D' T5
' q/ s: l) x5 c9 l; K6+ n* y3 V3 H# C
7
. T+ q! \: o, v) z8
. P0 g) X% J6 [9
1 Q# K( l1 L9 D107 g1 D4 s2 E8 l, T; V t
11, I! ~$ M. ?5 E: P3 }9 A- ^1 j
12; a. @) I/ u% Q2 n" f
13, c Y/ w* z0 k7 j
143 m! a, i7 v) J% ^* P* X7 l6 D
15) M: {+ w# d4 Q t7 m# E; }& V7 O
16- D' } M7 R/ d. {0 z( m
17! t1 x1 N" n& o! t/ p/ M8 ~" B: y
18
4 w( C; G) p2 Q4 N' u$ w4 B4 H; s19
3 @+ \0 w0 r8 ]& J" ~, e20
: z3 ?% {; j% o( l' R& `, N* j21
3 E: I7 u) N( h) f6 Z22
7 B2 ^5 Z7 M2 B7 c: ?1 @1 d9 [23; p& x3 E& z* j) X2 {4 D
24
2 T7 S, y* q) \ G25; K" |3 G; @6 T- I4 G
26
2 X" x: A. v8 z( n27
. j2 L3 L' K8 K' @% l, E28/ V9 r- K4 V N
291 R- y5 S* k4 U; B: W+ G* g8 D0 W
30
* b6 b. d5 x1 c31
" m1 _- F1 i' S8 h' ? 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。( ?4 b% {4 i/ C7 @) l
/ Q! D3 ?" G+ @- A6 G J" W/ d& u9 ]
递归实现
6 k" A' V* d, q T. \ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。$ K$ f+ d1 W: }- `6 O' a
& U, V9 q1 b% o; C) i( H
& f. h1 N, X6 |% w2 o) _9 V! e4 o- _# H9 Y9 D% X& p7 M
7 ^# b7 G/ Q( _* ~# p4 @& n
# i+ ~) N8 Y4 T/ e; bvoid _MergeSort(int* arr, int* tmp, int left, int right)
, X- J: c- f t4 K6 I( V" V7 a+ N{9 A5 z( c8 \7 P/ I
assert(arr);: P/ v" z8 |* C4 W6 _( k7 B1 v
2 u/ t) k b, v1 p+ m7 _ if (left >= right)//递归结束条件不要漏了+ s( _) p8 x+ X5 l
return;
+ l" O* ~8 \$ m7 P
6 \& \; U6 F. q( L" m0 W int mid = (right - left) / 2 + left;( B: g- j# i2 u' x* N
6 ^% S* ]9 f- ~3 \: Q* m
//划分左右子区间[left, mid]和[mid + 1, right]
0 `' _4 d1 P) o7 f* J4 Y. A2 V _MergeSort(arr, tmp, left, mid);
! ^* C: X5 @; H* ?* M6 \ _MergeSort(arr, tmp, mid + 1, right);& R1 s( B0 n* G9 u/ Z
8 o# q# H! { D+ d- M* S //归并9 N8 ?, b6 s% Z: e' w. b |
int begin1 = left, end1 = mid;# I' A: }% s2 \* R5 D8 N& x
int begin2 = mid + 1, end2 = right;
0 m z- C6 ^+ {! B/ j/ H int i = left;7 `9 Q, b3 g) r6 N3 C& D. h
while (begin1 <= end1 && begin2 <= end2); Y" o# E4 p# ]6 y. t _
{8 A8 w4 s- n! }/ _
if (arr[begin1] < arr[begin2]); k5 X' J$ B* F$ w4 ?
tmp[i++] = arr[begin1++];
& [' f k5 }" x Y else4 x- H6 v: w6 J. i
tmp[i++] = arr[begin2++];
" B2 M6 y& `) Q' ]* f1 z }
* ^+ w' f% |0 X/ X
( ^8 [; I7 Y! y# L+ K' | while (begin1 <= end1)
# x& v2 H* m- i7 V- E* p, o- k0 p) x tmp[i++] = arr[begin1++];- S- H% n+ m2 J0 y4 w* T
while (begin2 <= end2) U0 ^3 Y' `6 i1 ?! l" `& T( B
tmp[i++] = arr[begin2++];! N S# s- M# C
6 L! t* x' F! h) c, s
//拷贝回原数组——归并哪部分就拷贝哪部分回去
0 ^! b1 L/ l; x8 X2 W; P! H //而不是拷贝整个数组回去3 F# ], s% u" ^: ]$ j$ o
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));4 z: A3 f* _1 ~/ a, ?2 H
}
0 [9 c, f" x" J) y7 O$ {5 R
) c, e, X9 V* ~7 k2 Ovoid MergeSort(int* arr, int left, int right)
6 t4 r; @8 W0 A V{
/ R6 h* d- B; B0 A6 S; ` assert(arr);
; v: f& W5 U) i- z7 w0 j1 e( h& }3 O; z" T( r* u
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
% G: Z" J8 H# n) v if (tmp == NULL)
4 T/ e E) Y; i8 `1 w) w/ G; h {/ d. [; M7 u! k1 J2 C
perror("malloc fail");
8 I" J7 B6 h: j" P return;
# Q2 h5 [7 _6 D8 \6 e$ M4 w2 i8 C$ ` }
% \( x( _; U1 o! u7 @. s# S* J E g, z9 r7 f' ?1 v! I% L
_MergeSort(arr, tmp, left, right);& L' T3 p( l8 N% ], E
* B0 k% t7 `3 s6 B6 A# M7 A
free(tmp);
) U7 V3 J: J- z0 ?1 J% v) P tmp = NULL;
5 W+ Q; x2 y* x}! T4 a9 x3 N$ U. h; Q! K
# I7 n( n( P- T3 f; t2 @! f
1+ k* {+ f) P& D
2, q) ]% r. f7 A& A
3) p9 g% m X# \+ m7 n1 U1 o
4
* [5 b" J. T" g4 T) ]- d5- A9 y5 A: g7 `* O6 U$ b! ~
6! A( ?4 m# d J2 Y7 s! T% h! K2 |8 c
7
8 @7 H- ?' O( O7 m+ |85 o1 H% v) L$ n9 f6 }8 W
9
# x" t5 z& m- u% B! l0 a10
7 c1 R) u5 h, P Z- r" [11/ X u9 H# U( G$ y& D, q
12
, }% `. Z) h0 B. u. m# F _0 k4 S139 Z& G7 z; G$ B# F, U8 ~
14
$ m2 x& r( U! T7 W* \15/ L( m& { o% H/ N
160 T0 {% q- I3 B. R& b* w& _2 v) c$ e
17' C# Z% |- |$ s. Y
184 O9 i+ D, g. b. \
19
6 O- R4 u3 \) x' h- q20
5 I+ `- h% E% W& r21
7 [0 g1 P% {2 Z/ h8 m226 v% ?# {: W( o( h; f
23& b: V2 b* Q s- j9 I
24
; Y" x; ~3 H% ~! G25$ u! ^/ l8 b1 y! ]& s
26
! _: X9 U3 k: p. C6 l4 R27
6 N6 K& q/ J: L3 q28
0 i4 [8 O7 U- n8 M R29
5 _7 f9 J3 [' P+ v( b30( S+ R8 ]9 S7 C5 @& r- S
31
7 Z+ y" m$ A% Y" h# i4 s32- b; C5 |& P: i9 ^: G( h$ w3 w
333 l: ?- o$ X) ?: [# K
34
7 N5 A, v- | i+ z( P9 w35
8 F; |: G0 M) k" {& h36
1 y$ B' Z" {5 W8 K N0 ~1 I' l37
, l r1 b6 v( R7 X& D38
! R5 ?7 t* `2 p+ ?397 C' s; n0 A) \
40/ O: s( T4 b9 m: A4 E6 f Z- q1 a. u
41
! z+ c8 j4 q8 R, p0 e+ F42& `6 q0 J, S6 }
43 k1 D8 [( P, I5 ]. @
44
+ y8 U0 L- ]7 }* }: k' ^" m e ]45
4 N3 |! _ C0 d- B1 ]5 Q46. W- n A8 z" h+ n! R* @
479 w. L7 V6 _ G; v% _ P
484 U3 z" U! }. p4 g e
496 X" T2 f4 J U& ]" ?" T0 K
50
; V- U1 Y- b; P, m5 o! {51
& Q( z; v9 O$ T0 ~非递归实现
+ K, }; N, e# \& F. S a+ y 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。: ]' ^9 u$ B3 r$ U6 f
9 @. n( p% L, F, f& g9 K6 H; b4 Q- e
8 c' j3 H% E* W3 R
9 _0 j) c& q+ d" }: x. i( t
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
( | w$ W; s3 D3 E; w, s. I b( g; D
还要注意区间的取值,每个区间就是一组,就有gap个元素。
3 j* i1 b$ P" d: P
' w5 v N" }. ^9 B2 p; g 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
/ o |3 p( S, q& \7 d3 L
0 g& y$ F$ u+ R; j5 U) [代码实现9 l- n) I& z" {1 y! v, s$ `$ [5 q
* g' e. z4 K5 a: E3 U& E! \void MergeSortNonR(int* arr, int sz)+ h( Y) c8 F* P- o9 e
{3 L+ v1 L: H8 s/ `" Q! U% Z+ G
assert(arr);
% d9 W8 v# U/ M
0 Z7 h. E" L) E5 N2 A" |& B- N' k int* tmp = (int*)malloc(sz * sizeof(int));
$ N J! ^/ j7 Y+ c) q0 g if (tmp == NULL)1 T! i- [7 {2 `% Y! U* y
{
& ?: d: a9 L- Y5 E perror("malloc fail");3 Z) e( v1 r3 Y: Y( {9 |3 N( l
return;% f3 A/ K% ~! w# c& M2 s+ Q' _6 z
}
. j5 `8 r, p- Q1 `, M" e+ z: C
int gap = 1;
7 Y5 L/ P2 M; }- G6 o1 O while (gap < sz)
" v7 U' q% r/ ]' J- G {: O) o; c' L, o
for (int i = 0; i < sz; i += 2 * gap)! M J7 ^. Z1 \! T% q* r M
{
) q+ q. j( T/ S' o4 g, ` int begin1 = i, end1 = begin1 + gap - 1;9 b7 P- t- q% F/ p/ H4 T! ~( k7 m+ u" @" w
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
& _0 e6 u9 _, A/ c# k1 c int j = begin1;* R5 w& |* e& \ M
6 I) n7 ?4 U# v$ J! m j
//归并! v3 B* y7 L( |, c2 i
while (begin1 <= end1 && begin2 <= end2)
; U% i6 f$ S" o: E, n {- W- c6 \/ k* `* i8 Q. S" Q" t( }( {
if (arr[begin1] < arr[begin2]); P* b) X' E4 p( m
tmp[j++] = arr[begin1++];
0 h2 Q: U: l: K0 ]% z* t else
c+ C$ |4 R* P( Y s! C, y2 W tmp[j++] = arr[begin2++];
% ^% R6 v( t; B( h8 K x }1 n$ e7 ~$ V7 F8 U' }
( Z5 T. @" u5 M; A& N2 B8 A- Z while (begin1 <= end1)
& `9 z, @# T @; u- j. H" M* B tmp[j++] = arr[begin1++];) R- k9 ?& q0 r: V8 R- Z9 ~
while (begin2 <= end2)
# ^$ i: `5 M7 F3 A& Y1 ` tmp[j++] = arr[begin2++];
& Z+ H, z; Y. }
" {, X, a' s# ^8 Z- N //拷贝回原数组——归并哪部分就拷贝哪部分回去, `. N4 m$ j1 n' j. I' Q, K
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));$ }# z$ w. V/ D1 \; g
}
/ j( m8 K! e: u1 \- c gap *= 2;
! A$ K) @2 T2 `' @9 }2 a }
1 O' c! n# h5 P9 Z4 l6 u# V5 ?7 @4 `) R `, T% H
}
6 U& g; u+ B: F% q2 @/ }8 {; K' P+ C+ ]% P3 b2 R
1
) O/ ?& u0 W9 R/ x3 `2% ]5 G$ C1 _) f1 t+ y) z
33 P8 v# Q$ S6 I! A7 r( }# B8 j
4
# E! Z, C/ n9 q8 w W53 D7 F5 g* p2 B4 s; w+ ^' ~
6
4 M5 Z# k3 g9 f) [' N; A7& o+ d, |$ w1 f9 ]( D9 z! g
8( W, b8 ]3 L) d$ I- k
9
9 ^: j9 h5 g+ m3 n- e7 Z103 t3 g* l% W; S9 p, Q
11
' Z% G+ q4 U. Q12
) s& P* K7 E, O- A- l13
6 p& {% @/ Z. o6 ?( s14
+ M& j& F7 i- a- y15; W# E; h; @; k/ c6 k' e9 {6 ~
161 ^+ I9 ^$ O7 i* s0 Y
179 b' p- |2 U$ l5 ]/ v4 \4 y
18
. I: A @! W; B19
4 M& p8 Y' l; Q) I9 [20' u) ?# F. K b5 X3 ^- j/ |, Z
21
+ U: ?& M! t$ E9 [4 g C! w22
O) ]2 `0 P, ^* L. S M M! R, U23
% s# Z' H% B' {& k2 Z' Z$ H2 l244 u1 f" J4 T: a# n5 d) b
25* o5 ~, S# E; O, u0 `; a
26; A9 {$ y, C' p3 ~/ P$ ~
279 e' b7 S1 W) z
281 C7 A( r7 k$ W! C( w" @0 _% f" l
29, X& n& H) _5 b: C, O4 I
30
1 {: R8 _% M, h! T# C; U& R312 L; i! k3 W8 V1 n% V0 m% Y% ~
32
- b3 w1 {" `7 J4 N33) f& z, G' P) p2 Z9 P
34- m6 {! M6 u& r, O: h
35
7 I" J/ W" K0 B! W* a8 q( u9 M7 D3 J36
7 V( z. x/ `$ ^37& @/ t! ^' \: d( }. d- Q7 K
38 `- z/ o8 U; P" v: o3 j
39 h& V, x# m+ U" L
406 m1 G, U8 s8 }* e! L: |
41. N8 i8 }$ F- Y6 L# E
边界问题5 M/ E0 Q, R1 Q& T2 n
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
6 y7 c$ j4 l- i
4 y" d+ V3 v# @# c- G! x+ X% X举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
8 o, k0 v1 `- w9 T ?- @4 R% N/ n! X" i( p: `. |
6 n5 G) {/ r6 b8 b
- T B& u8 b" v/ l由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)2 S( N# f) w" k7 G1 k, J
4 n& W# z8 C% N0 N- W: t) B# m6 m% |第一组越界(即end1越界)
! b& @2 T L8 Z7 }6 u3 o2 O! f) r
. o# B" N) [( z; H( u9 T应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
/ n6 \/ R5 y: L3 B# n* Q: O
I e/ E0 Y% F7 Q& W7 ~2 w第二组全部越界(即begin2和end2越界)
3 Q+ q, i! E2 i/ I9 M8 n
# M: O7 }1 c: Q( U- [; L应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
- D6 d* P5 `' }& Q2 B" U* T+ h [: m6 A
第二组部分越界(即end2越界)8 @) T0 X, D/ U) o
# s# ~7 M, N! M" s; \
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
0 O4 F+ V% h; @+ r1 h' w# E% b( t2 T( V
其实第一种情况和第二种情况可以合并为一种情况,原因:2 @1 I. @3 H. ?7 H) ^
% ]$ \9 d! G3 f end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。( F6 L4 }" Q6 {% w, d
: v* F' `# f* I! N 拿两个数组试一下:
3 c4 @" k. A; g. C
" V! N/ @+ b% Q2 B1 L" G9 {; L, h% Y
! n% H. C1 f5 f8 \
9 v" Z9 a/ J1 U* Y8 t" ~/ W4 O1 U- E' S# A# v& f0 A/ x
代码实现
2 o6 H/ f. I' p8 o9 v Z
9 e+ X- u+ c3 ~- wvoid MergeSortNonR(int* arr, int sz)
' [! C" R; d2 `! o{
( p' Z) V* d' f1 |1 Q, K ^( E! g assert(arr);
* T- q3 l) L; D$ y: _8 `- m
2 ^9 K+ V% J3 Q# H ?. M8 ~ int* tmp = (int*)malloc(sz * sizeof(int));3 a6 t- J" N$ Z7 S. S% Z0 `% ]
if (tmp == NULL)0 k# Z( @6 y. E( J2 N
{' X* r/ _, ]- n- M. ^- u
perror("malloc fail"); s: h- k# P5 A9 y& L7 {9 R
return;, h1 K* K* \: b' `) k
}: I7 I( j4 Y9 E' j6 M4 K
* S- G5 e8 |* {+ u
int gap = 1;+ R8 Q) ~1 Z! p& R$ _8 X
while (gap < sz)" f" ^* L4 E* J H
{
3 F: @0 U" x: [- X for (int i = 0; i < sz; i += 2 * gap)9 n, Z4 I5 {' q, r+ f. W6 ~: l! l
{
3 S7 G1 W, H+ g4 {9 |7 Q int begin1 = i, end1 = begin1 + gap - 1;
# l: q, U9 d8 }' f$ K2 `* A int begin2 = end1 + 1, end2 = begin2 + gap - 1;; P* j$ D/ d8 Y* L3 a7 Y6 r9 r
int j = begin1;# r7 M" M; J9 r/ d
//越界检测
' l, E; d+ x" b8 F8 T if (begin2 >= sz && end2 >= sz)
# X( v- U" x1 b O; q+ n break;
+ e7 j- x, c9 V. p1 W if (end2 >= sz)
9 f/ w* D5 r5 O! q# J end2 = sz - 1;$ S2 ]! P h: G) l/ R! L A
//归并
$ O9 G3 r3 |% \ S while (begin1 <= end1 && begin2 <= end2)
, s# U. @ l0 F; W {& ^7 J* M% m' O3 Q7 d+ I) v
if (arr[begin1] < arr[begin2])6 R# E6 i$ S9 n& s
tmp[j++] = arr[begin1++];! V1 p5 a8 v6 O& m5 Z" `
else
7 w4 N( U3 {+ h2 z; P0 ` tmp[j++] = arr[begin2++];
5 G0 x9 @; x5 b8 n) m }
, Z+ B, w- K) c8 \" A' z8 Z8 x* h% p1 C; v3 E
while (begin1 <= end1)$ d; d8 ^/ \0 } T
tmp[j++] = arr[begin1++];
) b$ }' P( v, k( b8 Y3 f6 ] while (begin2 <= end2)4 m1 p3 |: a, ?9 j; x
tmp[j++] = arr[begin2++];% t0 s1 t) E+ F
$ x7 Q8 n9 d( h* v k5 F
//拷贝回原数组——归并哪部分就拷贝哪部分回去1 s" P9 J) N( [" j
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
6 \4 i" L+ @4 x) e+ f/ p0 \ }
1 G ^: V6 O. @. L; b, a+ d/ Q gap *= 2;
& v) [5 j, E$ S9 q) C }
* H4 X. @. |: w5 k3 Y& H% O2 q0 f2 _) ]4 |1 [$ W4 z0 r
}2 ~7 { d3 D' t% o+ K
* m0 o/ Q, x/ T* F( l1
/ `5 d# x: ~) T) d2
+ T a1 A: p( g! P' p2 ~' Z- O5 F3* b5 Z$ X& h' ^2 G
4/ e6 }3 t! x, k' ` h9 v; S4 p+ r
5
+ R8 p. |6 y) V+ b# _, p& F62 t( }" I. [( H/ k+ Y {# Z
7
. w) P* e+ _1 \' S3 x9 k. H. j80 @6 _9 b) A7 u9 ~
95 ?& `& {* U4 `# K# }; n6 X, B
10+ E2 x5 x+ y: n; X* `+ r8 v
119 j+ v/ S: y( w N3 ` J
12& W& c" T4 f! |1 f& f* o
13
& d+ p& y+ k! v& F14
( T; k: \+ r7 A* b& o" `15, b) J* m1 r0 ~% z& j
16
: u/ z+ O2 v' W& a& i1 e$ h/ J1 N. j17 D, u# N5 k( H5 ^+ l5 L1 q( i
183 X; {$ k p3 \+ l0 B; o! d
19" l2 w! z! J' u2 T; i$ b0 z. ^1 b
20! P: T5 M+ X1 }1 @! u
215 i+ {3 X, e" k- i
22
) n! M0 ?: o) w" b2 B7 U( r; M232 _( i# \& p! J% n
24
* v" h- _) B6 ?25
8 @( ~; k& G4 i/ v/ y( r26! z" z; a# H3 q) m. L& P
27% M5 Y, H' {9 @5 [. V' L
28
3 i6 Y+ [& j1 D; \6 ?/ E3 ~+ y29& P' }, P: o7 j" w
309 r3 ?2 H" U( I/ d& Z4 ~
31
3 F; K$ `$ L% f% w. u# F32' i& S( E+ r5 Z3 S5 E" G/ D0 {0 i' R7 Y
33
0 _: c/ ?/ x/ i0 m34
5 [4 k+ a$ d! o; I5 f$ r; F35" u; y& ^: `& a3 E9 u
36
8 k" t% F9 P C, v+ ]0 O/ Q$ I37
6 h1 [6 W% i3 Z& X38" w" ]7 l# o# u% p7 A0 [5 m8 u" L& {
39
7 F5 `* Y. r5 d" `7 D2 v40
4 r9 B& h8 }5 c41& l& p* k/ H$ t& x4 l, `- z
421 {. n$ ^( j% n6 B( b$ |- S
43
' J$ y* P: n& l: [' r44
: h4 `* ^- [ a" ^45
! N( X5 C. K: U* i$ W4 `7 a! D! g归并排序的特性总结:
4 G- C4 U0 j6 ~) u7 b" }* ~8 z1 x8 A: ~$ r" a( b
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
" e( r8 b% p, N, B$ u0 g, v& W时间复杂度:O(N*logN)
, B6 c; R7 ? J5 x# y空间复杂度:O(N)
9 ]- T8 N; c: V' |1 X3 A稳定性:稳定0 ]: }8 G2 A l9 s
2 C! W( C% u4 a. [" _9 _————————————————
. y3 [# @$ l2 `) R& j: f版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
5 c8 d- N* M. E w原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
* v- X, p' {! V& @$ o
, v; g+ O) z& ^$ }9 M3 f! u2 C# \9 o0 @7 ~( y! M7 q* B
|
zan
|