- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 569630 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 176112
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序" h& v& |, }' Z3 {% `2 [% N- |( c
" z6 s- f, k8 S! b3 M F前言% j G: }+ w3 x6 [+ ^
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
* i) s D& k& n4 q, v* v" F' y/ p" [ n
归并排序6 D9 L0 ]! m) [) w
基本思想
+ G( R3 _4 ~+ @. Z* c 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。% _- I& {6 g$ @& @3 @" L8 B4 W
( r' |/ @; K" C! o' g0 J$ ^5 w/ I3 M* _& U2 R) g' {5 B
# Q3 [7 W3 l# e' ^& ] 合并的思想其实和有道题目的思想如出一辙:
v8 L ]* L! o( Q
" U1 l1 R9 V! A; d7 z
9 h# I, C5 Y. \+ g
1 r9 X" k2 ]- x" u 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
! q, ?4 L. a( v7 h, U0 L2 {
( j7 s$ Y+ i8 b( {[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
$ w1 M1 k) d$ d( p$ c- P; ?. Q. G
# |( @5 `. U3 |) @8 Kint* merge(int* nums1, int m, int* nums2, int n)( y* @; H( Q R' H( N2 Q
{' D* f" l* h4 P/ c) W R, o
int* arr = (int*)malloc((m + n));
0 _) M1 A9 D( c8 r* }3 H if(arr == NULL)+ f- G% i. o3 a, u: s3 j
{
+ L/ `. r/ |5 `0 ~4 Y- B( O, z' S perror("malloc fail");
8 ~6 k, l& h- Y& O! k+ g/ e% M: p; A return;
# Z1 N: e/ d6 R4 y1 z }) M2 Z) g& o. O1 D* d0 d
% L% d9 P% r7 \+ R% L( K$ o
int p1 = 0;
+ u7 ^! u. ~/ h3 L6 P8 l* s# m int p2 = 0;
+ U, U( U8 r& q2 @9 b2 j4 _ int cnt = 0;) p0 h( a2 U f
while(p1 < m && p2 < n): ~5 l! @& M/ c' o
{
- o \1 [; \6 a$ Q& L if(nums1[p1] < nums2[p2])* M% Q8 h7 G/ M8 K3 R1 C5 C
{
/ @; X8 b% _: y( ^ arr[cnt++] = nums1[p1++];) p3 N# }" `5 Z- `
}) t8 @0 h/ T9 q2 ?% `
else' Y- E' `$ g( A( j0 G7 K
{
) e, d3 g. Q9 y+ N5 N arr[cnt++] = nums2[p2++];
w1 N8 |! k2 {8 I: `3 D }
1 M6 k$ F& f; P& c9 J$ K6 P }2 }( |5 q- g5 V5 f
while(p1 < m)& b) s- Y! [5 w/ t' f. `
arr[cnt++] = nums1[p1++];+ F3 U, G( z/ z
! H6 o- W- @! ]- n while(p2 < n)
# X" r! X+ N) ~% N1 g arr[cnt++] = nums2[p2++];4 @: `# ^2 @3 ^! O* p$ J
: @ T3 I6 z; a# @7 `& v
return arr;( [0 S5 a( A: F4 [( }' \5 _' B
}: Q/ N f5 j$ g4 u
& ?9 F0 O" {* L) i; t1( M: V: _: j' }, q6 ~% t1 [3 v) w
2
& n: x& R2 [! T; l0 a" ]3) ?$ t0 Q. `! c9 B! Z/ r8 w
4
# F6 X7 D# q: a; \& P. E5
8 O3 Z! f$ o6 Z; S64 e* y0 X# r. b
7$ ^, b6 }! e) V j( j1 Q) e8 |
8
- F5 T* s; C: G& k- d9
. w; K, D5 G4 F, ~3 Z3 F10
* |1 T# v4 Z" j: y4 k11
. V0 V1 }* U8 ]% l. P& I1 L12
8 K9 F0 Q6 f7 R8 {, S% R6 t13
: B+ l8 |8 K9 ~% e* ]$ a4 d6 y+ _14* Q0 x% S' U! d, B0 |9 a
15
, _* k# e& p' ]! u+ j8 o2 B16, M' J1 E# h- l: L3 C ~& S
173 R) R1 ~! q4 ?# [* J9 v/ ~
18
0 F% _1 M- M9 n8 r& x' |19( [. z% ~1 U) e6 \! e
200 [6 l7 q) O3 i9 ^% l* n
21* {: A/ N8 p9 Y3 t& {/ J
22
7 C, }! ?& u3 B3 ]3 R' |23; ~, ?/ f% ~/ _% k$ t" ?2 V
24
' ]6 a6 ]7 F! k8 h6 A* P8 Z25
4 X, F8 K) f1 r: n26
+ j& ~, _. R9 p9 H' r- ?/ j. q270 ^% v) l* O! Y2 l1 i
289 o w1 s, D% M# k* u
29' t3 s& | y* c7 e
30% W: t5 [* Q) W8 N2 O. O% E
31
0 G7 A& c( b8 s5 T, C 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
; I w* X+ Y6 ]
; K7 \6 N! X, X递归实现
/ [9 n/ }3 N0 l 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
. ~( r# ?$ P) X( N9 A5 x& u4 |! [& q+ S* t6 E
( t7 o% y- a2 A Q! v, t
; E6 ?7 l: x" _) i/ @
5 F6 N& i8 m% L0 Y. x" ~6 }8 H8 }0 l% ]
void _MergeSort(int* arr, int* tmp, int left, int right) ]$ D3 J( i( e) W
{
`3 s% N! s' H2 u. n& r assert(arr);3 W# n+ m0 E# Q2 B
( E9 Z! n0 }/ g. L4 X9 k# L5 R if (left >= right)//递归结束条件不要漏了) Q* W2 B3 o& Y' g0 c0 m
return;
( Y1 K0 t! {5 a0 o, T3 I
% ~( I8 x' L) m# e int mid = (right - left) / 2 + left;$ k6 V" a! S* U% Y* u1 \$ L
; g. F9 e' u! C! v
//划分左右子区间[left, mid]和[mid + 1, right]
5 \* C G% A- R2 V2 p _MergeSort(arr, tmp, left, mid);
/ R L- X& Y* W$ Q1 [4 F0 \( @5 ~ _MergeSort(arr, tmp, mid + 1, right);
( |$ b; Z$ b& Z/ y" a) c% r' N# D% P% r* ^$ L3 A! l. B
//归并' G" L5 H) y0 ^/ C0 v$ Y
int begin1 = left, end1 = mid;
6 y" ~* X! v! ~- {$ R/ G: o int begin2 = mid + 1, end2 = right;" d# _. q4 h) J3 W/ n$ r# @. m6 C
int i = left;
' ]( P" _! m% F while (begin1 <= end1 && begin2 <= end2)( I t7 l% Y/ L$ K
{& H) n$ e/ c) ~
if (arr[begin1] < arr[begin2])4 h; `: ~0 y: @
tmp[i++] = arr[begin1++];7 K1 t2 l; Q, U% [: _9 C
else9 C9 ?. Y) U; L5 y8 d2 o" d# B# v
tmp[i++] = arr[begin2++];" C+ {* _! k% L I2 H
}
/ T# T( K$ l2 T5 v
) f' |4 d$ Z4 ~ while (begin1 <= end1)8 Z) a; i; q& v% f: F: l! N
tmp[i++] = arr[begin1++];
& e, g% V" m( c/ [ while (begin2 <= end2)& }: k( ~( G! E+ p4 {
tmp[i++] = arr[begin2++];
' j& f( F4 U9 i O+ n: I! D % J3 ?4 _! u: \; |& q5 v' _- c
//拷贝回原数组——归并哪部分就拷贝哪部分回去* Z; f3 C) o f2 N/ B8 o
//而不是拷贝整个数组回去
' y# W4 _) }4 m! p; R* L memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
# R4 m2 M. Z) }}' |0 R! W2 j6 w c- V- @* g C% R
1 k3 j e- i8 _: Q
void MergeSort(int* arr, int left, int right)8 c+ t' S) {6 L1 C7 \3 m( S2 j- e
{/ G" F9 b- q% o( X& x' |
assert(arr);
6 g, \# ]4 A$ O; v( }: A
/ E) H7 [$ m3 {: G: B2 p4 s5 v1 y- u( c int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
* j5 Z/ z- Q# l5 p1 y if (tmp == NULL). a7 ^- b/ P8 v
{7 H( L1 X: v3 y: K1 E9 }
perror("malloc fail");/ p+ M J- r8 B2 \5 f0 ~# G" v
return;! N+ T. y8 O. z
}
, K1 t. J! Q7 B8 W: B3 t3 M: v9 |' G2 e d0 B6 n- `
_MergeSort(arr, tmp, left, right);! L9 [- T5 A- p7 @ [ ^; b, A2 a
- P2 J4 ]7 H/ R3 j$ k- g free(tmp);
" i& `' W2 b3 W$ M4 _1 d2 ]0 ^2 q tmp = NULL;' T* f$ G" ?! C, }( b0 h4 C
}" s# U# ~! {/ A! [
' N- k! S4 W- R1 w1+ s( t U. H' m6 G7 \) @
2
4 f `7 w" c* T/ h0 v, |( D30 `6 \5 `1 D+ M, F$ u
4
% p5 v! r8 p4 j9 c' Q5, ? z. V# I1 V) o! I. N; { D
6
/ v: Q7 |+ B! h1 c7
- W4 z" D! U0 Y- @9 M {8
6 Y0 K" U4 s8 g* \9
$ O( k, o! ]' P; T* F10
9 r+ U& e- `# w11
+ s8 ]2 F; G5 y4 P7 q) `9 t12
% {4 b8 Y/ A7 e13
: F2 q: L- |# {; r' P14" M2 A0 _8 y0 z9 ]8 G9 D
15
# v+ N3 ~: }" R16 e. v; h8 A0 {/ F! ~2 w
17, k3 d5 u3 C/ A8 G
18
B5 S E1 _* ~' W3 Q; i8 V19+ [+ q6 N8 t: W8 i7 H4 i) R6 P
20
5 X: D( Z2 M' I3 b! X! i& r9 }, |21# D Q- w/ W# K6 @! l$ K A
22
$ ~3 b5 f$ N0 U' l! F23
" G) g1 j8 S7 Q24! o* R. u" w; B
25! A f, b( D# q; p+ _
26% U# f- N) ^$ S, ?9 @0 w- k& B$ u
27
5 J2 Y1 E* X" m8 ~3 p, R. P/ @0 I28& ^9 z; K& ^) P
299 _( N2 p( W1 H; A# {
30
4 t D+ J' K' o$ a# E31
' u. q/ i! Z' k) E+ j U: w. T6 p32
7 r! f- g1 Y8 T) T3 [6 R! ^33
9 Q6 W/ _3 x9 O% ~ H6 ?34
9 \: y& Z( a+ K Z) p35
% a1 J, m) N% w }* \36 p; L1 i" `! |3 k3 _- m- v
37
0 ]8 a2 k1 R1 `38" I- F6 _4 J f
39
. p; c/ U1 R) J7 b4 e* H402 \+ d: n) ?7 L/ B8 G: j. ]
41
% M0 x3 a1 h7 I" S7 p; T424 s7 \; X& _: J0 r/ `+ V# g( j5 ?, G
43* V- n: g! s: t3 ~. r8 D
44
! M T; }. B( P& B45
3 e4 J2 R3 l% E8 h1 ^462 a4 ~& m! Q8 }5 y1 i$ ]/ D; g5 t
47
3 e3 b1 r5 Y6 D* S" J48
- w, D) q) Z1 C: }% ~# j: T49: `- ]( A9 p7 [, l
50
4 u! U) s& H2 w' z; ^. W6 Q/ L' Z512 J: T' U1 u7 P* z, ~
非递归实现: P ?8 `* T. x" b! G
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
$ M! D% P) U! Y! [( V* f N. @( `& b
+ b; p7 j& y N, |( a9 _
' k) z+ V+ H* w, K6 ~6 Y/ h+ M5 e3 o! t) D9 U I& |4 B
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。* x1 O& X ]5 b4 J9 M/ }" W2 ?
6 [! x1 F) x) T& Z& I
还要注意区间的取值,每个区间就是一组,就有gap个元素。+ o) S) n* ^4 [
0 S( M- {) ~5 M' s# s- W6 Q; n% H 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。 E! u5 K) A5 t. g
6 Q8 q, e. c9 v/ c$ j; |1 U* C
代码实现, ^, B3 U1 j1 u2 l3 T* l
8 h2 h& I+ f0 [: m; l0 V% v9 dvoid MergeSortNonR(int* arr, int sz)
& M% v' ^7 Y. C3 c0 j/ J{% [2 }" u y8 C. `. v7 U% \
assert(arr);
4 Y) u/ j+ D% |: p% N6 x V$ Q( b% t$ w7 ]; t5 I+ f3 ^8 ~( g
int* tmp = (int*)malloc(sz * sizeof(int));$ M3 f2 p! [8 q k, a" B% }7 Q
if (tmp == NULL)
8 o* T l. f0 p5 b5 H- \ {
6 h. n1 x l, a1 z; A$ V: Q perror("malloc fail");
0 x/ ]' j1 N1 [; P. T+ C+ G6 B return;
! C" A8 t2 h7 ? }
. S$ \' h# T6 v( C
. _. d* ~# V- q3 g, b3 r int gap = 1;! j6 c' Z9 U+ h8 [$ r$ P
while (gap < sz)
/ r* L& O' `$ F; q% v- l- @/ Q {; ]+ U5 j* I" T" Z
for (int i = 0; i < sz; i += 2 * gap)7 Q; Z9 k+ d# R) I+ O+ Z
{
$ O; V8 E! E! z/ v int begin1 = i, end1 = begin1 + gap - 1;
: y3 e0 d- T3 b5 [( @ int begin2 = end1 + 1, end2 = begin2 + gap - 1;# r% R2 A# w* b9 u
int j = begin1;
+ t6 [; f, m6 N3 T/ v% _- M( b$ u' \6 h7 `0 k, V9 e
//归并
3 N+ C1 l3 o, r" K( D while (begin1 <= end1 && begin2 <= end2)
0 y9 } K( {( I+ z {4 O) p0 b+ ^4 d. }
if (arr[begin1] < arr[begin2])
5 c& D* d) [- c$ v8 M6 _ tmp[j++] = arr[begin1++];
* r: X% t7 X5 U1 _. G else
; N3 H6 \) D: f& t r% s6 H tmp[j++] = arr[begin2++];5 x' k- ]. x. E% E7 {: w! x8 z
}
& }: J [2 K' ^! A' k$ x3 h
9 R2 D; ]8 S7 i1 B# E+ \ while (begin1 <= end1)7 T, S, E. }! u/ M9 g% Z
tmp[j++] = arr[begin1++];7 ~. ^" B3 m: V
while (begin2 <= end2)' e$ G& x; A- z& H& L
tmp[j++] = arr[begin2++];( K; d- L1 h0 Y
* H: ]1 v( }; [* H- i0 w& S- R
//拷贝回原数组——归并哪部分就拷贝哪部分回去
4 f: M7 S7 `4 V' d6 q" Z# N memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));3 ]. }3 G- w, `: W5 s7 E
}
1 O/ h9 @+ H. m5 w$ o& e gap *= 2;( B# \7 m. o2 ]% u" K
}% Z' v& l7 z3 P1 K
; @8 L/ E; z4 \9 V4 @4 x: D8 M
}1 d" P! Z1 b+ a
- A4 G, |! a' t$ [
1 k9 m6 O+ B! [6 ^9 n
2* [+ b: s. M0 R
3! C7 h a$ r( n# B* E, U) b
45 \0 @& k. J: n; ?8 D$ u/ J
5
: p& v( q% t5 U: q1 v% j6; v' w& L/ ]5 g; P
7
3 X6 e! P' z- r- P v0 @8' ^1 z2 K: Z0 x6 i+ @0 U8 ^
9
6 c K3 o+ I6 X. e' M+ x0 W105 Z) ?& i+ L8 [7 [4 k1 d8 L3 m
11
5 P( d7 v. r' s; u12
$ Z$ K! D% }# F1 z7 A' ?. h13
- k9 T5 l4 H2 r5 J5 X1 v9 P14
. R/ n# v' z: @6 A15' d+ N5 H2 ~4 h6 i1 Y0 ~
16, K9 X/ w8 N: m5 j
17( R+ d, \1 z R9 |+ }
18+ H/ ~3 D/ X1 d o" \7 y
19
; V+ D- x d' T( I204 F5 Y/ Y$ N. E b
215 d' O! q! v2 o5 f- u' l
224 P/ p) H4 N) R' v( c% z/ A
23& y% n' n0 p5 j& o6 |
243 ^6 r4 L2 u) N& y; l9 G( V. ]
259 G4 s' n* g2 R
26- b) v( D4 A6 `" Q
27
; ?4 h" P! q' k1 s) ?$ ?- U28+ R, H1 R* [7 ?, B( o* g' k# {0 J
29) u% g, S+ o' ~2 Q6 Q8 u
30
; M: q/ n; l- P$ V. w- c I. e& w31, ~& s; h8 r- f/ J
32
5 e. O8 B" P _/ `1 J/ G, `33
8 F! u3 L8 K0 [: I1 K: Q34; v. j; N9 J/ ?: t7 _5 R
35
) P: f1 ^ X# m+ N8 r7 j36
9 J# @ P/ m# m9 c37
$ B, a4 S; H1 h& C) q38
; f5 ~1 g+ f( o! m& c39* r) o3 k! G* y% j& \% }
40
5 Y# b% {. Z/ w& d+ q% M- p41
* e; Z3 D& a4 r3 S! f6 A) J! [; A边界问题" ^- P1 c f+ _" n9 s
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。! V6 M% Q1 O+ ~* d: v; F1 b
# R* r' N* @* w0 J" t& w
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
% H/ C/ y( _5 Y: i! }
- U$ O1 L: W: J1 i' |
) ^$ X: ]$ e7 I- y
( y/ h4 [) c4 q; a由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组). q" A& s9 u6 l0 f
' i; q, o/ |/ P4 t( K
第一组越界(即end1越界): y2 C1 A5 T4 ]! m. ^1 R
/ H! C- Z/ _' b: D% X
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
# o' @% H% W! f3 E+ h( i+ R
1 k" ?1 @: U( i5 c: ^0 g& E第二组全部越界(即begin2和end2越界)9 r2 a U' o5 T2 ]- _
0 {4 J; O7 }. d* m
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。( ^( s0 j; F! b* G6 L+ X& ^+ @
* G2 @# e& W/ }1 i
第二组部分越界(即end2越界)
3 I& V& A# F3 Y. s/ f2 ?4 I
5 u: `* e9 I6 l8 ^ w( Z. Q k应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。 I# E" N! E( G- I3 {3 r+ U
+ i! n8 L* s5 I8 J% H
其实第一种情况和第二种情况可以合并为一种情况,原因:" o, D5 o0 E& \
) @4 l& t, s! v- W" ]) i- } end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。* e1 \% c1 i% g% a( D: ]; L
. A! P: t0 C( i! u# b; K' L! Y
拿两个数组试一下:
! b h F4 l1 X% j+ r; k
7 W. {- P. R: s) r7 o% \* D5 J6 O, U5 E/ \. r$ ]) c. x2 I) `
& |, V# o, d0 J" @
9 S6 E) ?$ A! ]4 t! G0 q; n) y
$ ^7 V" |% x9 B; H2 y Y+ T- C
代码实现
6 ~: c- x9 E6 k+ q8 u& }# p' q' z0 b o' v
void MergeSortNonR(int* arr, int sz)
) z) J& U: S/ o* D$ [{
. q2 [ _ Z+ O assert(arr);
" t' X( z! x( c$ K! w* ]; t1 m& g- n" z6 b1 o( k2 [+ P
int* tmp = (int*)malloc(sz * sizeof(int));# C7 ]4 @% w; \. ?, t
if (tmp == NULL)) Z l" {7 C% A4 Z
{( _5 ?4 ]2 ?9 Q8 K: Q* L# f
perror("malloc fail");3 y) z, M% c, z7 e
return;6 g+ Q6 ]; |9 ~7 a
}
: @! u4 F5 O: I# @; e4 {
9 e; C9 E+ ^! Y; k int gap = 1;
7 ^" |; Y; @! D: @ while (gap < sz). g" G6 N) D% F h
{& H$ w V& u! `
for (int i = 0; i < sz; i += 2 * gap)5 r( O1 a" _4 k5 H
{
- ~4 M& A1 |5 i int begin1 = i, end1 = begin1 + gap - 1;; B& j$ ]& X7 d) n5 q
int begin2 = end1 + 1, end2 = begin2 + gap - 1;9 ~- ^+ U c5 U3 h! d1 d3 M
int j = begin1;: B5 r$ R7 H# f a/ y( [ t# _( \
//越界检测- j; k' e, R; P& d$ q% _
if (begin2 >= sz && end2 >= sz)+ L& d4 \9 Z$ ^& N: [* P
break;
1 O6 `8 e5 _ W" f if (end2 >= sz)8 N5 f( T" o8 v2 k/ Q
end2 = sz - 1;
" D- w; ?5 `/ Y5 D //归并
( a7 t# j7 w; i" c8 o4 Z, V5 w/ X- ^ while (begin1 <= end1 && begin2 <= end2). O& {+ `: o t5 e9 K
{
# ?' {. y( Q* y& `& W1 b; h if (arr[begin1] < arr[begin2])$ f; b. i) T3 q* _& m+ y# T
tmp[j++] = arr[begin1++];
1 y2 I# g1 @$ r% x: D! G# [ else / _4 }: |3 p+ h
tmp[j++] = arr[begin2++];2 L+ W8 f1 R: R. Z% t/ c* K
}
7 u2 ~1 y: c7 K6 N5 m$ I
7 Y- O' F7 [" l$ Z. q while (begin1 <= end1)
7 ^$ @. C' v2 m1 K tmp[j++] = arr[begin1++];6 W% Q, q% g- k; O D4 ~/ X: Q
while (begin2 <= end2)
; w7 r% v! ^; j: J4 R0 v9 w tmp[j++] = arr[begin2++];: h+ S* Z9 w) y7 r% o9 r
, o7 _8 A' x' J9 P0 S* Y //拷贝回原数组——归并哪部分就拷贝哪部分回去$ p& F4 O8 x4 @3 W# h, \: f# S0 K) p- c
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
4 Q' a1 [+ {- I }" W) `" y& g; [. Z9 B9 D4 k
gap *= 2;! M a" w1 K5 R" l
}
# [7 L4 u" {' ~* h' ?$ V
2 X0 k1 n- @# a$ o}
8 k2 P) o; Q+ `' j9 c7 b
% t3 F) }& w8 @: a8 d+ `17 A1 g1 @! w- ~! B9 t
2
2 @9 p' u" G2 `% r9 X3
, D- ?( k% y* k4 g6 l49 V; [4 ]; `; e n7 d, F; N
5
, X6 E) M9 L) k. } r5 B, M67 w' d9 U) j$ ?8 W# Y6 I
7
2 y4 a7 i) Z# U# a- ?6 `8
& g# s. h( z; b) O) B: x3 u9( x; {% N( U9 Q. H7 P
10& \! I8 z8 ?( @6 ^1 v
11
. l1 [" Z, v# i- I$ E8 V12/ l0 a% E0 s3 \9 T3 D
137 Y" `# p& I* q" F% O7 M- H# k
147 N5 Y5 l4 ~1 w# t0 `0 K. z) L
15
# C( X! ?( q7 S# K3 o4 K7 N$ B16 U7 `- Z9 C0 g
17- V& N4 K2 u% c. f: w
182 J+ w3 C; T c+ V8 }, O
19
( n* `+ J& | R- U, n" |20
- ~$ A' J/ `" w' Z. a/ U# v21
8 a2 _: o b" d222 c( G9 u+ ?( J4 z; `" Y7 `! N
23. \* q% R' x' }" b7 c
24
: T8 e* w2 J: i8 y' Y1 p25
+ s3 Y- Z. E: ]# j; l26( B% b6 H9 u* k3 h* w4 d! E, l# O
27
% `; l1 z6 A, a281 \. g, q* _# M& ~4 G
29& w4 x* k: H1 q, B6 a+ V7 u( G' E
30
/ Q9 u o1 [0 x- ~* Z+ l31
' k; s' ^0 E) ] e7 i0 }32* x5 K: ~* O0 w
33
* ~% ?8 Y' {6 x34
" ~+ L- \8 N4 X/ }35
( U, N# M6 s: p) M2 f# {; x36% O4 a5 t; S% T* K+ X( R
376 a7 i0 a4 @3 S
389 D9 f% G$ F$ x4 H' \
39. ~. U! x9 v y/ d$ |* ]
40 B% i1 a+ n6 y" l0 k
41
/ l( z0 z# b) X42: C9 G- q6 ^; H/ m( T. E, I6 D5 |
43
9 o5 a/ k" K( n& f44, I' Z9 G2 d: [
45
0 l9 {- B0 [' q# @- j8 b归并排序的特性总结:
2 S/ N/ S" C9 j* f! [% E0 E I( j5 n
8 s: `( I; K2 u* k& B4 L归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。/ m) v7 Q# a/ U5 u4 L
时间复杂度:O(N*logN): A. v. G$ L3 ]! L7 p0 J
空间复杂度:O(N)8 b* A: C' q0 C" }( M% o
稳定性:稳定+ n+ r: t9 h) b2 K
) T D+ Z6 Y4 }9 h
————————————————
5 s( b4 L# s5 M! J版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
7 v5 R, k0 d1 ` }+ J; K原文链接:https://blog.csdn.net/weixin_61561736/article/details/1267966575 }* ]" ^' w# O/ Y
1 h% J' V/ Q: B K& A- ^6 H. \, F7 B2 ~2 D* G1 J N6 i
|
zan
|