- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 564700 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174633
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序/ {5 A6 t# O) T& J+ t4 e; }
# d8 k& G& e- g/ i4 ^: p1 ?前言7 \- q& u+ p) c- _$ t+ \+ y: [# e" p$ Z
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
# N# k& ~; r8 i7 t+ s
, ~$ t1 m# f% F8 C3 ?. d9 s归并排序9 _6 B4 L* }+ V9 ?, X
基本思想7 f- B B6 u7 w" ~' v' B
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
' x$ J) D W1 {1 r& p' m' g# U/ Z( Z! O' E2 V: N$ w) N
$ `& ~' a* [6 C* m: c! N8 R! Z2 U+ R
( e9 \2 ~0 v2 Z r% V; L/ B# _ 合并的思想其实和有道题目的思想如出一辙:
) z4 x9 i, v6 w% r
. f, F1 y& ^: X. }: C4 b9 n% ~; _$ j' o; h3 f5 s" ~4 N4 e
+ x6 d* T) i/ x1 A6 A+ m! Y 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
# H% z$ Y2 t4 F6 |% @9 _& e2 s8 n8 i0 j. Q$ {! n$ a4 }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
6 f. H" C- Z- F K: m% ~7 d3 C: p( C; L2 n; V1 O0 C
int* merge(int* nums1, int m, int* nums2, int n)! K, X6 f4 S8 H' t
{! E% O( Q9 C. C) v6 P4 d
int* arr = (int*)malloc((m + n));
. Q; b' ?! P% y) ?" y# _- [ if(arr == NULL)
, F8 j6 `+ m% o; F {
" h5 `' z2 l6 m$ x. c/ I perror("malloc fail");, O( M8 w1 }& ?. J
return;
6 D+ U) T% n/ G' `2 u/ r$ _8 h i) o }& ^& s6 I7 R" h8 Y0 r
% L. c5 I. z$ `3 e7 | int p1 = 0;8 f# d) d- q. f& m: Q
int p2 = 0;
; A J5 _& x5 F4 y int cnt = 0;( F* C: z8 u8 c7 ?$ v
while(p1 < m && p2 < n)0 h, P; q# S. G) F, j1 B$ [
{
5 f1 c+ Z( q; ~7 W4 F, S/ f. M if(nums1[p1] < nums2[p2])* D7 J( h# H3 i* q H
{; ]4 Y+ p. R: u2 U
arr[cnt++] = nums1[p1++];7 g* p) c0 a) G. K& d7 |, q
}
) }8 ~! @2 T, l7 ?4 U- q" { else* u- }# S( O, P: ]) p9 q
{: ~+ S- @$ f5 H5 s" v/ ^
arr[cnt++] = nums2[p2++];
! d5 s8 B3 f+ Q! o0 N }
6 U+ J& i. ]3 V( ] }- d0 q. o X7 G- \2 B
while(p1 < m)
# A5 r) I1 A3 P# v2 X2 Z' [ arr[cnt++] = nums1[p1++];1 O/ d7 k" C" x/ ^" v, o5 D& o Q
9 V! U" _/ K* o, N; B
while(p2 < n)7 O, v% v' p" C# b2 d6 ?. @4 Q" f
arr[cnt++] = nums2[p2++];
3 f1 A. H% v% g7 C! `+ D' n- }& v! K0 u3 a& ?5 s
return arr;
! I+ r; h7 ]8 w' S}( i" ?9 a# W# m/ t
# a9 Q( L) P! L2 C$ |8 b3 w1* x: A* S3 z D
2
& f) S! I' F3 B. R/ y# G3+ W0 b4 W# n$ W+ \
4
; R* m, ?0 u! y0 N2 c* G1 E5) ^4 E) R. @1 _) X
60 ~2 X. {- `0 d
7( r% D7 H9 n" _0 q8 x0 E n
8
" a. b/ ?( C# h4 w8 [95 h) p: d* r6 W: C G+ d \0 L
10
4 e9 G$ c! f; Y) B2 M8 Y) X1 h4 b& c11/ i$ D- k- F: Q! k
12! r! n$ }. u" G6 @
13) A6 _- e% O3 T
143 y3 D$ G6 Z1 A; O: O4 b3 t
15
) s; O' d3 ^" U# f+ Q% ~0 }- y16- X+ T8 T' m) ~, W* W
17
" w4 D5 ~, S5 M2 y7 R; d: b18
* }8 j1 I3 }0 E/ V19- w, G) \$ V: Z) b( L9 Q7 E6 V
20( X, U: y; |$ @3 _, V4 T
21
+ Q/ G3 t3 e! ~6 r$ Q) V% Z22$ h5 A% Q+ d+ a4 V) U, n
23
- Y0 b$ O. v1 y5 | v* U24
( x# ^$ y4 Y7 Q5 W25" M2 a3 Y$ Z3 I6 J8 _
26. a) x+ Z% y% X/ {: j3 v
27
1 _& B1 z( s6 e' [! c4 H* I28
! h1 F" I+ x+ B) t6 T; Q29; L: g1 R$ o+ f& [# e* h2 X
30' p, K5 g' D. `' l" s4 H
310 h) i, J. v& A! S+ W, o) t' X
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。8 ?' |% h2 L3 f# m5 {- s+ S
2 d* s3 ~/ `5 g' m0 q
递归实现
6 K, a$ R* Q" Q, E$ i* E, w 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
7 T" u3 S, w( w; ~
; v( R% S* D# m" L' @/ s' t5 c# M- J! I: w1 z6 Z, a" A# s% u3 a2 [
. I: ~: n) P0 S
) U+ L+ \& K# Z0 q3 F$ K- s! d6 w3 }& {* A1 y3 \
void _MergeSort(int* arr, int* tmp, int left, int right)- E' |& J$ u6 o/ E# L
{
% I' m- c9 S% \ assert(arr);9 y: w. o: e& f8 B/ J" A, M
& W, I L- S) ~. k3 a/ H' V if (left >= right)//递归结束条件不要漏了
) ~; R% i5 }9 ]- U! C& s2 B6 M return;- A% L5 ~; P' C, q0 R$ L
6 ?4 E: A# S( n( r5 {5 Y/ R
int mid = (right - left) / 2 + left;
3 ^9 s& v( n' H0 q% l% [7 [& T8 f/ O1 M: g4 P3 [& {) m
//划分左右子区间[left, mid]和[mid + 1, right]! m# ~5 ~! x( R+ b! @* ?9 D9 x8 g
_MergeSort(arr, tmp, left, mid);) w2 [6 Q# w$ }1 U3 r9 i. [; ~5 `5 ]
_MergeSort(arr, tmp, mid + 1, right);% d, a0 c* e! X) M
) q& Q% m6 h, Z
//归并% ]) w; C6 h3 F" ~' D( W: p
int begin1 = left, end1 = mid;7 V& S% h6 x5 ]' y
int begin2 = mid + 1, end2 = right;) l6 ?1 Y, ^- U- }# w( n+ E
int i = left;
8 G; u# S7 M) Z# v while (begin1 <= end1 && begin2 <= end2); G( e2 M5 k) O
{
' f& Q) J% _ i) s& ^3 x" u) I if (arr[begin1] < arr[begin2])
! q* s, A4 M7 p8 {0 k- w tmp[i++] = arr[begin1++];
0 m9 H7 i2 B( B: I, W4 g: H. Z else
- u# h0 }$ b& y8 R tmp[i++] = arr[begin2++];
5 h, N+ c+ N" [6 K. k% S }
0 P% {' _2 {( e
. {2 w# q9 F' t- z" N' s) @4 Q" o while (begin1 <= end1)
1 L9 g; `9 A' X& u3 B tmp[i++] = arr[begin1++];1 D0 v( l. X2 b' c' L$ |
while (begin2 <= end2)3 c1 r$ l% I" o7 C
tmp[i++] = arr[begin2++];* H7 ]) h. }( H$ r) S/ p# [
7 i# Y r: H2 f& N! a7 r
//拷贝回原数组——归并哪部分就拷贝哪部分回去) s1 ]. B7 O. ~7 y9 |
//而不是拷贝整个数组回去8 N2 D2 h8 d9 Y8 r0 ~7 ]
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
& B+ l2 S8 l7 K; W" i3 B}, t# r! J8 o9 Y
# k5 g# H$ i- I4 A8 f5 Jvoid MergeSort(int* arr, int left, int right)9 Q1 ?& z6 F- r" y" I$ M
{
: j9 m6 b* k' C assert(arr);9 M1 U1 Q- F/ C# R, u4 U
9 d8 o6 |9 v1 J
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
( z! Y5 e4 d8 O4 i/ B if (tmp == NULL)
8 ^ _* d9 m. A# T0 f9 O" L: s {" L: K+ }- K- s( w
perror("malloc fail");
# u |8 \ M7 n3 m4 C( n return;
" D0 q+ U9 Z% [+ O" S1 z }
3 `2 `" M4 }( n, y7 k) Y1 E6 t3 _( G! i2 p1 Y* Z, o- O3 S* T
_MergeSort(arr, tmp, left, right);8 m8 P* R% Q0 d0 V, l
1 y/ r8 B! j9 l. [
free(tmp);
2 ^, V9 J6 b: H5 x5 ? tmp = NULL; Z% u; X: a5 d6 O5 P% q1 p1 X L
}
( u; A8 y, ]: s3 w1 T- ]' \
+ y0 M8 l l$ R9 i1
% E# K! n2 u4 @- b. ~6 G4 Y- B, f6 k2
1 k" z# g" Q4 ^! E; C6 n3
0 F- @) B0 h* ^2 H4
6 U1 Z K/ D. n" O R8 A5( ]7 F7 ]: }9 n7 D# G% g5 t1 }; E
6; o: D$ H4 h! E) u! K
7
& g3 f- R% X# r- t0 Z$ G( k8! D. m6 u; B( e% c! m, q
9- M- g2 {) Q6 e; {& X/ I$ V
102 u9 v# ~, i4 n' `( c9 D3 ^' P
112 W) H5 f/ `+ h- W% @7 Q
12
) g0 J; k. ]* d; \9 m- P9 |13) x4 C1 A; B7 N6 K% J
14 r- J: n7 @9 s2 I9 F
15. Z% K- C5 U+ E; s
16. L$ b) i* q2 z$ `2 P7 v
17; y) o P+ ] w0 P$ d) l
18
: f( ^' S3 X! R, e& K) V198 `4 d: H! P3 S, j2 O) m
20' @+ T6 D* o+ j6 j" e
21- N6 _) R, ]( F! G" m
22; ~+ K( v' C4 H& U+ y0 S7 [
23' t, @9 U9 ~; E# }
24
5 B6 s- Y! C) L25
6 _4 C9 N$ z) U( k7 x0 ~26! ?0 o. Y; ~, g. Z
276 \0 y) G+ H6 x) K+ ?) z/ b5 H
283 `7 J2 ^/ T/ n1 `0 Z# y/ I
29. c6 E: Q& L4 c. v0 Q
30
3 i3 Z) L2 a* ?31& b& W! F: ^, ]' F% v
32
" G; I; p" K* d" d33- c: ?8 `) @! X8 {3 q( U
34
& s+ `0 g$ n, ^9 q0 b35
4 S3 q' C, a9 }- i/ I, ^- \36 m6 F+ X/ Z/ T, s: j4 o/ w2 m2 Z
37* V3 r8 g$ Q, ~* r' T7 M# U/ H
38
- E4 f' ~/ |, t7 v' \& x39) }6 n7 H- O5 O& Q: ~& `
40
$ N7 g o" U; Y41# l# m8 y1 M3 i( o0 n% y. K# w& w
42) i6 l4 `/ \ N6 L
43* Y5 n4 X2 H" E
44& s) | Q1 B; f* M0 S" Z0 ^
45
5 F! |5 Y" u5 U* ]) [$ C46' c& X w9 o% C5 G
47
' k1 H) w% ?/ j J' d48
# Z# X, _( q" i! H( n) P49
+ X( W( Y+ M$ X$ f% k f, l50; w s6 }6 h' t; l1 @* X
51
: L# y; m+ g8 s+ }2 h" I非递归实现
. |! v. |3 d Q- v2 i1 f$ l 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
" h x) G6 m/ x3 R' F+ |5 I- e% ?: Q5 t1 G1 L
8 y; Y% N: b% A+ t/ V- e
1 P/ ~4 C3 l9 W) d; O) \5 T 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
4 M8 N& X: d. G. u1 [3 w. y; I; y+ i! y- n% K5 x0 @- u
还要注意区间的取值,每个区间就是一组,就有gap个元素。
8 h* [6 I: @8 }6 `! Y
( C0 h' Q$ G. x 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。; R/ c: a) W/ }2 `" Z4 M
) E+ c) x# ?0 v9 [
代码实现
9 r. ]* U# z- h! {) H, w5 a7 J; n* N) J5 } v( o" C- Z" y& Z
void MergeSortNonR(int* arr, int sz)& @ I. r) D$ D& B' ]6 {
{
2 z1 Q, b( c4 h1 ~ S$ @ assert(arr);
4 }' t" \; H+ D) ^/ V
. y, D8 N* l4 q2 j W0 d$ Q5 V int* tmp = (int*)malloc(sz * sizeof(int));
+ x! P. f) z l if (tmp == NULL)
# g. v5 Z/ o2 i% G3 F% Q4 o! S {+ d% i j4 |4 s4 T$ @
perror("malloc fail");
$ [- z1 b i6 a* p( u return;, t6 \2 J( L& ~* a
}/ |6 H# V! _# b: A, ~1 n5 Q
; Y5 ~$ B' _7 U* p! P" |; F9 o, `
int gap = 1;
/ p/ K8 f- |' A! S: V: d while (gap < sz)
: o3 r% N- g3 X7 G3 B/ ~8 G {. k7 @/ ~" k5 r: \
for (int i = 0; i < sz; i += 2 * gap)4 H$ _$ P- D. d& [4 c" j6 F: n$ `3 m
{3 E% s& z. y/ u0 i
int begin1 = i, end1 = begin1 + gap - 1;5 s8 s; \3 R2 M, r# g
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
5 G% r( _4 w" ~3 ?% b# A. _ int j = begin1;
" i- B8 L# Z- `7 W4 `0 u# e7 B) z4 e) H0 Q
//归并3 X. r) }7 h* o: j/ R# _
while (begin1 <= end1 && begin2 <= end2)
; B0 \, k h, p/ T) B, B {
5 T( W8 e, p: m$ \/ e- F4 Z if (arr[begin1] < arr[begin2]); n9 ~ r/ c# ^, z
tmp[j++] = arr[begin1++];' Z- @$ {( U# P; p
else
7 }. _& [/ W j# G6 f& i tmp[j++] = arr[begin2++];
* U0 D' f- n8 T* \& ` }- {2 |: U3 r1 n8 u! Y, r
: ~ k3 ]" k5 F6 P# S7 G0 ] while (begin1 <= end1); @$ t$ h# f4 k- d% o. m' v
tmp[j++] = arr[begin1++];7 ~+ _- C5 J& Z3 g, }! k1 x8 Q7 s
while (begin2 <= end2)
; R2 H' W9 m1 F |' ` tmp[j++] = arr[begin2++];
]0 m* v' W. ]" e
/ k4 @6 ]+ v/ D U //拷贝回原数组——归并哪部分就拷贝哪部分回去, A$ c$ s' i7 `0 z, T/ ]
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));5 S# r* i0 l" G1 J
}- C& Z( P3 v; Q% j$ S/ P, |' z& w
gap *= 2;2 x; r4 {7 g( l3 Q; R3 q
}+ G/ M1 b/ b' m3 _7 Z
( E4 z+ y. o. L- N, v
}- R h, Q) }& U \
( _' b7 s! Q8 }1( X' h3 E. W' E
2
6 u6 ]& I& h) [8 n3% B) D4 [ p* O- _
4& Y3 v7 X! m4 _' T: K
5
9 l+ Y8 h! ~# _$ n; ]65 W# D* P2 p! h) R9 a% ?: o8 k
7
! _9 s+ x: Y. l1 n8
) ?' v$ M% Q- x& l, h9
) b5 y2 v; u4 k% y10
! A2 w9 c3 @! R" w3 \111 v# j6 v0 f9 ]. W |9 r) u! y/ X. O
129 B! D, s! c& u$ d& T ]
138 I+ \* F4 X3 |9 G
14
$ q. [% [2 M' B" a$ J9 A15/ e+ ~6 B% p- q4 f5 p% t
16
* D. G. Y$ ]$ i' b4 r" n* z7 `0 ?# d174 o1 W/ r7 D8 d2 z
187 ~, E5 q3 t; \' S7 j# V- {* h
19
' ] n( J8 r1 G& x& [% H20
% L6 P$ C* z- |+ F, k8 C21* W( \7 P0 Q7 [: u# d9 Z
22: Y+ @; K- P; M% o7 p: N( ?
23
% O/ A! w; p. q! ^24
8 p9 i& [- g6 h9 y$ ^8 r25
0 ]% U6 _/ t9 I3 @! g26
2 c' C' J4 g. _( J( p27
& z) f7 f7 \2 Q28
# v# x: r0 h8 r/ L290 f5 A' b# T" b* m2 G: g* c
30- F* U- d, P* m- P5 I' K" q
31
( k O4 }4 x9 z$ t" o32
0 H: c7 j/ F1 z0 W" K+ ?0 r33: @" h/ \( w+ e' ~
34
) X8 _; F. a2 q2 d. y" |35
7 T$ y- ]! ?2 R' S8 ^1 M- P36
& s0 {: T% [7 {/ }5 W! v! H" K37
- h, ]5 e9 {8 F6 W9 M" X38
7 W3 u) Q" U6 n& z+ U4 R39( ~9 x+ a+ n( Z' Q- W9 _" q
402 x, J+ f5 o) u: s# G- E
41. C) F/ \0 n8 Z8 f9 ~7 Y
边界问题$ l! I; y9 U% }' ^
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
" V3 G9 r5 _* k; m1 j
, [) O6 {2 T8 K7 Z( u# [( S( o8 h1 M4 a) Z8 z举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:; e8 S, |9 ~5 u% L
% j' v- B+ H# d! q2 f6 B7 ]
9 l) p9 L7 N$ X' Z9 m% s4 ~0 y: e8 d" |+ R
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
1 G/ I% _ F3 h4 ?) E/ d6 I+ T7 I: n( n
: ^% S: E k7 Y; \第一组越界(即end1越界)
# X! I" W: p6 t h" ^1 q* d: h6 T8 Z" T5 U Z% r1 O# Z n% M7 f
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。$ n& N* |% d( X/ t, H8 ]; ^
H* l+ b0 m- |1 |$ g第二组全部越界(即begin2和end2越界)
" L( Y @) E. {/ z! ~9 x5 V. G6 a# t; L+ A5 @" |9 j2 K9 B9 f
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
( v, j: ~; t5 A( P
4 x( l+ B- B" U7 ~- [第二组部分越界(即end2越界)7 W. m! T+ k- z% X
) h) w. ~2 P0 W3 E应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
+ ]# Y9 V! \- V8 F
; ^0 R. E8 Y( d 其实第一种情况和第二种情况可以合并为一种情况,原因:
: l! J! f" L5 ?" m' z$ f) D7 I# W: k3 d- v# z
end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。0 U: ]" @" ^& [, ~8 ~! J
/ w/ h* z, |* E9 A% ?9 l 拿两个数组试一下:
1 S* s0 z& |9 c1 Y6 z# E+ L. a5 Y Z! y5 z3 { R, A
0 t1 Y; r, \2 }5 C
h$ w' [; Q& B: S
! C+ x# {3 }6 @
- K' s2 Y% C, F; u' Y8 {代码实现
4 U m+ K, r2 g# O+ ?: e/ J% h. C4 a; ?
void MergeSortNonR(int* arr, int sz)# @: u, X, A. [
{. x0 \8 X6 k1 V' k& R0 [: L
assert(arr);
1 a" R& ?1 M3 e: T: y6 w# i: |. U, L
6 P. @% J* Y$ M( k- l8 d int* tmp = (int*)malloc(sz * sizeof(int));
" t$ k0 \. C0 ^6 V# M if (tmp == NULL)) U8 `% c7 T0 v5 U
{
/ E' W3 F( n9 S; B perror("malloc fail");
5 G2 [, P- o2 K$ l3 b8 j. `& X return;$ Q# v: e" u0 ^/ y0 j
}
/ ?8 w4 j2 b5 V2 }; w5 o7 } x. K& l- V. g' v/ p7 F" Y0 ?
int gap = 1;
$ i) M6 U3 y2 t8 @ while (gap < sz)
) T- I" ?/ J% A: _; j {# t6 \+ k8 ^1 ~6 L8 k- }% j, Z
for (int i = 0; i < sz; i += 2 * gap)
! `7 i8 G& l- `8 t% ~2 V {6 D. n* S1 y, s: M, q
int begin1 = i, end1 = begin1 + gap - 1;* l" c2 i. B3 h' U0 L) V! g3 [
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
! p+ s% \0 W/ A! m8 e4 f3 U int j = begin1;. A, G- Q7 g( r$ x4 X
//越界检测
, w- H6 ], f* I" L if (begin2 >= sz && end2 >= sz) w3 h+ ]! m# ~6 ?
break;! T7 P+ u0 l8 z( T. H1 ?; p L% l
if (end2 >= sz)
+ ~/ X5 d' s+ w: n0 _# o: r end2 = sz - 1;
`0 e! s4 z% j/ V& o //归并
4 n* i! Y) p) O1 [ while (begin1 <= end1 && begin2 <= end2)
- i8 e7 A% v7 ^9 O1 q {
?1 z% |. ?* d# R# y& N7 n3 F if (arr[begin1] < arr[begin2]); _3 r9 u B% w8 I. ?
tmp[j++] = arr[begin1++];6 ?) x+ W! G; f7 [. C5 I; l& p
else 4 t* `. \. T! s F4 o9 F2 Q8 m
tmp[j++] = arr[begin2++];3 I* I* R6 w" c/ C
}
& Y' R2 m, @5 }$ @4 R- T# e5 `$ U5 [1 y5 f8 V9 |- }- o! L- M
while (begin1 <= end1) e% V" L8 `6 V- f. L# B
tmp[j++] = arr[begin1++];. t( z; x: t+ D' K6 t8 v7 y
while (begin2 <= end2)3 ~7 y4 y# J8 S* L8 q3 k
tmp[j++] = arr[begin2++];7 c# S, s0 d3 T
0 u& e7 ~: s; r& ?2 x //拷贝回原数组——归并哪部分就拷贝哪部分回去
. S9 O+ J' l; J2 I' t memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
3 C2 }: ~; u3 `3 U8 |* C% h }
0 p- `) u, W% e$ V$ i4 a gap *= 2;2 c7 f. q! D2 P& H& q6 X* V1 h8 L+ B! S. `
}
3 j( C# i2 t' {+ p/ Q( M" _; S) k8 K
}
9 A( e* Q" ^- q- s, z
9 E- f2 h* U+ f* O" }- g+ O( G1
8 P( @1 I" E; q6 K5 {* E# d+ c2! L- _) I, m9 k9 H% ]
3
$ ~$ I' e3 X1 c3 Q* l3 E7 z4; M% M7 x3 W! H2 q8 j' Q M
5
2 R2 i+ m5 Y2 W8 r* z6; M# f6 `9 j _& t
7
% l0 G5 ?2 _5 T$ F" q81 s' _8 V' A) ]6 b
9
+ L. L5 ]! p& U! Z( Z$ ~10
: |% Z) a) H* J% l114 Q" W1 Y4 Z7 I. [ R
12
) t" Y4 d) n% N- J135 A" h6 j# X5 R
14: B$ M8 r# P8 m4 D4 }& Q' b) e1 K
157 t, F3 ?# I. e, S3 Y- y
168 Q, M4 E3 }' I) y) B% _1 g+ k
17
# ^$ Z- i/ z: \& O$ ~/ w18* b) |/ l* K l. U
19
6 J1 t% I5 E) h. z20
# p. V* z0 Q4 e21
7 \. f) S$ u! Q5 j; u) s22
; N8 X( x8 z$ `8 i' o) j: K$ t. X7 K230 \# Z4 @4 W' P) l! i8 R
24
1 @4 _( a2 f2 Z25
5 o5 v6 ?5 M" r4 n* |, D26- X3 n( Y! }/ O7 \( U) R; x3 y
27
" P( _" [) L3 p- J7 l* J28/ O* r* Z7 R4 P( N0 I
29
/ U+ a6 d: R. q# z$ Y30
. ]( S/ V3 I' c h$ e! |, ~4 Z: G31
1 w6 Y: n+ L5 D' W9 p6 I; X32/ [( S- M1 _/ y6 U2 G+ f
33. j' `, K6 f* z; N. s7 v* r
349 K; m+ E) v& z0 I8 c+ ]
35
* v2 D/ ~6 [" G1 D6 A361 [. h2 r( } ^; G4 |) N# }# V
37) @7 I$ J& z4 N+ G& U( T
38
* H- U6 j, p- U# i: L, S: o39/ I% L' K% @% x+ b
40
9 H; Z/ F) R8 f; y" J41- y1 u7 t( o% j) E+ d% ^3 q7 G3 h
42) d$ @- d5 c' b/ [+ Y1 @+ t" I9 X
43
- E& A2 K" T$ w* X3 d- D4 Y- A446 G- a1 R1 M- u" {1 z, {
45& Q+ z* k# o4 Z" A1 m
归并排序的特性总结:
; S5 o; b! ~& o& n
|+ [) j: c- p" E. i归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。- ~3 \6 r E" P+ H9 O: ]6 l9 v
时间复杂度:O(N*logN)% I/ h7 ^) S0 \1 E6 N5 I
空间复杂度:O(N)
, j: R+ `+ M% j1 C/ `$ M稳定性:稳定% L7 w0 C6 h! M/ ]. H' \4 _4 L
' J- {/ c; S! F* D5 S) v5 b
————————————————
( j( k: {+ ^9 N7 J, d/ x版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。7 ], ^ F+ c0 C6 ~
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
7 j' D* e& |% n9 L4 `7 x
9 j- a: o) q$ H2 q' G4 P, ]2 M- T
* f; O& Z6 ^( A3 ^3 _ |
zan
|