- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 565163 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174772
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序: R6 W. o8 D( z& A, W
q* ^, C) p! ^* X4 q1 K9 E
前言: K. v4 D! K2 x$ m6 t" }& S
本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
& ]$ F* H( F1 z1 @ Q d5 z4 ? \ x" v- p
归并排序
; _4 @' |; x! {* W4 @基本思想
& V. r" \1 _. e& I0 y 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
' x& A& V. d: b( m$ I2 @8 K. E. D) q
! z7 q" P# B Z; E5 z& Z! J9 u
% l' }. x" }& d( j; k9 E1 X5 I- `
5 @) \& r: Z' W: ~1 S. \& r; H 合并的思想其实和有道题目的思想如出一辙:
$ h4 Y5 L9 s' g8 v' n% [& ]+ z+ o9 p( X9 B+ W4 d5 t& y/ H
3 Z4 Q4 Z" h* `# k9 m: p S C5 u6 L$ E) U/ J& W1 U- e( t& t3 G* C
我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
E8 @0 N3 u9 j5 r, M
% f! m8 F3 L0 L/ w/ A[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]: J- I; e- G5 f- \, k
8 K0 k. f8 |, C: W5 |
int* merge(int* nums1, int m, int* nums2, int n)
" j9 [, E) I" X" M W( N* L{
: I% a4 s" M$ q* e, X {( G int* arr = (int*)malloc((m + n));4 Z, T; G w5 ~- C
if(arr == NULL)
3 ^9 O- @- o6 Y: k$ H) P9 } {
1 a5 P3 {: T/ h0 G. B- J perror("malloc fail");
3 p2 ?/ b+ s% K- |: n8 t5 z) C return;
# N1 C, F7 w6 F% u1 A( _ }! f( t. x9 p O, y( k
" A! V9 g: v. Z f8 \9 Z
int p1 = 0; s# g9 `6 r( P9 r; N; g
int p2 = 0;
2 a& ?4 _+ f, h2 x( O. b9 S int cnt = 0;
2 @% k6 s! G# ^* u" v while(p1 < m && p2 < n)
8 |! x' e# O& R( P {/ g8 h' |$ O* V
if(nums1[p1] < nums2[p2])
6 h$ o, L, j% h3 T {
9 S/ a; o* v7 x7 y arr[cnt++] = nums1[p1++];
/ ], W* N& a i& M9 | }
/ b- E8 [4 b6 K, H# ~5 D( ] else. _3 P! u4 h! X3 f4 T1 N9 q! z
{
' t, E0 k8 { U3 f arr[cnt++] = nums2[p2++];
, V- j( H2 b* \ }
3 [- [9 ]/ _ w! {; Y/ ?; k% x, c }
! m7 w6 X3 X9 {* g+ l7 o$ B while(p1 < m)
@2 V, G9 M3 j0 v9 \5 | arr[cnt++] = nums1[p1++];( I6 }+ c4 X3 c+ n. }& k" P" d
& Q* e: ]1 }: X/ f% B
while(p2 < n)
6 Y i1 q2 ]# u1 E arr[cnt++] = nums2[p2++];
8 P& }: J" k c& B0 `
0 X+ B- a) B4 v return arr;! d: m, M3 t. ?# ~! u
}
: T( Z% D. }6 R: {
4 ]1 @) k) X+ \' e12 D1 o. F r F) j3 B
2' u( T8 N! u8 r/ j8 `
3& q/ S8 S4 A3 k- e& o
44 G6 m; P* K' A3 x o- k/ c) x
5% X) ~8 p' X; L+ e" h" _
6; J4 q; g9 c2 u: [+ }
7* ~. p: C8 f/ m
8
% U( d% f9 N0 N) ^9/ l( A1 L3 F5 \
10
7 i" J2 Y9 N7 M3 \( B0 }11
" a% f4 m }* J# P6 f127 V& d0 \6 r f
13
- i+ b# ~3 v/ r# j) p0 N/ e/ M$ f+ C14/ ^ n$ }: U/ P1 ]% V& {
152 T) B- ]% F5 F$ W+ G
16. x5 n$ `$ m* I4 R$ O) Q/ ^. f
17
5 \+ j3 B9 X4 o# Y# f/ G18
! o( b# q* V! y5 D197 ~, T, N0 g0 k2 F
20
3 [# k1 {: i" B/ F) t( t, j21* _9 I; K. z/ \' _& M" k
22
$ l* \1 d4 n+ p, [5 H$ V23
; G6 h4 O8 E$ k243 _+ G; X4 q6 m7 |( e0 {) e
25
' C# q+ Q5 Z5 @% u( L( |& Z26
+ @/ J7 A! X6 X( f% g! W/ ]27
; T( H8 G, J! l, h28( H: h& Y' b6 j5 B* I ~- F
290 [$ V4 a9 j# W2 A W8 Q0 Q1 A0 ]# t
30
- R) n8 C3 G% y31* P9 K2 I( R& P- X @( a' J3 a
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。4 s" r7 d- i" _4 R
1 _$ O3 { U5 W9 _) o8 v
递归实现7 l& ^. D! g! ]
通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
0 ]; i: p" ^( l5 X+ n( I) i. ]# n' {3 m- d$ d# G: D: w4 L$ R" M
- M+ v* B5 X: P- }
- Z8 I/ O8 w# v" |( ?; m
: T( b4 u2 n( L6 v1 T# ?: @& T% ]: I- J- ` Q$ H9 z) R
void _MergeSort(int* arr, int* tmp, int left, int right)
- R' A& }1 W- c: \3 {2 L{
. p4 T% c! X1 c; O assert(arr);
" r2 b0 t, A# e
7 G5 {' R ~/ P2 [) z if (left >= right)//递归结束条件不要漏了! [- |. |4 p3 p8 r& @) B4 ~) m
return;
# b: w5 @, X+ {$ w/ y9 x6 j0 @; r, n+ k' S7 b# ^
int mid = (right - left) / 2 + left; Y7 S# f% a( G; Q" j# @8 _
& T9 W5 s; g: M0 L, E& o/ c
//划分左右子区间[left, mid]和[mid + 1, right]+ Y: x: H( x2 Q0 b' F% W# {0 T$ n# Y
_MergeSort(arr, tmp, left, mid);
2 b6 e0 `: O+ u0 W; ]5 z; L7 a# _ _MergeSort(arr, tmp, mid + 1, right);; g- H! ]' ]: J1 B
& X- x( J$ s( z& d( w //归并8 Y! m- C; `. a
int begin1 = left, end1 = mid;
# m- y! O/ ]: C4 Q# ] int begin2 = mid + 1, end2 = right;2 C) \3 m. G+ q
int i = left;9 i, F* Y z3 [' B
while (begin1 <= end1 && begin2 <= end2)
9 b9 S8 T" D4 t" j$ _ {0 f% F5 x' s2 O6 A- J( _( _$ C H4 y
if (arr[begin1] < arr[begin2])
, a& c3 J+ Q: N+ |) C( C3 j7 |( n4 V tmp[i++] = arr[begin1++];
" G3 ]; y- `6 X2 n* K* A7 ] else
: N9 |+ H1 E s! Z" ?# Y tmp[i++] = arr[begin2++];& a# L3 |2 T5 a
}7 ?* y7 q8 s5 g1 `- Y% W
' O* S2 |! t8 `& F0 L/ k. ^7 h while (begin1 <= end1)
0 u) f- V& H# w( G/ d$ X) e tmp[i++] = arr[begin1++];# q! C4 m0 d% D; j; J8 S% S; F
while (begin2 <= end2)
& k3 {3 k- L% G& G. o ^2 p9 g tmp[i++] = arr[begin2++];
' F! n6 R; q& u
) P/ W! p# G2 t4 w2 m/ Y4 f$ R //拷贝回原数组——归并哪部分就拷贝哪部分回去
4 O% V) }6 ~& @$ W: {+ I //而不是拷贝整个数组回去& m; X7 Y; z+ g) O6 S" c
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));6 ]2 Z' Q3 G- H
}3 n$ e! F) h3 Z9 x' d' e& [2 Q5 F/ Z
$ K' x: H* ]+ N7 `/ B% Y
void MergeSort(int* arr, int left, int right) F+ `) p& b- @
{) s/ w" V( S) w% X7 L
assert(arr);
' x$ Q9 n p: m! O A' D6 T, o3 e' m- `; w) Z
int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
8 e1 S) [5 m Q9 \% Z6 z& h5 Q2 {4 p if (tmp == NULL)
f! ~+ J8 j% a l! ] p3 B {
, B6 y9 o! Z- s3 Q; w; C perror("malloc fail");; M, i9 f4 j; S0 q! v6 `! O
return;
8 D1 c! _5 P0 R: D% } }
% j- m2 F( w' x: I7 z$ ~; Z! v0 ^1 y
- O, v7 p' T: {" Z% E9 l) n _MergeSort(arr, tmp, left, right);" G+ b" l0 D, b; P
9 |( n/ j$ h' R H
free(tmp);
# a8 ^; K' P+ j8 [3 s) k tmp = NULL;
9 S4 y2 p: W6 I2 z# d' K7 P$ H0 X}$ @! b' W+ n% A& b5 \9 C3 o
3 z1 r4 I. g' b5 F1" H5 J5 s' w* a+ p/ z! e; H3 M8 N
2
: l9 p0 t. y) N) v# Q3
) Q% s* P+ W0 l4$ M5 B# w6 X, e. k
5
7 `6 y+ r' G& i# b3 m# ^/ t8 E6
' X" B3 g: j. `+ j0 t7
. ~' G: |# k9 j+ g4 S8
+ ?6 O+ y$ ?" V" z* i9 ?9+ X( J8 W2 I* R* p, A# W; i
104 i% n2 v4 ^; j' L2 ]" e) G \
11% N- m' R: `8 h! k5 e9 X$ k* i, c
12' {) K, e+ B6 \/ ^/ A% g) C% c6 g
139 y( Q0 I' O# r' _+ S
14
4 N8 y9 L; I2 m3 G! N+ a7 r: p' E15/ a; N' w( N, |3 |
168 p7 X2 h+ U5 K4 N4 V5 {. x
171 w, P$ q) }5 P: u' e
18- Z! D5 h% S$ q, {* s( d, D4 Y5 x
19
+ }3 k, Y" j8 t207 F( f. u5 I I) j" u$ H" ?( k
217 J! n. S% x; _6 n
22: |* q+ P* v3 W
23
6 ^; Y( J- i" s( D/ r247 A9 N1 y2 s9 F: w
25/ O \9 G4 O. _6 i' a. F9 ~# V1 Z
26) {1 j$ f) t" u
27
+ W# M0 E+ ^# w' Q/ Y( r; \( W6 Z28
$ Y; P( }" E# @7 l f1 L29
p4 Y5 ~- R" y; v" ?: l5 J! k30
" T. ^' r0 ^/ T" I1 A$ q31& W+ }( r/ K5 L3 z7 ~# m9 D6 _1 ?
32
) W& U% O6 Z$ K7 T. M; S9 H33/ _' F5 f9 K( m( D7 `$ k
34) i* x: K% R& F+ \" i" ~; h
353 P9 ]$ ?9 k% Z$ v% w) |. i4 W
36
2 i% [2 j) O) _ C! M! }, _37" {. Q. x6 P2 m9 ^& p5 P
388 q6 ~( Z4 y, }, V' u* j1 j s0 k$ V
39
( U8 J- N3 E, D40! \0 S7 r1 K+ t! H: U$ ]2 b: Y
414 N. Z# L" y# D* i
42
% v, Y+ ?% A% P5 V# a% m' E43
$ G1 p- ?* ~1 f" c$ @, O44
! H: d% _7 |& Y- @1 J45
9 N4 S4 f2 ^) B: Z/ x46' m3 W$ i* c1 L4 {6 {
47) Z' ]0 n7 y" v. h6 V$ |4 r
48
- W1 K& j' Y2 J" G+ R' x/ J49
& T8 S6 C+ Z1 b; u50
' t/ C( C5 w# N1 z1 q; `$ q& ]51
* S4 \0 G5 H4 Q4 P! H B1 w非递归实现) H* f+ L# J Z& T6 q" f
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
% O8 v3 r# E* b3 l+ V0 N" e* @ p8 ?. N4 b
+ R$ T4 @3 ]" s- t+ N
: `9 g# o' ~$ o& a Z- u! H+ c
不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
+ l) i8 t6 u( K/ z" ?# A% p( W8 A: G. }5 }2 V
还要注意区间的取值,每个区间就是一组,就有gap个元素。, `% f! z* }- L0 C* u U( L
+ h, ]; }& u! Y( s: Z7 u
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。# @7 I! a y( d( V9 G4 A- e, y
+ f: z' `5 i. z t4 @代码实现% L) s: b; p0 ~, G! c( K8 I& s9 H' Z
3 T" g- C1 B: M$ [
void MergeSortNonR(int* arr, int sz)
' Q7 [6 n- t, W{
# d/ g9 }( I3 i2 i+ Q4 \( U assert(arr);
0 ?$ `2 V E$ x5 g, I0 x6 I3 ?: o& q
9 z0 x, x) m2 N int* tmp = (int*)malloc(sz * sizeof(int));
& N }; [; k' {, P) x* x& Q if (tmp == NULL)
& U( {8 H, w$ |) z# n( } {( g w4 B6 i. d: g
perror("malloc fail");+ h8 q r6 ^) Y0 M5 C8 Q
return;
6 U1 v( e! q+ a }8 t4 @0 K, v; H. H
5 `1 \$ e1 [/ T& w# m; g* E int gap = 1;( U! [1 Q2 k% O. C6 q
while (gap < sz)
, B% u3 H# W$ Q {
; s0 @! P1 \3 m7 U0 ~; X for (int i = 0; i < sz; i += 2 * gap)
; X( Z. G( g, T, m, p# W3 f { l4 q8 q* R6 \
int begin1 = i, end1 = begin1 + gap - 1;
+ Y1 z5 b) p; j' O int begin2 = end1 + 1, end2 = begin2 + gap - 1;
) B7 Q: p- J; Y a3 b int j = begin1;
9 \4 C# z0 ], U+ e( n
( s# L, |' o$ i! R# b6 K) ? n7 J //归并
! c. R% S) n& |6 c2 y9 W- ] while (begin1 <= end1 && begin2 <= end2)
; ^. H8 C; D' b) j5 v% }; B) [9 @+ P {
: c" Q( ?! V! N+ c R# b3 o) L& M if (arr[begin1] < arr[begin2])4 j) a+ ~' M& I$ F# h
tmp[j++] = arr[begin1++];$ t- D) u% j' A" C# o
else s) C: \, f) [. A: d% `1 z
tmp[j++] = arr[begin2++];
; C) @0 A _* q- M8 t! z1 ~5 Q }
& n3 n* A5 }: ~, w8 l! ^6 q3 r3 ~5 J$ l8 ~- \' Y) _) V- e
while (begin1 <= end1)7 B* u- c G# v
tmp[j++] = arr[begin1++]; a8 t& r# G7 \) v
while (begin2 <= end2)
9 l) A* h B& h tmp[j++] = arr[begin2++];
0 E+ d0 N4 S0 g9 q( ]# h6 ^( [* V/ a4 E8 {- D/ [' _( \& w' {
//拷贝回原数组——归并哪部分就拷贝哪部分回去
0 p3 `0 Z8 T+ ^$ N! [6 s w9 O# J% V; i( t memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
2 }7 t) Z. @9 J; S4 y }
& E: c' a" a8 {6 ]0 N; g$ V8 @ gap *= 2;) i: A7 p$ W# L/ U8 m0 Z
}
$ W+ i" p5 ]3 X7 Y J! J. ~: N$ I2 p, C* T
}, L* B0 A, |0 T y; k
! A* m0 j z; r. Z7 R1
: D$ _/ P4 x$ ?: U* F4 R E28 n7 i; o1 e/ p, D- Z
3
, i- L! _0 j9 o T4 e( A8 f4
x4 z$ T. Q- ]1 d2 ^5
7 z' N7 U6 b( S4 n5 R/ W6
& y0 t7 }. I, r# u$ V" l74 b: h z& D+ U* G
8 i' {+ w. s+ u: P( U" F
9/ K4 A0 d' E# y/ n, l# k8 W: o
10+ H* r4 r7 a9 k+ f+ H! ?# n
11
, ]" A* \) n8 Z1 g. K+ S12
# H" m) |' a# c. ^- D, s13
1 X2 [6 T& Z- {/ j1 _) R1 x14! l3 x& C$ d2 V7 o: J
15
. S* k1 X d3 @9 H1 b168 d+ t: G; v$ v
17
/ M+ Y* W- l' }; X, P& h, B18
/ [: \% ^3 v7 D4 U( M19
5 @; Y+ a0 u! b" |: N20
+ Z/ H3 B+ Y% }) c9 C4 [! r& i" R$ I21
5 P/ } Y# o2 R. b# Y: v. h223 t0 g! b# }+ U$ o1 ?5 v+ a4 L& O
237 }# d; r* }$ J! _9 m- g
24
/ N5 F2 W3 F4 f) ^% f25
- P4 h+ I1 R0 \+ v. m26
/ e- Y0 x, p! j3 G27! E$ p" S. v4 |2 g/ i' J
287 {! |3 W4 b1 h& u& U, G
29. }' O( C+ F0 y& O1 W4 @( r
30; W, w2 H# ?5 a- K* }3 [) E" W
31( Z! g, G8 L' n
32
5 v2 ]; H7 m% w6 A, t33
; g: [6 {: j$ D9 i9 C- [# a34! Z. Z) s6 s+ E% ]8 Q
35* s; Y( v; |8 T8 ]# \) V; C6 B
36$ E' ?0 I0 _( c9 w& W
37
/ S% g' ^0 `% Z# C' A3 ]) C& R+ ]38) ~( g8 _( ?0 }4 I) T# z9 L+ y
39* S- c6 ]$ L, j# a g
40/ E# R) t; K' x1 C3 P
410 w4 s3 U6 _3 p% U* n4 b, v4 N
边界问题9 i; s1 P7 S$ B6 Y
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
7 \( \8 |/ s/ Z( D8 s( B6 U* f0 f# R0 E6 I% ]% |
举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:
+ Q8 A0 P: v9 q( u7 D7 C+ M, O
" D4 t2 U9 v& v6 |7 a1 `' M3 i! |' L1 e# |0 c8 z- i% ]& q
- T v8 a$ [. {' {6 i由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)% [) [5 h l, x3 o4 B
. ^" a( X, n, L2 S8 r8 Q
第一组越界(即end1越界)- j# m, a# Y6 R4 G% {
/ {7 Y) \* V; N, B0 }3 w应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
2 G! R1 {8 U4 o6 I4 T
- p; x3 I5 j: w& P& y7 T1 L第二组全部越界(即begin2和end2越界)1 n; G0 }3 f4 z
+ @8 Q% R7 l! n# Z6 R应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。
+ V# V. c* t( J& U5 n
0 M" r0 Y- I |; B4 }1 B& w, b第二组部分越界(即end2越界)
) k: X5 y; X- T5 b6 V c8 \; |0 E: X" \" @: |" _
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
- D$ N) l( \" f5 t& z9 y1 O9 g7 a6 m L2 o! W% T8 V0 \& d1 ?
其实第一种情况和第二种情况可以合并为一种情况,原因:8 b5 k4 H3 v2 k! ~
$ p7 [$ P6 @* i1 ?6 b; R* o end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。4 `1 C4 j! y0 n5 }
/ t! A' ]8 G8 E
拿两个数组试一下:$ N0 y* C! s% ^1 e% Z
4 K4 C- C& b! r& Z. _0 i# F) e* ^# F( s! b0 ]4 q' X
- I# K# @4 Y" ^% i1 \" X8 g' G( y# t4 R8 R8 b7 O T: u
! q# d* ?' q" m M8 H6 Y0 d3 Y# {
代码实现: s3 v, c, i" \: }
# x. R, O' W- r+ m% c2 X
void MergeSortNonR(int* arr, int sz)1 P1 y& d7 n+ p6 b# p" y' y
{
! Y$ A. J+ m" n6 @ assert(arr);
/ p. A- u" j( F+ Q- Q( I
$ a3 d: B+ E1 v- B3 U) V0 j0 Z int* tmp = (int*)malloc(sz * sizeof(int));# j" r* b7 F6 f
if (tmp == NULL)
7 y1 u o2 {$ a8 H; b! F8 u1 x {
* B, I0 q3 f& i7 _# s! k perror("malloc fail");
% J W+ q' e! b$ L# k u5 R return;
9 A" T: A5 g: c4 S- y! | }
1 `" B( i3 s4 k2 ]5 C0 I& k; B! q
8 x) ]) j$ y. f- X- l5 X int gap = 1;$ G) l: r" x: f
while (gap < sz)% P) q( h; V2 p) Q( m2 Q4 h9 N; Z
{$ l3 T; e. f2 W0 T
for (int i = 0; i < sz; i += 2 * gap) u( T7 k1 \1 v
{) A& B$ h: E; V
int begin1 = i, end1 = begin1 + gap - 1;7 e( D* X% _& e |9 k$ g0 R4 L
int begin2 = end1 + 1, end2 = begin2 + gap - 1;' V8 s4 H+ B2 P2 L% S
int j = begin1;' O- K! D4 t6 O* U! P( Q" N
//越界检测
0 D L8 l6 }) h6 F: Z8 G if (begin2 >= sz && end2 >= sz)
: H3 i' Z/ ?* @, T break;5 C" m+ K. M- K
if (end2 >= sz)
9 E/ v0 J' A. p6 T8 E6 L+ z$ } end2 = sz - 1;
" V( `6 I/ D9 d/ _) o0 }$ w //归并! j( q! g, a- M/ U/ ?
while (begin1 <= end1 && begin2 <= end2)# c# _$ x/ J* A
{
0 k: y' m u; p3 T& ~! z2 E if (arr[begin1] < arr[begin2])
- v- S- T* R; X1 x1 C7 }$ q tmp[j++] = arr[begin1++];
$ Q: V+ B. T* G# \. j else
6 @$ x. c& k. w% f" { tmp[j++] = arr[begin2++];; V! J5 y4 ?* n, D" E3 _0 x6 l2 e
}
5 |/ r8 _" O6 }1 P- j# e4 v) n1 L
d$ Y8 M* {# c2 F% r* r while (begin1 <= end1)
; I; d9 ?2 g8 a6 S5 C6 m, s tmp[j++] = arr[begin1++];8 T1 T/ J( s# d; d+ q
while (begin2 <= end2)
* o( H8 l% V. Q; ~3 @% B tmp[j++] = arr[begin2++];/ l+ L: W2 M. F4 P9 `. ?" n. L' b
3 Q1 V9 l" x1 O# }5 M/ n5 T
//拷贝回原数组——归并哪部分就拷贝哪部分回去8 N+ `) z# n/ x( {
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));9 ^& r; |3 X ~' m) j+ ?
}9 g+ e5 l$ v& q: y+ k
gap *= 2;5 y; a, s8 k8 `; E4 r5 p' F6 J1 I
}
' I- I4 T9 c9 [( g* [* D! g" \
4 H2 ?* K V' @# c; j! y}$ J1 z6 D# W, t, q$ u1 N9 G' A+ Y
& h( q( J/ [# a1
+ h% E' @& H7 Q8 M. C% N2* f3 }* M) r% U, Y' n
3
. v$ w& E/ M: k- W& v4# s y' h. K7 f& K# G, _
5
( n& l1 g8 f# R7 T& t1 y& v6& [9 t, A, w8 r# A
7
: x1 A8 I9 M3 J/ t8" W8 A$ ]( f; \4 W) e2 z
9
: N! F( S3 s: d3 ]106 e( g/ x4 }# ^# I9 _, @3 z
11
- ?8 U$ v1 X# _$ U/ W123 T- C% d# i; a
13: j& ~; q' H, T! Z7 C
148 ^, q; _* c4 U j( O
153 x) b3 P; E- `3 C
16
_) S8 s7 b, @# z171 Q. S3 Z0 }% G; w
18, `+ g' ?" U: U2 W# H
19
" n7 r) K/ b: w* m" n20* t0 p# h: R" l4 x6 y
210 r* R3 y# M0 l+ T( S: y! @* S
22
2 Z/ d9 V6 A$ ^1 X5 W& c9 k0 d3 Q6 }239 s. D9 ~) r, u, k$ R( A R
240 V2 [7 ^: y6 G+ V- j
257 ?4 D" b4 k: m% g
26
) j4 R# O0 n9 }4 V" T1 x27
' h `2 |+ s$ q1 ~4 d) p; n28
" j) u2 Y. ?: @+ E, W7 ?2 P29
/ S- P' d4 i0 a5 F; M30* x0 K: x: Y4 c8 U. R5 X7 O+ Y( ~2 l
31
6 M" A8 o! b. G32& [' R/ a. y# ]9 ~: F" C) H: _6 e
33
; f- {# [: T( J. A5 m. D34& k7 X6 d3 p9 _0 _+ k1 _- `+ f
35
5 h! K) C" R% F$ a( P36
' a: @! C! ~' B37& \: E: P/ Z- L: A
38+ l, h. H9 ]; d
39( @6 c3 L: M' @! e$ }- |2 X( k' W
40# S6 B& ~4 w+ ^3 R3 N0 {
41: {' D2 \6 q1 y& L
42
) p U+ \4 v% b+ J+ q& v43! z5 D* b; ]' n9 \
44. G1 n" n. E( j- y) |
45! ?4 d, G- ]6 ]6 h8 x+ d
归并排序的特性总结:
+ v, l; `# t* y; ]( b! X G# R' N f( D4 y8 O$ @6 X( ?) j
归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。( _( {' ^! ^+ ]$ Z3 Z
时间复杂度:O(N*logN)6 d. x: w2 `& p& ^, j( j2 x
空间复杂度:O(N)3 t$ [$ B @* l/ L- S+ ]: u
稳定性:稳定9 J9 _. } O* [8 y4 D" y* q i( z! e
5 [, F( t% M8 I0 r, c6 d————————————————) `$ A$ R* _9 s9 c% i
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
# x M3 d$ w$ o& k5 R原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
/ R% P: i/ h0 {' g, I. o0 k A
- j. n" v( Q1 F0 }
; i# ^1 Y: ?: O% w5 f9 v3 G& V |
zan
|