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