数学建模社区-数学中国
标题:
【基于C的排序算法】归并排序
[打印本页]
作者:
杨利霞
时间:
2022-9-14 16:22
标题:
【基于C的排序算法】归并排序
【基于C的排序算法】归并排序
1 W0 |4 M& N- |9 w0 q
: L7 v8 q# e+ K
前言
. s I1 @! N* ^5 @, g P7 s) h0 j1 M
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
: _- C7 X. p2 {+ ^% V2 ^) u, r
4 d) d% P) v, x% g t
归并排序
1 K: ?6 l7 S( b0 |3 O7 g: z1 R
基本思想
w; v0 [1 P* {$ T+ p/ t+ h
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
) K; V; Q) d9 w1 W
5 K$ a) N7 n4 Z1 ?. N8 O- S j
) e* K( y, i4 ?6 x( F* r
: t* b3 C) ]$ `. H& i3 F
合并的思想其实和有道题目的思想如出一辙:
+ A, D+ B6 D2 `& L M* [- Q/ {
& y0 }) j0 G( _
4 p }, o* e. e! h
; n$ M' x, [* F+ I. W: n7 [
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
) i# j* y" e: d9 W% w7 [
1 P: D% w/ P/ _% z
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
: Y4 G; Z- [+ l8 B
7 d6 X9 j) y/ E: U1 p# d% t( K- w
int* merge(int* nums1, int m, int* nums2, int n)
$ r' b, T) L" g5 g" ]
{
( G' D* Y( m( c! `
int* arr = (int*)malloc((m + n));
. J2 S% f2 r5 [, `. `
if(arr == NULL)
- M7 |3 m( R% ^0 Q( t) j7 \: G
{
. f" Q% e5 y( v1 l- I
perror("malloc fail");
! t X( P5 A: ^
return;
# E a, ]' O) a3 ]$ `, A2 J
}
! E, c. t2 ?, e$ n9 G, y& ?0 z
R7 j4 `& q* f% G) P
int p1 = 0;
) S! P/ M- w( H b1 u1 y
int p2 = 0;
" p, t e! |. L9 r( f% @1 l0 j& p
int cnt = 0;
) c& k, J9 ?. C& V) j7 o8 j: b
while(p1 < m && p2 < n)
; A9 j: N5 N# M9 T; \$ I* A
{
2 N2 k4 c z! ~
if(nums1[p1] < nums2[p2])
; u& F ^1 b9 f- Z
{
& c# ~! c$ z2 u% v' l5 L% q
arr[cnt++] = nums1[p1++];
4 G: f: X0 b" Z. v
}
' f/ s# q( i7 T, i
else
5 W7 r# [- M/ v; e6 v- o. X( o' g2 y. t
{
Q' z# v# Y4 C
arr[cnt++] = nums2[p2++];
( ^. Q$ A F7 v- I o4 B) K
}
. w0 a Z- I% m' M0 d
}
8 Q) p$ Y& L! S# q- K$ D0 V6 E/ A
while(p1 < m)
2 p6 N( _: h% m; \( `1 S6 U
arr[cnt++] = nums1[p1++];
Y2 {& z) P' Y9 w! @5 D
% ]$ K0 d. M; i0 u2 f3 z1 H# j
while(p2 < n)
; t: F* j' k# G# V, O2 \3 D
arr[cnt++] = nums2[p2++];
5 `& n j: e& |
9 F; f* ^" r" g
return arr;
0 X. d! n- c$ k7 d$ w9 e, j
}
' N Z$ Z. V6 Q, q. a& j4 k
5 w' @- M8 ?2 B9 t. M7 s
1
+ y/ i2 |( |: u7 j# O8 g
2
7 c9 I7 c: g" P( V% C7 c7 w
3
- ?+ X! q- O! a# z& `
4
! h% L7 N6 P# p7 `4 F1 J# h
5
3 p+ s$ l* M0 I
6
+ s2 O! x* B+ O
7
( w: D8 ~4 m8 {; W- }. C
8
$ X: g3 K# K. |* z3 s! Y
9
, e! \* }3 ~( o
10
8 P9 N9 W8 |6 x6 s+ ~$ }, c" Y
11
% j8 ]1 c" r1 \- p# t) m2 M
12
: T. O) ]; A5 f( i, Y6 t$ Y
13
0 u! Q% Y$ E/ q6 g
14
4 `! V. W( u( J1 F6 P x& X
15
- z& Z6 N [3 q3 e( Q2 E& ]% H: @
16
' c% P* T2 I2 D9 [4 i3 c9 h8 M, _
17
4 v3 i. R; }# r9 G8 {) C( A7 l; ^' _
18
2 u* M* y% M5 |! `5 n
19
% X6 S( |; `7 m' o9 l$ |5 N2 `
20
; B9 k& L2 l v" O) j0 ^
21
2 ]9 i- G- o& ?& ~9 i! N3 v
22
% A) {& n1 ^( h6 i
23
C& f) q( U. u) |( ]
24
0 v* r# ~1 M( |
25
! z: Q1 [" h, d' j$ A
26
& e9 |0 B6 y' m
27
' Y- i# o) {3 y! i: c. o k
28
; l* d0 f) a0 @
29
8 ^, p! ]9 o6 Q3 \3 A0 B
30
. T( B* R( L! [3 Z; p+ }3 x. u
31
: @7 n* A4 e9 p# P2 X/ F/ W ~
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
9 a3 b" \4 @7 b
; ?4 x* i* ]$ z0 M3 W. a& ?
递归实现
$ P" c$ b, J. b4 j- e" Z" c
通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
# y7 Z7 z' ^7 c3 n- k
# L$ Z$ x/ f" U! t+ n
0 q9 @8 M/ J/ }- P: p) ^7 r9 B
! m3 v/ P- D( e8 Z6 h
* x1 d k8 _( P' F* y
$ X# G) |0 {; ?
void _MergeSort(int* arr, int* tmp, int left, int right)
- `/ o* Y4 g1 F a/ s6 ^! z
{
- k% ~! h, f' [2 ?4 k- u
assert(arr);
: S z1 A& _# M: S) s+ r# L
7 J" ]6 m+ [, l% _- a. D: O
if (left >= right)//递归结束条件不要漏了
* O) C) w2 ]9 W( T9 H; @2 Y
return;
# r9 |7 I6 p) {, s" r# R; ]9 R
# q- c+ K2 t0 @5 w$ a: ~
int mid = (right - left) / 2 + left;
7 L4 S# w# z, g) a
: |! x! F0 y7 Y6 p& a- q8 }2 `$ L7 I
//划分左右子区间[left, mid]和[mid + 1, right]
) m, b& V& ]1 w2 Q9 i/ W6 r
_MergeSort(arr, tmp, left, mid);
4 h: e+ D6 n2 h
_MergeSort(arr, tmp, mid + 1, right);
) e4 F7 V; S* J* l/ [1 V T
2 e% {' \0 {6 E5 _, t" t! X
//归并
i$ h8 N3 [( `# g% j
int begin1 = left, end1 = mid;
; d5 @; S! V8 W
int begin2 = mid + 1, end2 = right;
4 k+ f& p5 o( ]' ^- {+ ]
int i = left;
7 G$ |- u5 |: A
while (begin1 <= end1 && begin2 <= end2)
+ Z6 G! B. t, K% q
{
8 M7 H& H d5 ]/ P* s. J
if (arr[begin1] < arr[begin2])
! \1 S9 N$ [% e1 r
tmp[i++] = arr[begin1++];
4 |6 ^, y2 F# P
else
; _5 E2 Q h/ K( ^# Q: R; j
tmp[i++] = arr[begin2++];
5 `7 l/ A2 Q% C0 |# s8 H- w6 \
}
" P- P9 p. r- P+ m7 ] G- e0 Y
i" K. I d( G: h4 l. b: _
while (begin1 <= end1)
1 p! i: m$ e' X2 t
tmp[i++] = arr[begin1++];
8 L7 s8 o4 s3 j
while (begin2 <= end2)
1 O: R4 _6 D1 Z9 H4 l% J% `
tmp[i++] = arr[begin2++];
# V: i6 @$ i+ f; Y8 `
( M9 r$ J. [4 m4 f1 r
//拷贝回原数组——归并哪部分就拷贝哪部分回去
, x+ \5 F$ @' Z; i$ I3 e
//而不是拷贝整个数组回去
, N6 |" B& g% \& A4 {& A* X8 ?% w
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
8 i+ H4 M, w& U4 f
}
8 k" s6 L9 N ^; G: s) i; {8 q
: ^) V( Q7 v' t* @0 W# U
void MergeSort(int* arr, int left, int right)
- n! S/ {3 \, q/ Q+ J
{
8 s& O y3 n5 L% ^+ J/ h" m
assert(arr);
) h- j8 B* a8 P
. u d; I: ?1 M/ n* `2 u) t
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
2 D% D: n- \7 ]( D# G
if (tmp == NULL)
# s- G" M, V# N. h+ p
{
0 h6 s4 P. a% V0 V4 {1 u0 h7 l. k! S+ P
perror("malloc fail");
K( g; p- z8 X
return;
. `( N$ J$ s! F+ c
}
. ?, c% i6 u2 N9 P) s4 |/ ~1 ~
9 b* @% D7 M% \9 X, c. {& W" F9 y
_MergeSort(arr, tmp, left, right);
4 S+ B/ W# u+ A8 D# w* g0 x7 k- K
C" N) c, A3 r7 _) ?+ }9 r
free(tmp);
4 o0 }7 A. a. f
tmp = NULL;
1 R& ^9 ^9 \3 |4 p+ `
}
+ N) r$ P0 u4 m }
* `- C9 z D$ H0 R
1
# Q: D3 Y" H1 t6 c) w
2
- o: m5 w$ u4 [
3
! ~) R: Y. T2 ]5 A* F
4
' B L6 {' @ R2 D3 X
5
) {! f8 j6 K+ B0 c9 w& J) L
6
d7 n* R) k. }9 N
7
, E# i9 Q; c+ }& j
8
. [* a9 m4 Y& X' `* i0 T( C
9
$ `8 m" U$ @4 ^4 O3 l6 C' Q
10
- R/ G, k1 t3 [! E/ O$ n
11
' Q* n, Y) ^8 a- A: Q- C& y
12
, p8 w" J4 O( Y
13
7 m, O. _6 F0 Q+ C. o. N0 ^
14
# y; m5 @) S l( R) L
15
9 B' H8 h4 l, u
16
+ W$ a% Y/ W: ^: C% `5 l
17
- K, e, U! K! V/ C' F9 p
18
5 ]2 Y9 f. h& m$ l! _; w9 M" z
19
0 c& ^* b+ O6 j3 R% Q
20
0 I* `+ l: |* c- w v
21
% P5 j {5 M' f$ F' {% t
22
% \3 r- o1 J$ z
23
8 a: {) N+ ~7 C
24
5 ]- \% F. f3 o0 |
25
& m$ y# F; Y4 x
26
) [) L3 M% K' X
27
# q1 j0 e% j9 u% r
28
8 q: t& o/ @9 b, K5 B$ Z
29
4 h1 }% V2 ]5 X1 _
30
+ T& \, \ K% m% u9 _0 [/ R
31
: F+ z2 n* W W$ V/ E7 B" v1 D
32
4 z0 @# o' T7 r7 p
33
3 Q+ O9 g; W0 M! V8 i. Q5 m
34
E) W- }4 P: L. w( ?5 Z9 a
35
9 H' j2 H, n" M
36
6 W4 b& N# m3 R1 W3 l% y. O% ^( H! c- c
37
8 K' K) b2 `1 p. J6 ^, D
38
0 A- K) z; u, Y3 [% L+ B+ A
39
1 ?; t0 g3 G7 V, I7 ~
40
0 a6 e5 n$ ?4 T
41
. M& g1 z5 u( F! p( F
42
( j+ M# W% F' \' D! a0 y
43
" C+ t& ^' Y: Z: ?0 g* B
44
7 J" i( w: v$ E t6 h. o$ O
45
! T6 s, R! s" E3 K3 b; `8 ^9 Q z* H
46
1 k3 W; b- O* f; ]. M7 B
47
( u u0 p1 l4 h0 m$ O
48
+ b0 E' }, ?1 x. E# R5 y
49
V% @! z2 w/ R3 Q) B
50
! z( l/ a) r: E7 v
51
$ E6 _/ D( a8 [: v1 o1 Y9 M5 ^
非递归实现
. o! @% s7 q6 [8 g
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
$ i9 O+ r. N( Y; D( c
. f* q% T3 _' D, @* @( @
8 \; p& m; R ~8 U+ X, S
, I) ~- C+ M, G5 \0 Q3 J S$ z5 S
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
! F M; f$ G+ W7 E6 _
: h3 S8 ^& D K. D6 M; H5 x, W
还要注意区间的取值,每个区间就是一组,就有gap个元素。
. ] Q( J+ A: S7 p% k* o$ [$ P/ }. R
, ~4 {: {; I8 y& R0 ]
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。
; _ M! ~/ p8 h
" p8 t& B6 W# F+ A% O E. O* s( ^
代码实现
& N' ? O. ]8 [' i; `/ U
1 ?5 B* j4 U: O/ S
void MergeSortNonR(int* arr, int sz)
4 }3 \2 g1 S# s8 ^/ v$ m% Q& y
{
. u( f3 \9 A) R( d) ~/ m
assert(arr);
8 o5 i/ Q+ i, E3 o+ z" Z0 N
' V+ c, w2 f) {1 J2 B/ p& Y$ g# l
int* tmp = (int*)malloc(sz * sizeof(int));
. F/ Q- f7 N, j7 ^ w$ z, t
if (tmp == NULL)
7 U) f7 r$ R1 b. ~- `
{
# _$ M1 x5 `$ d6 |1 k2 F7 [3 r
perror("malloc fail");
. [. u, g/ s R2 W" X6 u4 ~
return;
7 I0 K% d3 v2 s, f
}
/ K! B2 M1 T) L( ]" T, M
5 j% a, O7 Y% j" E
int gap = 1;
) V8 C3 r0 n0 d! @- L) l
while (gap < sz)
0 P4 V- b; j& v5 q: g
{
$ c9 J2 o$ Y' \& E
for (int i = 0; i < sz; i += 2 * gap)
# ^8 m- `7 f( Q: N0 W0 @0 ^
{
8 M. N. \+ c. K. ]# M- v1 [4 n4 J
int begin1 = i, end1 = begin1 + gap - 1;
% G: S, R. N# _" a* D7 t( O+ J# _
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
0 \9 q) n# }3 V1 E8 e) J8 H
int j = begin1;
& b8 B' d5 d' r' ~6 u
- ~: Z0 f" |# I$ P
//归并
i' g4 d0 G |$ m4 s7 \
while (begin1 <= end1 && begin2 <= end2)
6 V; ]4 W r; Z9 ]2 T" c
{
- i( W! t; M* D" J( J9 s4 a8 _6 F# V
if (arr[begin1] < arr[begin2])
" U8 s! W9 v5 j( U% K
tmp[j++] = arr[begin1++];
+ i& R+ q+ w% g* J" _
else
* c3 H6 @; G$ i* ^1 E2 L7 f7 O
tmp[j++] = arr[begin2++];
3 D, M3 \/ g7 F# G6 T2 e
}
$ u; s" u8 G9 m+ ~% E
" d$ A5 C$ |3 @8 i! ~
while (begin1 <= end1)
! w" d( d% w: F r0 Y3 U
tmp[j++] = arr[begin1++];
o1 i* I9 h' P
while (begin2 <= end2)
4 m' r& x, h0 N O i& [6 U4 X4 `
tmp[j++] = arr[begin2++];
6 I: C( J( V4 N; l4 R
$ S0 p5 D7 d) U F2 F
//拷贝回原数组——归并哪部分就拷贝哪部分回去
! [, f% Z8 {# J- q+ N$ t1 K4 q% ^
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
3 i& r+ t! `8 A; _- N. d4 H: o
}
1 X2 o, }4 [/ V) @) h
gap *= 2;
/ U# G0 F( Z, V2 ]5 R* b$ L$ J
}
/ B# ]' N4 P3 |: h+ b* o. k: z
$ p& a4 d# }) ~0 O# J) e8 Q
}
- M& W( }% ~9 n- C2 f& k5 Q8 j
+ D) f' u$ Z2 [/ o1 L3 w2 U
1
/ ?9 v. G: ?8 W2 n
2
1 b5 h. J" ]3 r. I- S
3
" L/ D+ I' X# D* o( C3 j
4
1 ]9 _2 B/ v* x+ X' e: o
5
# ~3 r: U5 v7 F( d# z% S
6
+ W2 x% O$ v$ k# I
7
8 k. t( A5 S+ b; k3 h0 q
8
6 S4 g+ r: X% T% ]7 M' w
9
! v: q0 V8 ]/ X, s, c! O
10
- e" Q* u/ v& V0 N- B. ?
11
( V/ x/ E6 _/ J8 S
12
# T7 f# d6 r$ `7 z/ X5 S
13
' Z% G' G$ I2 G j, V H* x
14
# ~7 A" l3 c5 u
15
$ u' }8 `' w( l7 k6 L$ g0 a
16
% }4 |- d, T( d* Y
17
( X; x0 K# n4 Y8 k) n* S
18
: u. h2 s" z$ u& M4 C: l+ a! X
19
# a* n" {/ ]/ V8 Z7 ~
20
h h N7 h7 v% T. L6 l7 l
21
& U1 i* l' l( w2 N& V
22
+ D5 g# ]9 l& O- b
23
& ~+ i i: S3 a9 s1 B, }
24
+ X3 F t- E4 F% I6 W
25
6 E6 w1 H* Y# p ]; h/ I4 `
26
) h7 B z J- |; T! Q
27
; y: @7 a$ _4 X, t+ x2 a: n# n
28
1 J$ M' P; y/ d. I. y, O& A6 R1 M
29
: H4 ?' O3 p, J* P
30
- Z% m* O! j2 A" u6 a$ W
31
3 U' {1 M( \+ I# z: e
32
7 P% r$ ~% L; F
33
0 X4 m5 Y; [7 n
34
( [- B/ d- s F* q0 s3 C% I
35
2 q Q( ?& A9 {5 @/ X1 W
36
# h( B3 `8 \* I; h: [3 p, q; L
37
, K! b# U. [8 ^( J8 ?6 x
38
! |/ x9 [7 m* g) R7 |+ {
39
5 \& Q: E, O1 z0 E1 g
40
* r. f2 i: V" o! w1 J& N: [& W4 Y
41
( ]4 d% P% Q5 j( T( ~
边界问题
* e7 r g2 o) ]0 {2 x
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
* D9 {& p4 X. g8 W* [" c
4 u% W; l9 z- Q3 r; d5 L
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
$ q& c3 v' e9 K1 o/ a: S
! K" D. ]3 n) S1 o
% Z5 V& r9 g N, u9 g
$ E2 y+ i- Q i, K7 n# X7 T
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
; X' N* Y# f- H6 K
& _, x3 S- Y' E' G
第一组越界(即end1越界)
+ f5 D6 [# `; m% m/ k
) u: u# Z4 P( i! P( C+ a* [) N0 R
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
) Z: l1 z- t3 X' G
1 M1 U% |& C: r6 l4 U* r
第二组全部越界(即begin2和end2越界)
. V# C; S5 P4 v9 G9 v
; E L9 L: D. I' x2 h% G# m' v
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
D5 ^1 P5 g; v5 D5 v) h- w, L
2 W/ [5 u. e9 `7 h% \* Z8 ~
第二组部分越界(即end2越界)
) `% p0 Z/ b% Y' [ a" Y* `; Y, K
+ P- F9 w- e% ~6 E
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
* C7 s {6 H4 w; p- y1 a
2 R+ R6 y) U# I& T8 e
其实第一种情况和第二种情况可以合并为一种情况,原因:
% m, K7 t' x9 p q& g" @/ D
5 w4 O. v. Y+ E) h' O. T7 k% f
end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
8 Z1 u5 |, @0 B
4 G& [: ^# H/ |" Q
拿两个数组试一下:
* n/ @3 i ^6 z( v7 A2 k* g
3 U p6 |& E7 F; Q6 ?# i P" c
$ L; a# {. B' Q& l2 d+ T
: B1 }9 D; y, }$ h& V0 a
+ k$ m0 Z: [4 A4 [! y8 A
3 [' Z% ?- S" O% r3 w# B3 i9 J; R
代码实现
2 [3 m) f3 X5 b$ u5 H* K
5 j% _$ `' i: S# j6 L, X; L
void MergeSortNonR(int* arr, int sz)
& m+ X; n2 X+ |
{
1 J7 e7 o& b* M! @$ n
assert(arr);
7 n6 C' `- n R6 p. b6 f9 a5 J
2 N8 w9 M3 I' Y9 f' Q/ d
int* tmp = (int*)malloc(sz * sizeof(int));
# j# z+ g+ D# m! y! e) ~
if (tmp == NULL)
9 ^9 h* I) c: Z4 D$ `, \, W+ u
{
* i# @# v7 F( d1 C
perror("malloc fail");
6 G$ Y7 a6 J" {7 G7 S
return;
8 Z7 Y- K: o" ]5 C, W. Z; o8 t; j! A
}
, C5 i# ?; u5 V' o" l; I
. E$ j+ u+ { c1 Z
int gap = 1;
3 _) {& B1 t. Q* k: x3 _
while (gap < sz)
+ I$ M" d% W/ o: F
{
6 L f- w* O% v3 {0 K
for (int i = 0; i < sz; i += 2 * gap)
$ s9 f* X9 y! d$ p( Q
{
, d; T3 R M. c- t
int begin1 = i, end1 = begin1 + gap - 1;
3 P- f( ]2 O5 \4 G8 c* c7 C: O; n4 L e
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
! i c3 p( e: v2 |+ G
int j = begin1;
( L. N3 `9 V& \8 r4 ]4 [. M
//越界检测
9 K, J( o6 W" {, [7 _2 F' L
if (begin2 >= sz && end2 >= sz)
. } M& D/ z" t! b
break;
0 e* p9 p% c' ~* }1 }
if (end2 >= sz)
% N% g/ }" Z# E% H
end2 = sz - 1;
: E: q8 t8 e' m- @) X
//归并
& _( a& `7 u# M/ \
while (begin1 <= end1 && begin2 <= end2)
2 @& ~' i8 [! A6 n* E# |
{
3 o* b1 L4 x8 e9 l/ [
if (arr[begin1] < arr[begin2])
. _- K# G4 [/ @0 ~9 z# b0 W0 Q
tmp[j++] = arr[begin1++];
. d% |$ o5 S' Z% c; \
else
% V9 ~' s$ I4 K2 E7 a5 P B
tmp[j++] = arr[begin2++];
( m$ k* B- z7 Y# Y/ v" |2 Y
}
" B8 s3 e% B9 C* d: |& X
5 Y* t5 ^ y: m- d! w
while (begin1 <= end1)
C s( S& M' @5 E# O. P! a2 p
tmp[j++] = arr[begin1++];
4 x# o5 x3 ~7 |7 q9 g4 c% f
while (begin2 <= end2)
) X2 S+ a% z; s P, |# @
tmp[j++] = arr[begin2++];
9 Y: _5 N, ]" A# g% U. `
, E5 f2 V! S2 ~, Z8 p4 r
//拷贝回原数组——归并哪部分就拷贝哪部分回去
9 `& }+ y0 R# Z ?/ i% m0 Y
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
* b `7 a: j/ N; p9 d4 u1 G# K
}
; g$ ]# l. d0 P0 b9 v
gap *= 2;
+ m; c: g, U6 ?- f
}
: c3 N% k0 {1 w: J# d0 O6 ]
7 }# {# \' I' ~4 r8 h$ J7 Z/ i7 `. i
}
. _, r4 i, p2 x; s) U
! s7 |+ A/ ~# a3 X7 R0 h% H$ _: k
1
; P3 d* ]% B* L+ u% Z8 k
2
. t" Z# y U6 m( }/ `. |2 z# b8 z* M* F
3
, N$ P8 |; R, `
4
4 `$ S- D% _+ b) p K% q# t
5
6 m, M7 b3 F' k' j0 S6 Q& a* o$ Y
6
' p. j& S8 p$ Z/ a& U
7
7 v& _- K( L2 T6 |9 ~
8
( Q5 M* _. X; `% u6 y
9
: Q6 `6 g* d$ I+ b% a4 p2 @
10
: S! w1 U' d! L, b' O) t' ^/ n8 x* F& Q
11
0 U2 ~* Y$ t& F# b1 {( V! L+ O& N
12
6 d+ N" W0 Q. P3 c5 `" n: H1 N
13
( m! |# M$ J* S( q! A
14
- U. c8 h" @2 f! F" k3 Q
15
( i/ d; S: p& [# A5 p
16
/ D, ]7 c3 K. g( N9 t/ p
17
p( J4 z% e, g, j ?
18
, O3 n2 Y8 Y5 c4 P2 ]
19
0 z' P* P9 {1 i. E+ E
20
# Q k; L) S5 F+ G B
21
; x. o4 Q- x! c1 O$ L* y9 N
22
7 u* U- d4 s& }
23
' l& r& h# ^9 A2 Q
24
0 `: E1 A% ^; r9 `( g/ ^9 {
25
5 t/ q- |& @) N" Q
26
; R9 Z, w; {! e8 U( }1 f
27
* H9 d2 d2 }3 I- t5 h
28
2 a/ K4 L6 w: S
29
) b! W! l0 {3 l' t3 K
30
6 N' Q5 }3 t. c6 v# ^
31
1 |: _6 R9 [0 z& c+ B2 i* i
32
2 m- i$ B1 w3 f6 n- _
33
G+ o& ]/ f4 J8 J4 o% L+ n% `8 s
34
j5 ^# W/ l, J2 q9 \
35
3 n6 n6 r z* m6 ^" z/ m
36
' g' Z4 j9 W8 n5 A* e' u
37
* g) x; p8 X8 ?/ b" E( \
38
* G1 K% `5 z" S: b7 V9 t
39
& G( i( E& k( \4 o# D4 Y7 r
40
2 \. t( M9 `+ y, K$ J' V
41
4 ~& q7 }! ]4 M3 C! e
42
: n, {/ \" X' [$ C4 q
43
5 Y |1 G; f, Y: \$ k4 S
44
7 O9 B* k" Y2 s
45
" t, R1 v4 X6 ~' z8 \8 |. `% q: h7 ~) h" k
归并排序的特性总结:
1 o! [2 J- a( B2 q4 P7 t
) v q; k( v& K6 {5 W. A
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
9 d* N! @9 K% w5 b& Z( h9 f8 P
时间复杂度:O(N*logN)
) n! P' Z e* e$ b* M
空间复杂度:O(N)
, n$ J* J' F1 M! g& [
稳定性:稳定
1 [8 |) v7 P4 r7 s# r
; d2 |1 K; x. P
————————————————
4 f) {% u4 h* E* G! {! { N
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
3 d/ Y2 _( t, ~/ X! ]$ ]) f
原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
- o2 R$ W* h( `3 B, P1 q
# _ g# T8 G1 m% G3 M
, C" w, L" D0 o( h3 O
欢迎光临 数学建模社区-数学中国 (http://www.madio.net/)
Powered by Discuz! X2.5