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