- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 565772 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174954
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序3 k* p( D0 ^ M
, I g9 D- g0 T9 k
前言
" \5 ~" i7 q h: u- O本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。
! X: F" }8 F0 L+ B: N3 D
. g1 l, U# L6 T6 H归并排序9 L9 J$ w- K! ~1 n* j% h ?
基本思想$ q8 C. i1 |! i; q
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
) d, \; G* K1 d" G: X* |% \
$ l8 Y, v1 [; w
$ P- S& h q6 W
: o% V/ o: p1 u$ T/ x# E 合并的思想其实和有道题目的思想如出一辙:
& Y0 u. j+ m* m" v
3 a4 P" p9 o/ g5 S" u( t
9 I( g" C5 a2 a3 R9 G) y. y/ F: Q
# t& h4 {+ D& @; a; g5 e0 _% O 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
0 s3 P) |0 ] w7 H/ H9 S$ w# i& `2 S9 n; ^
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
( a, K' p9 ~# w: C( }+ q* J4 \* x, w/ P
int* merge(int* nums1, int m, int* nums2, int n)
7 N8 d. c& j. b# w6 f4 `- }{5 Y% f3 K! P' W
int* arr = (int*)malloc((m + n));$ R" i' h' x3 b( u/ q' A+ i1 c
if(arr == NULL)7 H5 ~9 s/ M; d. I5 {) _
{$ g# N2 \4 R# d( I
perror("malloc fail");
( b/ `9 B( o; B6 @8 t9 r return;
7 n/ A: o. L' V5 p' ` }
# _* |! x, L) j; ~; b
; s4 ?; b) c) F, | int p1 = 0;. ?$ t! z( w" E: K% l
int p2 = 0;6 z9 e! E, ^" y, w X/ P
int cnt = 0;
: D. i$ u# @0 W( g5 ~ while(p1 < m && p2 < n)
+ S9 x+ k% E; I/ M7 P1 U% T {9 Z* w/ f% g5 G/ y
if(nums1[p1] < nums2[p2])# ]2 {# n$ O7 V7 x# d; n
{9 d. c! a2 W [2 G8 l) e
arr[cnt++] = nums1[p1++];! Y4 ?/ ]; U5 H3 g, F
}
. @( Q3 K6 g5 n5 J1 M: \, [ else
/ G- f9 X# e, |! {8 J* a {
# j$ V) \: p) O/ } arr[cnt++] = nums2[p2++];% S5 e% _ J4 F) k+ o
}, p+ |' e. ]: G6 {) ]
}
0 M' |8 H7 D+ R7 U: | while(p1 < m)
# H$ H* j0 T2 X! L* P# C arr[cnt++] = nums1[p1++];
: ^, ^2 c2 g& R5 X5 ]1 M4 Q5 Q
3 ^7 u& H* p: ?4 e while(p2 < n)& N% W, Y9 r B+ P0 O" f
arr[cnt++] = nums2[p2++];2 B- c: ^" u: J: ]
3 |0 X: T& a& X4 U9 \# O; G
return arr;
7 H2 k# Q( A9 A0 J}
" p& V# @* t: Q/ l1 Z8 I6 e" G# J0 Y7 \- Q4 I: W }
1$ X' k! W& `7 {- t0 a0 Y4 i
2. o* m( y5 D3 B* D$ E
3 m& b* ?% D& D* X y* l
4+ t" l2 E" y8 v! a$ ?9 k
5, w" W1 k! |" q
6
. _0 v9 Y5 Q6 T( Q1 H) l" R! p" G- T7% v+ ^! w" P3 J% h6 ]- b4 s7 y
8
! o# `& C9 G# x. C" ?! ]9 z9
( H* @) ?* y1 l. m# ?& T6 P" u' X10
; G& h9 S7 W6 w7 m1 D& j4 B11
( f2 J% o3 x$ _ F12
% O* e& d& m5 }5 M* ^5 L13
) N1 i0 O, i9 {( o7 f' e0 m14
# l8 ^2 H# H. ^0 ^15: l5 l: l. z3 s. g x# u
16( v( T5 v2 a( ~ y$ }
17
8 Q% `6 S3 S- c1 @" N6 [189 o& O6 _% g0 a0 `% K
19
# U' k- X+ k, f& s8 H20
# b, a' v* x1 }) v7 b; B2 r4 t0 p1 J210 T2 i6 j- i7 s
22
9 t/ J9 p( x; H: F: ]8 m: l- l7 k23
! I! p7 A ~2 I3 y; I" I; |24
& L( O' ^, _: ]5 b4 q25
" W6 V4 M8 ` A, `- G; Y262 r4 S! h% E: W+ S4 b. H% n2 A
274 ]. @2 a3 q: B7 C* a! K s9 r
28' [' M" A7 g, c# h2 S
29
( y- u# a- ]+ ^0 ~30. {% g5 N( o+ B6 Q* F; n
31
6 B# j# a* I ~, f: c 所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。
* O7 [1 S( Q" j7 i- M2 q1 w2 u6 ~, x; K
递归实现
! x" g; [; w) I t 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
7 E8 @; z5 f$ \' {
& Q9 P2 G1 r* U h8 q6 T
; ^8 Q- V; k1 h
0 t& _7 v% q& G) W
5 a+ _$ f u7 P. k" }+ Z, }9 V. }/ \# I0 j( ~( f, H
void _MergeSort(int* arr, int* tmp, int left, int right), Z" x6 F$ X- S5 H, R G3 {) L7 }& q
{
9 }( j o0 }4 ^) D assert(arr);
4 j, n( {8 i$ w. \9 U1 w& a7 `) b+ f, O3 i) K# Q
if (left >= right)//递归结束条件不要漏了& c+ W* a1 D& s4 K) B9 f T
return;7 \; H0 P/ x8 A3 N: Q- g
& {5 \) W* |5 j* G
int mid = (right - left) / 2 + left;
6 e% r" z1 [% U+ c( a1 {0 N, S5 p
" G9 b4 D9 V c4 ]" r% Y( N& D7 [4 L4 R //划分左右子区间[left, mid]和[mid + 1, right]9 X# J* b: N* P5 F& i# K
_MergeSort(arr, tmp, left, mid);$ v3 M1 o* n" r5 \& T
_MergeSort(arr, tmp, mid + 1, right);! Y5 J7 B- d( t6 Y6 n d9 ~3 S5 b
' U. i6 y9 T q( a
//归并& [* r8 N {/ N/ z
int begin1 = left, end1 = mid;
; P( u' Z+ E* T$ ^ int begin2 = mid + 1, end2 = right;) D% c# J1 N7 E- J) `
int i = left;4 }8 C+ @" F2 L3 k0 l
while (begin1 <= end1 && begin2 <= end2)# h d6 m( |6 L7 e( _% B" O
{
/ j! `- T8 J3 |/ f z$ V if (arr[begin1] < arr[begin2])+ V! N6 G# D! j i
tmp[i++] = arr[begin1++];
) g2 o4 D/ ^- u1 F else
$ `1 s6 p6 d% h( T4 T tmp[i++] = arr[begin2++];
; w) {6 y# s4 w& W6 p" { }9 f0 m# Z" l# r( V
, q1 D4 N6 g* W# a. ^
while (begin1 <= end1)
% N: ^$ B" d3 ]1 ^9 C! E tmp[i++] = arr[begin1++];7 N! h+ d$ j$ U! ?/ `
while (begin2 <= end2)$ S- f7 C; a* z; E
tmp[i++] = arr[begin2++];
& `5 a4 j6 S d. s% ?( X- |
7 y# x6 B) x' {$ u v0 ^ //拷贝回原数组——归并哪部分就拷贝哪部分回去3 y. @$ f& O% z2 U5 Z
//而不是拷贝整个数组回去; x1 [/ y( s, \2 n5 m
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
- h4 Q. z# y0 s}
! y" K- ^2 Q5 r {
$ E7 r3 ?; w5 Avoid MergeSort(int* arr, int left, int right)+ \% `5 j; K! b. z! A9 I
{2 L2 ? U3 z. T9 \0 p' X. |
assert(arr);7 r( U9 R& H& }$ S* t- U# _
% J/ }; C& ]0 X. p! [: [ int* tmp = (int*)malloc((right - left + 1) * sizeof(int));
' Y! C5 u8 @: U. W: o, j5 k if (tmp == NULL)
# ]! s# w B1 { {9 F* h2 S/ i E
perror("malloc fail");: i3 C; Z5 k) J; [
return;% I( l; |& m' L
}' q1 y& F; @3 m1 j
( z8 l% i9 n# j- B$ v5 ^ _MergeSort(arr, tmp, left, right);$ \! }" [$ F+ }, p% ^
5 B# n( \4 Z% m1 f
free(tmp);8 Q3 ?) B$ _# L% l1 A# E
tmp = NULL;
0 e, q& m! m+ }, m7 b# I}
! b/ k f1 {% G2 q: S( `# M/ p/ V
B$ c9 `# ?8 U7 S8 a7 @$ j" S1
' b2 a( s& V* D' x }2
" q. S; P9 e! o! {3
6 }+ x6 \* P5 J$ Z8 y0 ]* i( Y! ^6 M5 C4
* W. o' C- r ?# i {5
3 o9 \. L/ C( h2 Q60 A3 B: ^9 [ G% [* V& ^
7
7 k' F* w7 p" y; X y8
5 \5 a6 M# X0 B: i R; F6 a9
# s! n4 Z7 a7 R' O- V! s6 g10" ?( Q$ h/ f' R( E
11
5 R3 ~7 G1 J( n: }. \12
+ t3 t6 Z: C; `- S1 p/ V13
% G$ T5 |; E1 G8 Z: D0 _# H5 q14
+ r( z3 I! f. m @15( ?/ |* @0 Y6 t+ p, f
16( J, D3 c, R# T$ x5 U
17
# U9 u6 @, i5 {" P) O: G# {184 n; a, _ g0 S! {! ?2 g
19
p& L$ S6 r- \! H: v20$ b+ a- o; {6 K" U; a& x
213 m& t1 _% P( p/ r- F' B2 C
220 U& I( D) x: s' p
23
7 z3 ^ ]; |$ @: o6 l M& Z24
( G; R. e. t& i6 x8 R25+ d) H! Q2 T7 B" [/ F9 X
26" M1 l" y; y. T" ?. b& `$ s
27; q( t" g2 y3 m: |! i+ v
28
" W. n+ X9 X( H `9 p293 f0 J f& j9 @, G0 C
30
3 E& c9 }& _& J5 Z5 k" f; ?6 I31
5 F. Q4 O. u" I' {323 Y1 b4 E S" T2 e W+ J0 C8 @
33
4 M/ l0 v/ u! [. b; |8 d" x H2 y342 |1 f. m& l+ _/ F. b
35
# G$ g( L9 ~: ~+ z" Q, n36
S9 L+ X, g+ R2 \, I) D37 g6 {1 E9 t, @ k8 |0 L( b ^
38* h4 V4 {% T- {% J4 R# ~
39: u. J% j# w, K( v1 G
40
2 A4 ?! p; n1 g0 \! N41- O; r2 T. c- p# O2 b2 _5 Y( a, o9 g
421 \/ d8 t, q7 A) B7 h( U
43
5 S" g2 F- K+ x7 X' o: ?8 A44
# v: ~# F% p5 X0 O; P" |% v452 ~* E# L, p Y5 E9 ?
468 P6 h$ ?3 U+ d* ~
47 ?: a3 n) E/ y" O# b5 T* n" b! c
48* g3 V) b! t! x; t) L- Z
49
6 @$ c# F \( r% _509 ?' t! l0 m z7 z8 h
51$ \; h3 c2 R9 a
非递归实现 b( K9 V- g3 x* d5 g* h
直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。
% P0 g. }5 E; f g4 p. ?+ Q
# _. R# y" A' W$ o9 ?9 A6 ^. y: |1 Z0 Q- I$ o
3 G! H3 V( S9 A: Y( ]" x 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。0 A4 @1 {. l7 O+ a) q
% _- T- l9 ?) i* U: G9 X
还要注意区间的取值,每个区间就是一组,就有gap个元素。4 _ b. s1 ^+ ~4 c; k
$ z; |/ N) E! o* R 整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。3 R; A3 U- d6 \) Q: B
9 G! j* L( t, ~& R. T& q代码实现
% y2 L7 h# i* \0 C C' y5 N5 H
( x4 K! j" k+ N% D2 o% n! Z: Gvoid MergeSortNonR(int* arr, int sz)
! y( p2 Z( T h{9 ]" }$ ?6 y+ m V( n3 Q5 l3 g: E
assert(arr);
2 h2 |4 L- S6 [3 K5 t ?2 \* ?' j
int* tmp = (int*)malloc(sz * sizeof(int));
, r2 A" Z. L A4 o1 J2 P+ U+ c if (tmp == NULL): o1 p: U& ]( h3 [4 L) ^
{9 Q/ p( m3 e7 `8 M, B4 p F
perror("malloc fail");- p: p! ~0 |1 e3 L
return;
; g" l1 e" O" ^0 I( g7 l" [. u8 x }) l* z* t; D3 b5 R
4 [4 t7 Y& m4 c int gap = 1;
8 f7 B/ l# v# r' f: m c" i while (gap < sz)) k8 J# Q, O. Y: E4 p/ p
{
" [( P7 d% d* o# ?* M for (int i = 0; i < sz; i += 2 * gap)
) U. ?, e$ M3 h: h1 O$ V+ r {( Z4 E' n, N* ^+ R$ {
int begin1 = i, end1 = begin1 + gap - 1;
/ Z4 N0 d3 H# C! j/ r8 R7 v# L int begin2 = end1 + 1, end2 = begin2 + gap - 1;* f4 M+ R6 f" Y, g
int j = begin1;
: o5 _1 l! n4 A2 i% I3 K
; Q/ ?5 I$ [9 X$ d3 _6 \) e //归并
. R) R# w- S5 A* T" T( S V while (begin1 <= end1 && begin2 <= end2)0 L' P5 h9 x* h3 f% l% i" j
{
9 z7 O3 f' D* j# j if (arr[begin1] < arr[begin2])
5 p) ~, I0 S! U- c* { tmp[j++] = arr[begin1++];
1 z5 A0 z8 r% q: A) @+ p+ R else
1 W1 q4 d+ a/ f) G tmp[j++] = arr[begin2++];" H- L: m7 b- J2 U4 j; Z
}
( _" m4 g& T7 k# i# x6 z) l8 |$ W8 d
while (begin1 <= end1)
. F8 p7 E( I, e tmp[j++] = arr[begin1++];
, h* d- }7 x; _. F2 ?2 m while (begin2 <= end2)
5 o. C8 e* L2 V g. }0 v tmp[j++] = arr[begin2++];- ^0 C+ ?: h- q& f. U4 A1 h
: \9 E9 h! M6 t# J$ J+ B1 G
//拷贝回原数组——归并哪部分就拷贝哪部分回去/ [5 b: q! m4 W8 K2 o# g# _
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
, J6 @5 s& w X }
/ K7 V( I, j/ d gap *= 2;
% w; ?% Q0 y! \* s }8 o! d- C; C, L
6 n' i3 e! T8 H}% N2 n+ L5 d% X& s
3 J6 X: e6 c& f' t6 p% v
1+ n3 x1 k A9 J
2
: j4 ?7 l) U/ p' ^' I6 u. I3
: K: T6 H ^7 S! Y& P' Y4
6 W, k. W9 d/ z3 S# S5! c7 A$ Q+ o# q$ z$ `8 H
6. r" A/ R- d: q4 e. F8 X
7
, l" o0 s% I% B5 q8& e; [. U) ?2 ?* |! [" C
9
: O+ b- R! x* g3 D$ w10
2 @2 D7 C5 i. P11
( a; K5 e+ t1 j9 w% {12! `3 V' C$ A7 g6 l5 [0 R# s
13* G. W! a/ ^# h- e( ?
142 h' A0 ?1 I$ x& q. b; V6 @5 @; `
15
1 P7 b9 \# k* l2 T4 V16
6 @- ?! @$ T% ?+ y; I; h0 U3 M17
. {( r2 {: l& s" l18
1 m3 _# {; j, D' A- }/ ]8 Y( n; K19
) H. {! K- ?4 i20( j# j% m- D l0 x8 j) N1 G7 T, B
21
; Y9 D" K$ i* a" n$ U# o2 {) h9 C. A22! g) F ~4 O, u2 O
23
7 d" f4 M! H& T2 O. x+ a249 K9 m* z% H, @* P3 r
25: e- w( D3 l6 w
262 ~6 ^/ e7 ~: u5 V" S! I9 v
27
2 H8 P- \& _0 v7 e. c/ ^28
* c( h4 E0 o- n L! V9 x5 G" S29
# p0 n4 d1 T' r# {0 U. q30
, z, Y+ c* J2 c* [# D6 X( [, o p314 `& z" s6 W E/ k& c/ y! F; {
32
, }) V) g) N! Q/ q33. b' y: w' w. |+ V% R; b& k! z
341 [4 S" { l" e# F1 _( O7 \
35
0 F! r E' {' q$ _369 Q! p7 _& \7 n8 V7 Z" q
37- S3 @9 f2 Z: ~* M, Y8 }4 T
380 r' P, j4 I1 ], e, t5 z" o
39
8 Y3 X2 f( ~9 g2 b8 v- j( A40, s3 {4 l: L4 E& z0 _1 p0 V
41+ I/ |4 I2 X& M, a: y
边界问题/ I6 w0 M& ?9 v. I' G& D7 N
实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。
5 e4 b6 | `0 |$ c$ `4 }/ C/ F I
+ P* v1 w1 A# b5 ^" n4 \: V% V! v举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:! O& g- l, I4 N- P) D* P1 F7 ]
6 q: Y _: q; X- u* m q; Z! s8 H o8 Y, U3 k+ D
+ q5 M& L& u2 Y3 H) K* ?9 b% v: k由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)( @. l4 Z+ C, h* }( ?. y
9 X9 h% z) F& ~第一组越界(即end1越界)
# X) c' T8 r; z! y% [, H, L6 U8 u+ ~! w3 c
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。5 o! u5 c# q6 l; U% R+ u5 q) z7 D
6 Q% g% P& l9 r0 O' f
第二组全部越界(即begin2和end2越界)
' v/ t, T! g) l: ~% s3 w- Y- |3 X5 q5 X" K% ?! u+ m
应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。$ G2 o& ?; [, C& K& Z
4 s2 Y7 N! X. z9 Y, {
第二组部分越界(即end2越界)* v" Y! D; h, A7 s, h/ H, f; w8 }, F
2 Y" @! i0 A- [3 Z3 r; j0 \应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。
* G) w2 w& k' o1 C: n: `& Z
4 a- d( f. ]" _, D! L 其实第一种情况和第二种情况可以合并为一种情况,原因:
7 ^0 u9 Y1 U& A, b# U2 P- Q. [' |# U f: s$ N* G# K8 p u
end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。' f1 H% A0 p$ {- a2 V3 \! G
% @, k& J& x' [ A4 P) ? 拿两个数组试一下:
3 @4 s& i' c) [8 q) }0 M# n/ X- c
2 J$ v% `3 z7 I9 S- L3 x
6 b; A6 I; J) V4 L/ F
2 B, t, w6 p- D2 F
1 m9 j9 ]* m+ V5 A% n4 v, ?8 a7 u7 \& p
代码实现+ s& {2 V0 ~7 e1 ^2 l$ D1 `
5 }& T w. a) l5 f P6 Y, ?4 Yvoid MergeSortNonR(int* arr, int sz)
0 W3 ^/ d% q/ t{$ k! x1 c- y( a* n% z7 l1 x
assert(arr);1 f9 z/ J/ r0 O( D
5 R8 J9 E/ {8 s int* tmp = (int*)malloc(sz * sizeof(int));5 p3 i# U/ G$ H+ j/ q+ i& y$ @) I
if (tmp == NULL)
! @; {& ?) o* ~ {( ~1 G8 }9 c' `5 J2 e
perror("malloc fail");' z; x3 A, p$ {6 j& @/ J
return;( b- `9 t' t; O, J; r" {& f& T
}
4 z# d( I4 K% _ {
. f7 H% w! l/ M4 |( a: ` T6 @1 v) W int gap = 1;/ |) s7 J. }; c2 w7 ~& e2 @1 I4 V
while (gap < sz)
- z& I; ?8 c$ F2 G* K {3 c# i% Z- P' j0 l
for (int i = 0; i < sz; i += 2 * gap)7 o/ M$ d& H) @
{8 h0 y8 F$ P- j; d/ B! M' _
int begin1 = i, end1 = begin1 + gap - 1;, I3 D; j& a! L) S1 ]0 T! A
int begin2 = end1 + 1, end2 = begin2 + gap - 1;( W3 e: w0 h6 P+ K4 ]
int j = begin1;
$ u- C# C9 w. K; `" b //越界检测
& |- _" Q, M$ Y2 d if (begin2 >= sz && end2 >= sz)$ {5 o& a% T; }; h A+ e+ a# H8 x
break;8 D! l3 m4 A0 }+ ^: }- I2 ]
if (end2 >= sz)
) t1 B/ v3 q8 E: Y$ x, _. k( x2 b end2 = sz - 1;' `0 A. c3 k/ ?3 H
//归并5 J" n9 P) |: @# c. n3 D; O$ X' C
while (begin1 <= end1 && begin2 <= end2)
7 ]" ]: [9 ^8 n- U+ W {, i& k# r* i) `7 ?
if (arr[begin1] < arr[begin2])
9 i, M" C% [* X: s' u! r tmp[j++] = arr[begin1++];0 E7 ~2 n8 {) W* M
else
4 ^5 N. j0 n4 z, P3 d tmp[j++] = arr[begin2++];7 ^* r7 Z4 l6 I8 |+ z- M
}
1 z( r; w v5 G4 H+ f! ^: l: W, `4 z+ T$ [+ V' ^" ?( {
while (begin1 <= end1)
/ n3 p, {. T# p tmp[j++] = arr[begin1++];
8 `4 i$ c5 S9 g. V) X' u1 b while (begin2 <= end2)
7 w& o& G! n5 ] tmp[j++] = arr[begin2++];- t: @: m" E7 v" I
( F4 s+ v# L" W //拷贝回原数组——归并哪部分就拷贝哪部分回去, o: D i* d6 B) B
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
3 n9 |8 m" b, a: { }9 \) `- b: J0 E+ ]; X: }
gap *= 2;8 c6 z* f0 G0 L
}
0 d' i3 l. ^7 ~0 Z5 Q+ N3 T1 C
) E* h( h" C1 L* h) N/ J}& m" ? {1 G8 r, J5 q) S
1 C+ |" t1 i& e- ?
1
- w( H& L7 n5 c5 }% _: s2 ^. }" h8 K( v' c& q
34 `% G* |/ x1 N
4
4 v( o% Y6 M% F. A3 |5
/ g3 p2 b R7 f$ `" G6
7 z. l% m, t# a4 K4 ?2 E7
; @5 Y: G# C& e$ {& g8
" M, g( }& m7 ~1 k5 O6 c9; @$ C M0 m5 |: w+ ?$ d& e
10
+ d" u/ `% K3 A3 x- A( ]' [! r11
( o* E0 a" [# E12
$ P/ q; I) p; l6 Y) i13* [" p( b% A7 `& @
14
1 u- |, D) N) {; l U15
9 K5 S U. {, N. [! Y. a16
. g$ ^) q! D$ @* N0 M$ R177 ~ Z. v/ x7 q [& @/ y
187 S/ c( ^9 O' M4 r( f5 w
19
& y% i; ]7 f1 X* b! D6 V, v20
# m4 m: j _! l' S" S21
" x" `; ?4 o; R/ @1 w, J221 d) O: p1 s. _3 E7 J6 K
23# D) } q1 b" d
248 J+ w. _ L7 x; X
253 j, u: ?+ |% f% n* J" c
26 @9 l* G: g+ R/ ~# }8 S u
27
: Q2 P* C1 N9 Z C4 `6 g; ~9 l28/ Y- W' @; C9 P7 N
29$ @5 ]1 t( @8 V5 q: j
302 _; w: {% H2 {. _2 ?. q
31" o9 Y$ u, j, r d8 c8 q' w0 @6 k
32
3 B! [5 _; r% ?5 X& s4 O33: W$ f. p9 K# H0 D
34+ `) o3 L+ R7 i2 p
35
u" R) u& G. l0 S" y36
8 V6 |0 z3 ?+ z$ f( u% m* [ d37
. w2 d8 l) `! w: j k+ G# k2 ]5 R38
2 F& D0 S8 h* _39
" {2 |& S! b( ], j407 D* F( d0 k! b
41
! C6 @; T5 i7 i7 \+ Q5 H8 F42: _$ g5 |+ r* p% Y3 ?0 A- w0 b7 I$ {
43
@& n: d! T" Y0 z2 Q44; Y! Q& A- p4 @# d3 q U
45) r x4 q0 `% d g- u0 p8 K
归并排序的特性总结:
1 g5 @& G" |1 r/ m
8 }/ E6 f8 S% |& O$ o1 h5 k归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
8 @3 y8 ]9 m0 P8 [时间复杂度:O(N*logN)
. C" Z0 I# v/ |" ^7 F/ @1 M空间复杂度:O(N)
8 d0 |$ g' J8 z7 Q n6 T稳定性:稳定
+ \ [- P5 C t0 B; E: G7 x4 \* L; x3 r _
————————————————; P' t* g6 _- c' L) Y
版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
$ g7 f* |) s; B ~0 k6 c) y原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657
# {" G9 |- L" L+ y1 D8 p" { K- @; |! A X+ O% ?) v
# S* {# I0 n4 f |
zan
|