在线时间 1630 小时 最后登录 2024-1-29 注册时间 2017-5-16 听众数 82 收听数 1 能力 120 分 体力 565162 点 威望 12 点 阅读权限 255 积分 174771 相册 1 日志 0 记录 0 帖子 5313 主题 5273 精华 3 分享 0 好友 163
TA的每日心情 开心 2021-8-11 17:59
签到天数: 17 天
[LV.4]偶尔看看III
网络挑战赛参赛者
网络挑战赛参赛者
自我介绍 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
群组 : 2018美赛大象算法课程
群组 : 2018美赛护航培训课程
群组 : 2019年 数学中国站长建
群组 : 2019年数据分析师课程
群组 : 2018年大象老师国赛优
【基于C的排序算法】归并排序
8 u5 }7 N0 f6 L% F; W # Z0 j( \9 t- a3 M) ^8 T
前言
9 Y, b; {% j% d4 N 本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。- f! [; @0 P( t3 o; a# e
4 I# F: m6 X+ \7 o$ g6 y7 v 归并排序& p8 E5 S- T: i; C/ j
基本思想! \5 U8 M" e0 v4 R* k
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。& T/ w! O! Y0 r' R/ I' ]) g
+ P+ `; W, p& q+ `) ~8 @ 8 [: R* w9 U5 U$ `
* X# L: c, h! z3 U9 X4 g: s
合并的思想其实和有道题目的思想如出一辙:
6 ]6 I6 a; B+ p
8 x" l! K1 k7 J% s5 } , w2 n) y& Z( s) J& |# J
G+ B4 `& |* C& e1 g& }
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。2 M M# C$ J" t6 Y8 ^: I* x* b
4 ~0 u0 B" R6 J+ D# K7 l [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
' w7 t8 |: s: ]
4 _+ I1 s8 u4 Q' L+ R& P int* merge(int* nums1, int m, int* nums2, int n)
) J- b6 |8 Y! I1 G9 H C( R {7 c+ B% Q* ]" `% X
int* arr = (int*)malloc((m + n));5 B. U7 U7 @" [( O* P. H) F
if(arr == NULL)% e- j8 W0 P" J/ h: k
{+ s2 a! X- @* T2 p
perror("malloc fail");
0 C/ Z$ z2 s+ b/ p9 Q" j return;; d; y8 b% U3 [& A+ Q
}. R9 T7 M4 b& E
6 ^3 M! o% F8 q int p1 = 0;
2 r! a9 P6 t+ M% u. |0 Q- r4 J4 G int p2 = 0;
# y7 q, x: s2 |- R8 g int cnt = 0;3 ^9 Y( ]; u2 c, l/ L+ {
while(p1 < m && p2 < n)
. Z, Y- u$ G* ~# Z' D {
9 i' C/ u. |9 T5 \' i if(nums1[p1] < nums2[p2])
" d; R/ E6 p8 B( O; Q& r# E3 n( D {
* j* e: |3 H3 L! P( m arr[cnt++] = nums1[p1++];
; q/ }& R! q2 f" d9 G }- C" H' v2 \% M, u& v/ }9 o) j
else
/ \" _! D' z) w9 @7 O9 l {, X, A1 l' z+ ]7 r# I( ?$ q
arr[cnt++] = nums2[p2++];, J8 Y) |, _; i
}
) ^+ \. c; G7 R) C6 E8 B, z. t }
0 b! K" o& |# a2 i while(p1 < m)
9 ?6 n8 }6 C4 J: c; u arr[cnt++] = nums1[p1++];
" \. \7 h/ R$ p; i6 _ : |! M$ e; ?* j2 B. Y- l
while(p2 < n)
' F1 X% a; B: {9 p5 z arr[cnt++] = nums2[p2++];% J' [. i B ?, e
0 a3 ]5 Y( S3 N) c; _3 j: s8 s return arr;& U3 i8 o5 D' g. }/ H; Z: y9 y
}
* C4 }: m3 @( R+ i7 \2 m+ J
- a; G3 p; I% G2 L+ I 1
( M2 k. W6 a- G& B" n9 E; Z0 u- v 2+ H! E$ i: O0 T' t6 I0 Q. Q
3
5 O3 u) E4 u/ {+ N9 T; U 4+ V) D6 O7 N- L$ y6 Y. Q
5) Q4 ^+ ?* U4 F* O; J
6
2 N3 q7 T( x7 T- K! S 7" _" M, U! F& R. H' r9 ?
85 ?8 Q9 C2 A7 N" Y5 T% z
9% i2 t7 G& s! T5 C. y: q
10" y# @: B1 ?+ t% m. t
11
# w( l/ S# `: v$ q5 Y2 K 12 x( j4 h& }) A' u6 \ p: c
13
% s( q; w! _1 D2 T S3 f2 G 14
" |+ O7 r" O* j% v9 {3 { 150 k$ F' G2 h" E: F' j; x) u* c. a% S! R+ o
167 l( h! s# f {8 e# X5 a- W! Z
17
# @, b! O4 ]: C0 x0 |; g 188 E4 d M$ w" V- P
195 X5 ~1 `5 u8 r8 p1 r0 w. ?) Q
20, ]$ m1 \. K7 Q4 \/ D
21
) C. I, A# P% y& c- a, }; m 226 R* ~1 S! e' I3 F0 M! r
23- q+ W; R, j# u6 b
242 A8 c: J2 s5 B; l5 e8 M: H& G2 i
25& S* U2 K: g. b, n8 ?9 p
26
$ O' t6 y: ?4 J4 G! @$ V+ ^) u! V- T 273 q4 s* J4 H) D' ]/ L
28
' B! w$ k3 d% S2 K7 }4 V# b5 h 29
+ r+ ?! q3 K I 30% C( B% ~# [- G# Q! R# |' B" ^5 d
31
0 O4 z! H4 ^( ]8 A2 o 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。) s) A; e: p5 E" ~& [& [1 W
- W) G4 {' K! u0 N9 Z/ e! L8 k 递归实现
: K/ |1 E+ T6 \$ p, S0 H; b, r 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
6 R, t) p4 K$ e( ]% C6 k M6 ^7 s) x! F' M' u) W1 O
0 j$ h) s$ R+ a: @5 ?
* r+ ?7 \ E0 K+ b- s
: i U( M& O0 O% I' j* z) X |. E' n! c- |& a8 T
void _MergeSort(int* arr, int* tmp, int left, int right)% ]& Q0 M- {& @) F! E) L
{/ D' w: w+ w5 l
assert(arr);4 s6 q4 f2 b* z; k
$ e9 x/ ^# b( N7 X
if (left >= right)//递归结束条件不要漏了
" \6 k* E' \; g, O6 U2 l @ return;7 Y! M6 z) x+ ?9 w% a D
) j1 W/ ^, u/ \( {0 a# O7 @ int mid = (right - left) / 2 + left;
% _0 }8 c3 h- ?' T6 P2 Z5 C . ^3 e) u4 H) G O Z) ?, ?& }" ~# m
//划分左右子区间[left, mid]和[mid + 1, right]9 q4 |* l5 A! x
_MergeSort(arr, tmp, left, mid);1 J8 a" z1 @% S1 l1 q }* \
_MergeSort(arr, tmp, mid + 1, right);: f& }' S- J5 a* V: C
' e# e" f3 \- ^: Y! f //归并
' J4 a" I1 y1 v' d6 ^- D$ g; n1 E int begin1 = left, end1 = mid;+ O7 k3 G& }) L* z
int begin2 = mid + 1, end2 = right;7 ^9 |8 [% T; R* N. m- O7 F
int i = left;9 R' M8 q% D, y" [7 }1 q& O4 x
while (begin1 <= end1 && begin2 <= end2)
& g3 V8 r: ]+ r {
) ^) A r' c! P6 ^- `) g if (arr[begin1] < arr[begin2])
9 J7 B* y3 X4 O C0 l' b4 ~& N- t tmp[i++] = arr[begin1++];8 i* C( i, P: [0 K
else
T- ?7 @2 V' K* c' i! S/ k! h tmp[i++] = arr[begin2++];7 I" \& e ?2 a8 L1 Q- d' ]
}$ E* V R+ v1 R" A
. s& p9 j; U% C( O+ y' O: {+ h while (begin1 <= end1)
! x* V7 b" @" K7 i* D tmp[i++] = arr[begin1++];
, @/ f1 ^! v& T0 z. p: V while (begin2 <= end2)
5 _+ b& g5 x P( `( ~/ B' ` tmp[i++] = arr[begin2++];) Y- S1 l3 C3 K4 e. {9 X
- B" J, v+ F% m' A7 o# |) n% q
//拷贝回原数组——归并哪部分就拷贝哪部分回去* n1 t9 Z% _' w& N) ^5 O
//而不是拷贝整个数组回去, r- P! i. S6 {5 }8 D$ Q
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
# @" Y" `/ U& X0 L0 x }% E& W' J, q& K4 \
. G! c* a P, v1 B: e void MergeSort(int* arr, int left, int right)3 e5 }' D# D5 |! R Q
{
8 n, g# q& B8 ^ x) C assert(arr);
* K" u5 {; w# m! E8 K0 L & z3 k ~3 K4 z7 J7 ^1 D) V9 Y
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));- h6 T( q* g" ^
if (tmp == NULL)
O$ r' @. Y) V7 ] {0 A9 k* u8 r# w0 o) k
perror("malloc fail");
2 B# x. x1 R+ O! k: p return;
( Q+ p' f: A6 z }& H0 E. a9 f. c0 Y' D) F
9 r' J, L+ H9 k5 |" t7 \
_MergeSort(arr, tmp, left, right);9 m# P+ B9 z0 L0 }$ H
$ o5 c! ~* d0 B Y0 ?& H
free(tmp);
+ R% Y" B9 g" Q: B" G6 | g tmp = NULL;
8 O6 m& y/ i& s }
/ u) x0 q j# }0 V; A
4 P. `5 I! h% p3 H( Y 1 Z4 ~7 ?* G8 v: l" A$ b4 k- n6 I- ^
2- l+ U" ]. l' E
3
8 q. ~! C7 d3 c |- O3 ]3 q8 g. C% L 4
' s7 J/ ~+ t/ w# t- B 5
& {) c3 t& E( S$ ]8 J 68 @$ L6 L: y, n# l
7, p/ g8 W7 d4 g! w* N
8# T; G0 B9 f5 P4 Z# @
9. C. I' U6 ~! k0 t. q3 X3 y4 |: {
10
6 ^- Q1 ~. _0 \* i" M M+ ]2 \ 11# }6 W; F: C* M/ C: X: ~
12+ {! p- i5 s4 x5 F0 f0 z1 E7 W" v
13' L3 H) v4 M( u& K5 K% w
14
# W* T: S: u* ?4 r/ R 15& w/ j% N$ K" l0 }3 @& h- X
161 v( F3 ?- E7 V& Z& o; V
17
: N/ e8 m. Q( I% Y; e 18- y- m' p8 Y; m5 m, p# U @% J
19
9 A7 i/ i/ Q8 b2 Z 20
. T+ B& S! D" S 21
" Z* y* X& A+ W, U2 f7 H 22
; D3 S3 [5 P' n! m1 o 23* V3 N) Y+ M1 L5 S) B8 N4 j
24, s4 S2 V2 p f: p0 ^! H
25
& T1 `, g( S) L 26
5 b2 u+ C+ x4 ~! L; ^8 s 27
4 c( l/ Z" l' C. ^1 } W3 F' q! | 28$ z( N9 N8 j5 U0 @7 q
29- X; [% ]+ R6 Y
30
& F. G( I0 |2 Q, L5 r& `: F 31
* ^# P! U- p x; M 32* s. b: O- R; X
33% ]6 t* z, M0 M; ~ F" b
34
2 g/ p: P4 i% j. ^) L& ~ 35# z, `) |% m* a; _, @, Z
36& O7 H5 w$ c3 \- h* G, r7 y$ j
37/ O; Q5 t& t. E' m, y8 \
381 K6 E1 A) r' R" O7 D' n, q
39
$ o- I, Y" M2 p6 K$ P& E( d 40
0 d- @8 o' G* |5 ]) a2 {1 ?6 C" i 41
! y& W9 ~5 A7 M6 v; ] 42
# v" @) c! ~% s- g7 U9 { 43
0 C. J; [, z2 ~0 C+ H: K& { 44/ z* E8 N& Q6 s7 ~6 l
451 [. l+ _% ^3 ^0 ~
46
( D' f. F: I4 R! I 47 z) w/ Y: k& J1 T
483 {1 O+ f0 K9 P
49! z9 P" \% u8 Q) H' W! D
50 s' H: E2 ?6 ^6 y9 m8 ?$ Q
51
/ K" D- y+ T) g 非递归实现
2 T& h$ s$ |$ g3 o* q 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。/ @. ^" J1 M" k( |: v- k
* w& Q- e8 r6 D6 U* Q
; ~. o7 b1 p/ Y/ \4 { / ^% A: U+ j: `" O
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。" V3 g& Z+ n5 ~4 \; |: y/ h# M" ?
' h" l2 `/ Q1 M6 B; I0 `
还要注意区间的取值,每个区间就是一组,就有gap个元素。6 s2 m% j9 u$ w! M
7 d y: R( k7 e) Q 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
* l1 n( M1 Q+ A" _. F5 t1 T
3 X c' L5 I T s8 [& X! B. ] 代码实现
: t6 `' |7 G" u# n5 n & [5 y" z) H: Z ^
void MergeSortNonR(int* arr, int sz)9 Y% y, y# c/ t$ W' z
{! a+ O% z' K. K1 K9 D9 a
assert(arr);. f' h' F4 f& W0 C- c. x) q/ W2 O
) G. B$ y# Y* {6 `& h" `* } int* tmp = (int*)malloc(sz * sizeof(int));
: {7 M b) B, b, \* r. v if (tmp == NULL)
8 P5 K7 k: o" `5 S0 M. a# L {4 X# b) |0 Y3 `. V$ \
perror("malloc fail");
/ e X0 Y, `6 e7 O @ return;9 O" P7 s; r, y; t% j6 A4 E
}
9 m. v: M# q& { L( ]) I0 j 8 J; S7 }$ {! g8 F
int gap = 1;
- E# {% U& @; X6 d* |" [0 H while (gap < sz)9 P: |, T6 E6 W$ @
{7 ^9 [" u6 A, N+ K
for (int i = 0; i < sz; i += 2 * gap)' R4 N5 c$ l c* g4 X
{3 v$ e0 W9 B& f( `
int begin1 = i, end1 = begin1 + gap - 1;+ e. d3 T6 d# m! z, x
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
1 X; l1 P" Z& Q+ U* r/ l9 X int j = begin1;$ j& o" _; q$ x$ ]0 r
; Q+ N: q5 Q7 M" [( a2 p j' W2 o P
//归并4 t0 x1 D; q( T$ X5 e) N9 |( M
while (begin1 <= end1 && begin2 <= end2)
6 w9 T; r& h7 g Q9 c; R0 t {, t0 ]5 F. `+ g
if (arr[begin1] < arr[begin2]). r* G/ j" a0 c g/ @& X
tmp[j++] = arr[begin1++];
; p& k( r$ d) K- E" ^ else
9 y5 [, o4 J% h3 g4 B; Z tmp[j++] = arr[begin2++];
$ F& q. C+ ?4 J; h8 m6 @( ?6 k6 { }, o, a2 l& }# H4 B9 I7 R) g
I( ~; D6 @# _. T while (begin1 <= end1)" q% j% S! z2 t% Y, D5 A
tmp[j++] = arr[begin1++];5 S$ U3 b S* {0 `3 y- j/ p2 i
while (begin2 <= end2)/ p6 Y' j* [% y' b+ A+ \( h( k$ L
tmp[j++] = arr[begin2++];1 \& e6 S( Y4 I! I( Z+ c
# [8 m4 H8 f6 a6 O* u4 H7 M //拷贝回原数组——归并哪部分就拷贝哪部分回去6 m$ y( E+ E. S3 n+ {+ [. n8 B
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
! r' T7 [ z* `4 m }. g7 d% N& c4 l2 s& v6 y' y; E; }
gap *= 2;! g( |/ n% Q& W3 C. l, u
}
. u1 O" ~; u7 }4 F6 w5 E" ~+ s 9 k/ z- w. c% Z) K
}
9 ^7 b/ {% ]6 n+ S. i9 c: h 4 P+ D4 O. v& u: m; T7 P, h
1
" o; a3 ]7 H( `4 W C$ x 2. t$ g' b, H! j5 _& l
3
3 ?0 J! _5 y8 n4 f: l 4
$ c7 Y% e% d; N) o! i 5
4 x0 u& {4 k% I/ T$ ` 60 r, J5 W; N( \/ d4 m
7
" n: j& S. Y$ O7 O 8
3 L0 L0 C0 {% `- F% _! b/ X 9
+ B" a& x: P6 v/ [ 10
9 m" u T3 V2 B0 y; a 11. f- _* f0 D7 m ]& P- X2 I8 g# R
12+ T1 X; ~; E7 L9 l h: U- Z3 S0 `4 ?
139 n" ]3 M. E$ V
145 W) d. S! [6 L; h
15
9 @6 W* J6 A/ H1 D6 ^0 {. G" N 162 a" ?: v& y8 v3 s5 _& Y
17
8 |: A r) q$ ^1 w; w$ I, n4 m 18( v L3 ^" C" v4 P/ o* ~
19
" A/ w/ v) F: ~0 n1 S% | 204 ^/ W6 q4 ?% t4 b
21# c: X. ?- r4 N M
221 H) E8 J. r: [, H5 u( R
23
$ `5 j# |3 x- W+ M: A 24: x' L. y# h- M4 f8 X8 {
256 V' S9 q- u. U
26
% ^* b( U3 x" |1 n 27& g! h* K1 f8 `
282 v3 a$ t6 a* p+ N0 D( u2 y; J9 F
29
6 M' X% G8 d/ t6 @) F/ G1 t 30/ V% N; Q6 Y6 L5 [$ p" S9 a7 ?" G
31
$ F' V, f( T' | @6 C 32
6 ]# f9 N( D" I1 ? 33$ v& z4 u* h; o. \; e
34$ J: b; Y0 ^2 K
35
0 n- Q! f$ N4 u1 g9 G$ g 36
- z8 q; y3 p. ^& |, e6 l8 y 37
/ G9 N( `% r, h& Z! x8 ^ 38
2 }, s" h3 _* l! Y' C3 x 39
0 U3 ~- c2 S' o. T2 t, K0 ` 403 L+ |2 D" h8 u: G5 f
41/ b" L. g/ [) c0 P
边界问题5 }6 d' ?% G% l- S2 `6 s/ u
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。/ Y( T7 b* c7 e2 ?, M$ ^1 ^4 ]
6 {8 L9 O- s; H) X5 G* V1 q
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:! o$ a' m) g1 y0 o! ^& [
+ i+ ]2 c) b$ A0 L6 J
7 K) Y( n! O% m d
" v, K' M4 ~; {0 V2 H* d 由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
& V7 t# F# e1 R7 V; b6 r% Q " n" a Y* E* _- F3 I
第一组越界(即end1越界)6 n8 l3 H2 B( g/ i- L/ ^1 C
" L8 Y+ C0 L* v0 l1 I 应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
. z# V T: P) P7 I+ G) {5 @ ; O7 Y) k* ^" _3 n4 |' Y) Y# A
第二组全部越界(即begin2和end2越界)
, _+ X2 a% A5 N8 L3 v. V% V* T# j ) J% _: |( z% f4 s6 ]8 G
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
3 u% n: i! k0 \5 B 0 G* a: @0 d# ?. F+ N- k
第二组部分越界(即end2越界)
8 M( q5 _' @* v9 R$ c8 L! u. X
4 a7 z0 S% b2 p# N 应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。3 y/ B6 L4 h' _* D
( L7 F& {1 {5 C8 w" K0 C5 L6 x 其实第一种情况和第二种情况可以合并为一种情况,原因:: ~6 t' m: y/ o, V/ B
5 X } V/ }7 {% P3 _3 n3 { end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
# e7 A5 e' [: K' z- l& @6 y
% E4 x: \+ K' ?: X8 {" Z 拿两个数组试一下:
9 r$ e: u9 j3 {5 T, Y 3 J& |! [, i( m
# b* w- S9 S: O% D+ l4 @* i7 g 5 \: X$ S& V+ y* J
; Z2 [( r8 G: q Z1 T" Y ( i+ @6 f0 u, a
代码实现2 j: y* \3 m2 l" S& W" o
, ?. A! `$ y; N9 W void MergeSortNonR(int* arr, int sz)- X0 w- D2 K( m6 |% Z
{
K! s7 E, \4 k* ?7 w+ { assert(arr);2 v m5 `) v6 \. h% W
* Y8 c+ ?" t' Z int* tmp = (int*)malloc(sz * sizeof(int));+ }, d, g4 T4 Z8 |& h" Y
if (tmp == NULL)
' l; S$ h9 o( H3 F7 U/ O) \8 Y E {
9 {! {. v7 A* l9 W: \ perror("malloc fail");' A S- v! P$ B: a
return;3 `# H! P6 g- X7 N8 h7 e
}! t+ x& o8 p! n; h% w# X
" q2 M F# f- ~9 Y. \ int gap = 1;
( q/ J" Y& a% E0 g while (gap < sz)6 ~0 u6 o0 @' x# j, ]6 m
{$ s& s6 T( D: G& L6 E8 n
for (int i = 0; i < sz; i += 2 * gap)- q9 W9 b& X" O4 {: r
{' A0 l1 d: _. K! m
int begin1 = i, end1 = begin1 + gap - 1;
5 m1 k3 `/ {6 O9 C int begin2 = end1 + 1, end2 = begin2 + gap - 1;$ B1 U% B6 `$ A0 H
int j = begin1;, g" k) K/ B4 H6 a$ D* F
//越界检测
: M- B }# o/ U' d P- \1 y8 { if (begin2 >= sz && end2 >= sz)2 m& j f8 T3 z+ ~9 `7 ?$ H
break;1 m9 n: {2 M H2 g; ]
if (end2 >= sz)
4 i# W2 T% o/ x6 f) Y end2 = sz - 1;5 \$ I5 ^' n" f3 R
//归并
4 U4 F, M1 S9 N' O! p while (begin1 <= end1 && begin2 <= end2) C# K: W" O$ z8 S- W
{( O5 T! ^' V4 I
if (arr[begin1] < arr[begin2])% g/ P. R" H R4 R9 C) L5 O$ f# g( k
tmp[j++] = arr[begin1++];
( X& F( v9 S: b3 {5 Y" f, a+ } else
# e5 S; P; N0 U! w# p6 Z, k- w tmp[j++] = arr[begin2++];
9 m4 L# Y8 p% Y# d/ R& }8 { }9 ]# m6 q: r8 S& R
4 ~7 i1 V+ k5 G, V! ] _
while (begin1 <= end1)
3 }7 W5 U5 G! m7 F! Q tmp[j++] = arr[begin1++];
9 U4 V& p+ \. |3 ]' R3 r/ O$ c7 l while (begin2 <= end2)
0 `# X5 h: Y* s% \/ X tmp[j++] = arr[begin2++];
8 l( q4 n$ }3 j$ d" o" K3 U / [, @$ a. C; k) g. e
//拷贝回原数组——归并哪部分就拷贝哪部分回去
: Y$ l1 K" l+ L+ ]" } memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));# E) L4 V. C1 \& y0 J
}/ v9 }- b$ ~5 L, U& a
gap *= 2;
" q% b. [7 e0 h4 A }
* {/ k% C R7 t
6 b3 H0 _: b( L1 z/ F }
( H- B) L0 Y: E' I$ h& z
2 u; U5 r2 v3 L1 n: d 1& @* K9 S. |' u( V* U$ k" Z
2. D. z" a* X1 {0 W7 x1 U
3
4 ?; j5 a5 b& O 4% L' Z& z6 {, Q6 t9 l$ a& w* W
5
7 {1 N( \4 Q; O 6
# ?# F( g& m: U$ X 7
: w l x* N2 t 8. f. l% f% `& v# ^. n% X
9
4 M. Y4 S) P; F 10
1 }! ^) n* {. G" t* U 11
8 x% g/ L0 D( V- @% I 12
4 _' [6 C! a1 o" p 13 V) W. H4 ^( R* e
14% w- n6 h( N% v% Y* q$ B4 C: L
15 T! E. ~( w1 I% d6 @+ n& t
161 J, Z0 S- @$ i+ H, K
17
: {" F" R1 Z* Z8 t 18' Z5 r; z7 ^ A& ^5 j
19
1 s; d; [2 _' }+ @; u& O2 ~ 20
- P2 X5 b" x1 @. e 21/ z }8 ?5 O% \2 |
229 B3 ?9 g4 s, T5 a9 w
23) \2 K. p/ h! v* `& e' ? `* }5 V
242 t4 S. f3 M; A
25& E8 _% Z4 h' b7 l4 D% J. J
260 R, q* q6 u0 d( l2 A- v
27" b) H) ^7 ]& T) V1 u, ?
28, u3 `( k! e2 }( d* P. O
29
; w4 b. k/ l7 W6 p: t( Y* S q4 o 30) O% C. ]: [7 w- n+ T
31/ D3 c0 Y& U( z# j% z
32
" H& Z# N# Z. f/ L- e 33+ @! s2 {- F) ?
34
8 |+ c% H! R: V 35
: M Z% @) M- Y! k& G0 i 36
: ^! a0 C& M+ M' U2 P: ]: N 37 } p4 L$ U# p7 e/ ]
38 c; q( J, s3 B5 D4 Q
392 O A. X0 {; f) J# o8 }
40
U. r( s0 D5 s, z u( z. y 41, H2 J1 ?9 d* P: ?. G) U% P( s
42
3 N/ l, D/ ]" y) p0 w 43' i" w- C n4 A- W% V, l
44
: ]& Z5 F5 {2 ]+ |/ O 45
$ S9 j/ B+ N: t% i. q* l6 [9 | 归并排序的特性总结:
$ w# \9 v, _$ h, A, x
/ N& o) ^' n+ B 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。) q9 z) b; y! Q3 C. s* ~) ^* P
时间复杂度:O(N*logN)/ u3 u' A1 Z& m7 a& ~! t
空间复杂度:O(N)# T# ?8 a8 ~( j0 x
稳定性:稳定) d: O; i' t+ ~7 l- ^
& p+ I$ y9 j! e# B
———————————————— \, V) S5 I0 \3 i
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
0 t- w! D/ C$ L% E _/ o: n 原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
5 b/ l4 [: T& b1 G% ]$ [ % m; O; R! P8 J
5 U; w& H: w _
zan