- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 563249 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174198
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序
0 D4 m( ]% {: V5 R( q
3 U" ]: e6 f$ T前言: J+ q x0 ?$ \" M% ~
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。: v/ o+ Y( Q3 g7 A, n' G9 f) C3 z n
0 L% n% U! X3 M7 Z K
归并排序
, o6 ~" x2 m/ M; P9 u6 o基本思想
, k9 }% B1 ~# w 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。# E# s* A' A2 n
" ~0 H( g$ j/ N g! u7 \' X: R. E6 y1 g& @& |
( ]7 |3 `8 y! D% Y! a
合并的思想其实和有道题目的思想如出一辙:4 v* j8 g2 k, ]; u, m+ I
3 o5 X5 a: [( `3 u' J
' O, C% h- L. b3 E" y0 w3 X) X5 ]$ f) z3 m/ I' K- T( X
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。$ z( c6 D/ O ^5 E' u$ I2 J
4 a" ]( t9 u- T[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
2 b* @. F" j2 b, u
; I' k9 J. a+ l S! [int* merge(int* nums1, int m, int* nums2, int n)
+ H3 _- C- F; d- A+ J{
3 ~7 C2 f* T7 L# P& |5 Y" o5 d# b int* arr = (int*)malloc((m + n));
- D+ z2 s) Z3 x" N& @ if(arr == NULL)/ R, D- @. G. h! O* y+ k
{
- [. q3 d% q; u" A perror("malloc fail");8 G/ U, N2 L2 B8 h8 Y: z
return;
2 ?- q7 I0 D/ t/ x" ~, C }
# m4 x+ }# C" K: _! j9 R9 F6 i! E. A( u) U5 b- T
int p1 = 0;
$ I* s% T' S0 \ int p2 = 0;: \" s2 g, \( P: R( G8 r
int cnt = 0;& q$ R- a7 E# Z" I* L6 T/ m. {
while(p1 < m && p2 < n)" B) M. c: r: n+ q( x! f
{
" O& e! D7 j/ ^' u8 D0 j if(nums1[p1] < nums2[p2])
8 \9 \2 X: `* G& g% @$ N: j3 Q7 u {4 O" t- N; l8 H. ~5 @, P4 q) W
arr[cnt++] = nums1[p1++];# E' E7 [( {+ P7 f* @" h
}
/ o1 f! j/ x e+ A/ }8 D6 S else
4 h, b- c! `+ T9 I" |/ X {# H/ C g, g9 L' K9 L7 U2 ^# i
arr[cnt++] = nums2[p2++];; Z5 h/ o9 O0 v- }5 G
}, ]9 R6 S q" I7 [3 A8 |1 a. s
}5 [6 L: Z3 Q( k% t5 w
while(p1 < m)6 h0 C4 |( C- M5 Y; n+ d6 t
arr[cnt++] = nums1[p1++];
1 a% v$ f6 u' T' m' G7 a4 N0 k; ?6 b
while(p2 < n)) ]: V3 v% [2 X( U9 ^# i0 K. D
arr[cnt++] = nums2[p2++];
1 h" a s/ N) t* D# R/ J* ^' Q' d0 C6 M k6 n/ l* D
return arr;
2 D6 e0 @3 d6 z/ ]# X" v7 z}" l T" j: F1 i- J; J
& t/ b1 S5 R" n% e, b1
. t, K" r& ~# f* X4 {. J4 T1 u) q. p/ p2
7 x' ]( Y" P& s4 @# _. z6 S& n3$ t, B8 G, o) e+ ~8 G
4
0 r4 z2 P" \' z% F5
$ s* @, z. _! p/ @' k6 W4 l6
% U9 _" p8 S1 q$ b# c3 i4 Z: e; `1 N79 ]: @) r2 ?1 o/ F% ?- h
8# Z6 h. z) d9 V' G M5 S
9
) P2 V3 k3 p6 o" o( o10
8 V: P1 N7 M+ d% P0 H11
) V' v+ N# O& ~, D! B; w) ?& b12$ @5 t7 H; W6 b) Y( f
131 {( s( Z8 k t" h
14
- ] o T1 m( V5 ?15
7 e# y* L8 u9 ~16# a+ x) |, b! }: a% l( U* ^
17
1 [. N/ `- q0 ]8 u! E/ v18 f6 V5 B, {& A1 l5 l, Q
19 f, n' K6 \; }! s h
20
3 Z o& k, M+ j; E7 V8 ]% }21
; |: H" p. |" A. R8 S4 d22- o8 M; d' r' d& T( q) L
23
: R+ @ _- m; O" Y t24
9 z- c8 n$ Q% U/ }& i9 |25
" e4 f. _* f: g% t. P267 Q$ q0 S" |, Y, w
27
, \( ~( x' I- `( w28
6 N) Z% A8 i- E: `292 t) w$ M. R& ^! n5 h3 q
30
- p1 v$ [$ s0 i' ^; n& q! o& ~31
# F! r- f/ L2 t$ i$ i. o3 b 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。, A+ e" D% ]7 U
( i! W9 J- _4 }7 G1 U4 z8 a递归实现
& o) F) B6 a! ^( A- \- l! X3 @ 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
! @' f8 M+ ~* e3 J' `
, o. A* R! |# F! |1 ~' d2 U1 {5 l+ U; C+ I
% O5 Z# [8 \* s& Z3 [
4 e8 [" q. c& Q, m: @8 _2 _8 L4 k* e: F% z4 w
void _MergeSort(int* arr, int* tmp, int left, int right)' L5 U. r$ A, f. k8 j
{
7 X( i1 P4 R' ~& Z assert(arr); p7 u. Q7 U7 B2 `+ }
% o. {4 c" z6 l if (left >= right)//递归结束条件不要漏了
: |4 `2 I. \% H/ G' {. X: G return;
0 V. b4 n. t1 D# c* ~/ H% q! f. t
" P6 g4 t1 V1 W( \& X; d: F int mid = (right - left) / 2 + left;
6 d" w! i) N' K% c" W" b3 v% C/ e7 Z) Q- J5 l
//划分左右子区间[left, mid]和[mid + 1, right]
$ P1 O" e7 ~6 x8 A9 V* L. L2 Y _MergeSort(arr, tmp, left, mid);( L2 W% y7 O8 d3 {
_MergeSort(arr, tmp, mid + 1, right);1 @' `* B1 K/ G5 J& K& @8 G2 }, I
- I$ j7 y' }' N( c) J6 W
//归并$ S( p* b1 L* C7 p& Q; H
int begin1 = left, end1 = mid;
" p e- e4 z4 K/ Q int begin2 = mid + 1, end2 = right;
7 g% \- d+ k2 n int i = left;
! G2 S! u( ^7 W* I$ K! {" O6 n9 ^! ^ while (begin1 <= end1 && begin2 <= end2)! _5 R) Z! ]0 U7 d
{- g3 U7 n/ J- d# X# C; p
if (arr[begin1] < arr[begin2])* H0 S1 Y. _, M
tmp[i++] = arr[begin1++];7 S! Y, a L- l: w( e
else9 m7 Y* r$ u. V5 t4 |
tmp[i++] = arr[begin2++];. X- ~' j6 g. {
}) H6 `/ Z* R( N7 B' u* R9 @+ I
$ z: i- o' F& A* v9 d while (begin1 <= end1)+ L! u% s' C: \3 v& M
tmp[i++] = arr[begin1++];. i: ~8 Q; ~" ?, X& b0 Y
while (begin2 <= end2)
$ K( @8 ^6 V8 g( E7 o1 k* _ tmp[i++] = arr[begin2++];, |1 J u# Z, X; p
: r4 K& D: U) ]" s //拷贝回原数组——归并哪部分就拷贝哪部分回去
& [! F& ^4 l9 y9 | //而不是拷贝整个数组回去
$ a1 S* X0 M+ O( l; D- C( [ memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
' w% T" M/ G* P8 i k}2 g, J# c# U G( h) x6 [: Y
" t* N9 e! C% p* F0 pvoid MergeSort(int* arr, int left, int right)4 z6 n" e; T! r- U8 C+ _/ ~% D
{
, _1 A- v2 C; C' R# R1 p' p7 S' e assert(arr);: Z E6 b( Y7 J6 }/ s
p. e# y8 b; ?7 o# l
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
, d' v, j1 F; Z+ H9 a3 k, ` if (tmp == NULL). n: M1 a$ T# f I2 t' q- U
{, [+ E6 V4 u! l4 n9 ?1 e) H9 t# J
perror("malloc fail");2 f+ i: X9 y8 X- `! M
return;
3 H- l0 F( H# R: J. j/ r }8 R& r5 W; Y# i, ~6 B; S
: ?5 a7 v# F" j% T) S _MergeSort(arr, tmp, left, right);1 n4 f0 S+ c' g! T% V
! @: o: M) `. f free(tmp);% x! j0 ~' W% u9 M, ~
tmp = NULL;$ }' ?# |3 {, t; W O2 Y
}- s. a \4 n' a0 r' y% ?
7 P3 z6 j' C5 B6 \4 y# k, p
1# {& s( J8 O, f3 _( c T: R
2( d4 f" L$ }+ h0 K
3
% Q7 j0 C; I" ^( f- ?' ]4
+ Q9 D& ~. v! E+ f5
- h- ?7 K; |! G) D( E) C6- D% @. t) T3 L! H2 p6 K
73 G+ Z) z% l) O! f
8! H9 }. o- D! z. o5 V8 _4 \/ }1 j
92 C& w& |+ H8 y m
10% Y( L" ]. `& I, ?* |
11! P/ t( O, @# ?
12+ C1 `' Z, J* o% l- F2 X
13
. G& b7 q+ B* j9 F3 e `; F14& w, y* E0 o, B* N$ J* L9 f0 u6 p; H
159 W3 c3 A' |' k: _& _) \ U
16
4 ] y' D9 [; t. w173 i$ @, n' F! z4 Y
18
) D/ r9 m5 E' ?9 t5 z t) e0 q6 \8 Y19% C# F* D V0 O6 K0 r. m) O/ d
202 i7 u) s1 w# @, X! \$ X
21* K o+ ~3 K! p8 ^. O- J# Z* d" `
22) y7 k- N- m) P, x6 N: A
23
% H# t7 h0 s* e4 U24
6 [+ }4 S, K; U Q25
6 G. [$ D2 t3 I9 ~ C: @: {/ d26, _, l. |5 K- U$ T4 r; e9 e
27
A2 n6 r* c1 f28
9 ~# ]) A, n a9 V( b292 O9 a7 d: A/ @6 n, a' B
30: J3 d" Z# [1 ^1 @" p. ^1 A% ^5 e
31
& ]$ B4 s- Q8 M0 m32( f$ e! \( e3 A
331 M) I) B% j5 e, S- ], s
34
$ v6 z$ V. e9 j5 k' k. `, ]* v35; g" |7 A8 y0 I3 I) S: E* g
36
8 E& y' o6 X& U& E! z2 r37; C6 T+ W* _1 {4 H9 P. @$ E# d% t
387 ]+ ]5 v# g$ x
39* J9 \7 {9 B( |" e; g
40- g9 y; L: L/ Q( Q' K5 T
41
8 B* I$ j9 {" v- u# h9 p42
" ]& y5 ? T: O, a43: W/ A9 p' X6 [ T `; G
449 P, {0 E9 C. B
45
, C7 ^9 t* n5 A" @46
+ P( ?; b) a+ X) P8 o9 X47
2 T. n: u; \& D48
5 ^5 I* H9 [, Q+ E/ v# p. t& o, a49
' ]) p. Y# P; Q: k7 M50
; D7 j( ?4 r2 O% R& f! w51
5 ^6 [: u5 B: L- o0 H {) f非递归实现
" b, [' d2 S/ ?0 e/ x. k 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
# S @0 l) {2 f. B3 V9 R$ W" H$ @& k" ]- g2 \
9 v6 ]6 k% R9 T0 j; V
: V& i! H4 J2 |- }0 Q7 |# k0 {& J+ f( S 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
* {9 K9 R8 T, {
3 E& d* P* o+ {4 N0 }* } 还要注意区间的取值,每个区间就是一组,就有gap个元素。8 e! g9 q2 [: T$ ^
, d6 u2 c" @6 m% k1 h6 O' L 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。1 |6 L0 k0 v1 ?0 f& ? b; |
4 A1 w3 {9 s* W" G. d9 j4 m8 S代码实现+ _* F+ P1 y3 P; u. ]( v5 k
G) m' S; Y; I1 J
void MergeSortNonR(int* arr, int sz)/ {4 p9 D& N: U* s8 _5 O6 J
{
3 z$ p# t+ [4 @& o4 x; j/ K& E3 u assert(arr);1 x& z$ z0 [: R( V
* |5 Z" N9 o& r$ o$ R- X: c3 S" U int* tmp = (int*)malloc(sz * sizeof(int));
; U- u. R9 l3 D J* v: \+ P7 _2 y if (tmp == NULL)
) k2 D( K: Z' } {
5 ]! [, @! ?! n/ K4 d- O perror("malloc fail"); O2 [: ^6 g0 @. d, q' q$ o
return;9 \+ |9 n8 w7 K
}
, g: t/ f/ Z5 v# r2 ?8 ^( Z5 S! o: O( f; C: @1 m
int gap = 1;
/ w8 x/ \/ Q* ?' H! w- ? while (gap < sz)& `0 P8 E7 w- {, N; f) ]4 g. n1 o
{
. s3 @6 x# l2 `! X for (int i = 0; i < sz; i += 2 * gap). j8 `( F( J6 L* f& l
{2 T( k$ \0 @( `
int begin1 = i, end1 = begin1 + gap - 1;0 x7 \% @* Y" d8 o9 W, _) F
int begin2 = end1 + 1, end2 = begin2 + gap - 1;
% v8 Z- ^& _0 ?# `% F int j = begin1;
$ V1 R" H) P' M* Z
0 j& G8 I6 a5 |: t- A$ [9 v //归并
) E' F" `8 W6 B7 V while (begin1 <= end1 && begin2 <= end2) {1 ~$ l5 I; `; N$ H% h; R2 m
{# G* w8 K* r& z) ]! `% H
if (arr[begin1] < arr[begin2])7 G4 M t5 k/ |9 o' |/ {6 z
tmp[j++] = arr[begin1++];2 n$ n* {' Y1 {) `- I* O
else 8 o# K3 n$ N; M$ [& E$ P# u
tmp[j++] = arr[begin2++];
! y, i9 ~, t" L, D }8 h5 s$ I J$ O D+ |' o" \1 v& y
+ U: S8 p' c4 s6 X `( F while (begin1 <= end1)
$ w9 e( A( g% T tmp[j++] = arr[begin1++];; D5 F/ ?+ O- a+ R- J
while (begin2 <= end2)
) P" n& ]* @" ?) Y. l, k7 `% K; I% [ tmp[j++] = arr[begin2++];' n/ m, m7 B$ V5 @# Q
' M# F, A* ?) t) j4 n; j
//拷贝回原数组——归并哪部分就拷贝哪部分回去. i2 V _2 t7 W0 m$ H5 w5 L. w5 A
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));3 ?0 A U7 y5 C, `+ \ N4 O3 `
}
- \, |( t( P% Q& C gap *= 2;" Q) L/ M; U' G% ~$ {4 @
}
' w# s' N) Y" L2 C* G" h6 Y8 T; i8 I& e O
}+ O5 p2 {! ]! ^9 {) _ l5 \
' ~" C0 V* ]3 | M& K1
' X8 P8 j& J t2
4 ]0 K R1 Y0 |, D3; q% y' s" r4 A( m) w
4: H2 k d" W; O. j' D6 U
57 E" W, f. X, n
6
& Y1 N7 {5 n2 N6 N* M# G! L79 z4 c6 H* d$ G4 C3 T8 V5 v
8
/ u. x8 H, t3 {9
' P5 R" T6 o& d# z( A10
( ?$ H6 K5 N0 e; w# [/ C11
" x; y5 A6 S9 G12
n7 ]0 C3 y4 n( f6 c. h X13
?* V; G' G9 f3 @ S14
+ J. Q, K& R8 X, c: y0 I- y+ o15
& p6 s" |# b3 K" V! R3 m0 r4 Y* V" S% m* D16$ R* f" F: Z2 Y: X7 D
17! K( R0 t1 ~( m& e8 {* U
18
1 O/ m, Z' ~( w5 b19! b r3 u/ ^" v$ {5 M+ j
200 z. ?* n. D# w: V4 G
218 s }7 ~/ O5 B& F0 d+ P! a
221 }( b( X3 {3 ^) p: k2 o& k
238 v+ m' K# _" W+ Y
24
* f& O1 i) }9 ~& Q9 E25. U: \# W7 d, ]0 Z$ m
26
8 m1 G& y: [1 X4 K5 J274 {; m0 q: x5 D: H% K( P9 p
28
2 a+ }. p* G4 t6 U0 u29
% @9 T/ r! A6 |' u301 N1 N8 j6 \; O0 W! ]9 a) H; v0 ^. i
31
6 U$ w8 G6 p- O2 ?& B/ \32
$ y% Z! r. }+ I4 J33+ K& p+ I" V/ z3 S1 L- r% X' g% x" u
34
' g& l* D. Y& P" D9 M$ J5 O( J1 x353 n( S% L; B! c& {2 |( V/ X
360 {7 L7 A2 X- d2 O& t' z n
37
5 e; [2 k! I& C% S k; }+ v9 \38: y* Y6 p0 d/ Q* A, `: H
39 \: q: \. V" Z
40/ C$ C/ |' E# ?% c. ?' L! M0 a) V
41& w z0 z; J5 f! w7 p' V' R
边界问题4 `0 w: }2 P) S9 _
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
& z( c1 j4 a" _6 [: n1 Z
0 I9 }. B- w1 S7 Y) Q' m9 N举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:/ \7 u% @* n8 n! o& W4 X# f! k
0 Q, L$ [ g7 W$ ?
" X; j4 l4 ~! [- @3 b& j0 v$ |/ t/ L; ]" _
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
& P5 B( r) y' e' ~+ ?9 f
2 {: Z3 ?9 T/ J: [0 f, ^* W! y第一组越界(即end1越界)$ E1 Z9 q# H! r1 f% \8 d2 d0 p
' G. z. p0 m: n4 W' N. j
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。0 R) P+ V. j' P/ A( o& @
9 b/ i. s- h/ i: L8 R( o第二组全部越界(即begin2和end2越界)
& e5 F+ q' Y* f4 b: o/ C* {* e- m ~0 R9 f2 Q' }0 T: `
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。, j% F* b" q7 q; Y2 m
Q' ?. s" P, ?" h r9 N6 K
第二组部分越界(即end2越界)
2 R z T1 f' k# f+ h/ Y& Q1 F% ~& l0 p: w6 R8 a3 Y# v5 H k) f
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
5 K$ S, B& M3 b. Z
4 ]) R" `) [, C2 P7 Q H' h4 P 其实第一种情况和第二种情况可以合并为一种情况,原因:
4 A. R" p' n, y2 G/ u
/ d6 z9 o9 a' G$ _" e7 t4 U end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。& Q% L$ t7 x, J8 _9 q
, U8 Q6 y/ o9 x4 I9 x- Q' }: d 拿两个数组试一下:) d& u4 t6 J7 P5 n& v v+ Q
& `" a8 ]$ S) h/ n2 H" I. x9 a
8 d+ P0 D$ N4 ?- M c: D+ Y' Z$ h6 C U ?- @3 [: L
! j. |' M# v/ B! T' F
6 T' P0 I: ?5 t- n2 O8 \代码实现1 v* m4 K* `3 T" n* \3 h( o
3 J k( O# u6 c' C/ k
void MergeSortNonR(int* arr, int sz)( m9 A% u' F4 e7 t& ^6 e0 }
{
1 e* L* O1 F- Z# W- D( z assert(arr);
# T5 w4 w# p( J# j V4 a7 u' `
5 I* \1 _( Z a5 p7 T1 g' x) {6 y# N int* tmp = (int*)malloc(sz * sizeof(int));
: c1 Z# F, f) Z. k: G if (tmp == NULL)
+ e+ m5 |9 v* t% y {
4 U) K7 C+ [. f9 u c# `7 h perror("malloc fail");4 C1 w* H7 y- I# y* F+ ^; Y3 n% {" T
return;
# D3 `9 q1 X+ `6 q' e% B+ } }6 v. j0 Q/ @9 X2 ]/ J5 L7 h
5 i3 y9 h0 R9 p) T- i
int gap = 1;
9 v. S& Y$ W+ W7 F8 I( P& E while (gap < sz)- _% o% H* }" q/ z- X
{* ~+ P% |' z' B* P* [1 j9 T& m
for (int i = 0; i < sz; i += 2 * gap)
; F0 e9 _* V$ ]' i {* N# ?6 B' ^7 N. y3 q5 ^
int begin1 = i, end1 = begin1 + gap - 1;
1 e; c" r ?% a$ h- U8 ]3 N+ Q int begin2 = end1 + 1, end2 = begin2 + gap - 1;
4 b" f; m4 e$ x$ ~ int j = begin1;
( n2 G) @% A( m. w$ X //越界检测6 X2 n0 s! D. ]) n: c( b$ Q
if (begin2 >= sz && end2 >= sz)
# ]7 W _( B- \. z+ n; P3 P5 I) D" w break;" K2 w3 c3 t7 I
if (end2 >= sz)! ^0 e& I$ F0 U) [. |& s/ c
end2 = sz - 1;1 [, c6 C/ ?' B1 ~( I& M, H0 ~
//归并* p/ v1 K) l6 ]6 [0 d" ~, h
while (begin1 <= end1 && begin2 <= end2)
+ L/ m; [! W7 o {
$ c- i' j: ]9 j4 t8 V0 B( e if (arr[begin1] < arr[begin2])) R4 j+ Q6 b; Y$ X$ }% z: l1 p( s
tmp[j++] = arr[begin1++];
6 h. M: n! t3 M& H5 g" p1 p else
- q; a3 P, m9 p tmp[j++] = arr[begin2++];/ z- V B/ {4 @: ^9 Z$ t( W
}
8 s) E7 [6 N" O9 x) l# M6 {) O. D* j' h& Z( l/ g' G2 F! c
while (begin1 <= end1)
& t$ `5 ~! O* {+ ^; X tmp[j++] = arr[begin1++];9 `1 j+ r2 d0 N6 z2 \
while (begin2 <= end2)% ]0 y% B+ W) L& }1 [
tmp[j++] = arr[begin2++];5 {- U4 A ~" b$ ?0 X; b G
, n0 T2 [3 e& i3 }1 G) L //拷贝回原数组——归并哪部分就拷贝哪部分回去
) N1 d2 P6 i5 A memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
' Q0 s1 ]5 V) l3 S! d& I5 B }
" Z# x( g; w$ u gap *= 2;& H. e- A/ h0 e! |: S) H
}( `9 q9 S+ Z2 h$ A
, F; E p: }. o( `) }+ K& o& K" ?}0 o* ]) \; w$ \8 Q6 u) s8 n
6 ?9 t5 a8 x& I( z3 R
13 w1 W3 t" n5 d
2
4 D/ e* w4 I& O; \ E* j7 L' ?3" c$ P8 P3 O$ l
4
1 {$ \% m! z, u2 x51 p' R3 @# W, P# R/ ]0 P; h
6* O% [: G4 l: v1 i- p0 @
7& Y* o4 e4 \0 o6 S9 N$ H8 ^
8
; Q \) K0 |$ j8 O3 Y g92 c7 B5 t" W& C& i% J$ I
10
$ Y% C! X& Q9 \7 B( |* c* L3 Q11: b8 n- v7 H* d) g1 i
12
; i, |+ P+ ?; P5 V' N3 N% b136 _ y+ G) ~) q/ C7 ~5 z
145 b2 \ K, G& ^+ r
15
: {! c) J9 i3 K7 e6 M: j16+ Y0 j. n) q W7 p0 B3 I9 r
17
8 F6 J2 P3 j. j! Y, _18
2 k+ H& A8 f5 y8 P; `+ V, q2 K& w191 G" ]" O! a# G5 M! |, V
20) G! U6 [8 J/ W- z: L# e
21
" p5 i# C1 b' k0 Z* L22/ ~; _9 o- \- M! }, @
23
R# O1 ~0 v6 [- v9 C3 M. A24. [$ Y1 H( b7 I/ @" X- d( g
257 A% J$ Q+ j! V. b8 v5 ]
26( C" C: s( f4 q Z6 [& S2 ^
27
# ]- m {7 g2 h4 R0 L28) Y; E! R# Y$ L& A: @$ c& Z
29
& F7 i; B H$ D/ q30! r% r7 y2 h! O' k" q7 J
31, Q' O9 j! b/ m7 z
32
, g4 X& Q8 D5 m. r33$ t4 M- J& k8 H
34
- E. l+ S/ i3 Y4 w; Z, |35
) W; c4 U* P7 c5 q8 V2 a* O36
0 |! [. ^0 A- H0 {: {" c# q37
; O" |% O/ a" q7 y. F% v8 X38
# w8 p* t. y. j# A" {$ f39
. D8 `8 n, i% q6 H1 i7 t40* F$ P, |& }# v" B, |2 V1 i" w
415 b7 C( b$ L. L6 U% x/ T9 Q
42
) g# u& a' b* q1 u. r) j43! h9 k- L, p7 g G/ q
44
: G5 a$ p' v4 e$ x; Q/ y! j45( n3 m* r: h- w" _
归并排序的特性总结:
+ g) R7 b9 j' x( L7 \
" }# p- r1 h0 p$ l! M归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。* b; I0 @# M- e# Q$ u/ @- Y- G
时间复杂度:O(N*logN)
6 O9 y; U1 I- i% v空间复杂度:O(N)) n( u+ w+ X2 _1 y5 r/ j0 G/ _
稳定性:稳定
" ~( b# j3 J+ p* g* m! [! J/ w! f, j4 N# F( r3 Y/ p2 W
————————————————, |( U( P! L8 i# E
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
' f) U' z( C. }/ h原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
, Q* V5 s1 ~6 a% w L6 u+ p
" L3 e- p& O, A8 n' L! }/ D) G% j6 z/ V/ r" m0 E
|
zan
|