- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 81
- 收听数
- 1
- 能力
- 120 分
- 体力
- 554084 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 171598
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 18
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
【基于C的排序算法】归并排序
. j* ^& Y, n+ H! W1 b3 v* @7 z* y# i F; C/ J0 p
前言
. J- _0 W1 d! j5 r9 K* m- ]本文基于C语言来分享一波笔者对于排序算法的归并排序的学习心得与经验,由于水平有限,纰漏难免,欢迎指正交流。! n2 m, F: ]( o) D- `( u& I6 T P& P
8 ^9 h9 m8 ~- N! H/ l; R
归并排序5 ]4 V5 h: [& A5 o
基本思想5 x% ?$ |; i9 v& o; b
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
: ~: X# S. f2 h1 B) z+ q h: M$ _. u
]3 U6 X$ S2 q6 Y9 k9 K0 k
N B& `% N! u7 m: x 合并的思想其实和有道题目的思想如出一辙:) A' @. J a, r! f; w
8 W" O( t3 e* A! u& |9 i* @* h/ `) |. I
( P+ Y6 s k# i5 [6 g 我们考虑新开一个数组来放入排序好的值,要不改变顺序的话就要用尾插,让nums1和nums2数组元素的较小值尾插到新数组中,两个数组总会有一个先插完,另一个数组就把剩下的全部尾插接在新数组后面。
5 j: {0 R- N2 ^: V2 @
2 q I2 E# W; J: T- X[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gsgj7Cmx-1662793985599)(https://typora-picture-1313051246.cos.ap-beijing.myqcloud.com/归并原理.gif)]
8 G( T! O- @1 o$ O. T8 Y7 W8 F0 s$ c+ N+ B3 K' v+ c! S+ {
int* merge(int* nums1, int m, int* nums2, int n)! S; w* j; p0 i& ?9 G
{3 v; p8 t8 v: F& D1 D
int* arr = (int*)malloc((m + n));/ d3 c' i$ h! q7 I3 S! T
if(arr == NULL)
# S6 a& u, V- q" u$ [! W {
4 Q0 X. D4 _0 Q3 g6 S3 n, P perror("malloc fail");
2 t' n: i+ D7 I1 _ return;
8 e4 T+ E' R$ r, }$ ?& \5 y }
" w4 Z" g* P$ D( o
0 c6 e! L4 q, i. F7 C6 X: B. Q1 ?8 ` int p1 = 0;
, x: H% C3 T2 ~8 r2 | int p2 = 0;
( k4 ?; {; ?& E- M' w5 d int cnt = 0;
! R; r. u) W; b" u4 Q! i while(p1 < m && p2 < n)/ \1 p( R, ]) ~/ O" M
{. F( R( H2 P' p% k; K( `
if(nums1[p1] < nums2[p2])
4 b0 E1 r) w J' i# t {
, L9 ~$ H8 |2 c& E# n( W6 v. q arr[cnt++] = nums1[p1++];* g' H, |- P. B+ `* Q& z
}
! W8 S+ z7 U; m" z7 C7 N else [2 L6 z1 }7 N9 Z, ]4 Y
{2 n+ \* |6 V+ ^
arr[cnt++] = nums2[p2++];' v) B( x- w6 k) N
}. \; p, |8 L8 H
}
2 S+ ?' A% ^; V$ G while(p1 < m)
2 [& v! f/ j; K& f" k; u$ F1 `: S arr[cnt++] = nums1[p1++];4 l, Q5 _% F7 n& V) E4 k- [, p
1 R7 ?( e! l# P" y8 Y* k5 x1 |1 D while(p2 < n)
1 R6 o0 [& k0 u k- Y arr[cnt++] = nums2[p2++];
6 s P/ u5 `) x' _( v0 a* o$ a' C; \4 G
return arr;: I' r+ y8 J% G! r, Q
}3 j; T- X% n& B" {
+ }$ l* P7 L! R* L2 X% L6 x: q' F
1
3 f4 i; k6 ?/ b2
3 ^4 q1 {8 e. C3" I T2 K$ m) P, s5 e9 }1 d" s3 }
4- w2 ]6 b4 Y$ f' _6 N! b, k h8 q
5
0 K# z4 ^% H. B* B# x8 m& y6- D3 S+ H8 A# v6 ?
71 H0 u, M3 u, ^
8, P( s" z* O! r0 }: K5 e9 j, e
96 q) a2 E1 d. p' g) ^6 C2 z. A7 w
103 s; A4 E" {1 |' I" }( H# L
11- T- x# K8 Q9 ^
12
' D* c' f5 u4 y* R131 H7 H; s$ H1 U; i+ t* Y/ ?
14
% p) Y. k' _, l15
+ e8 h) E0 M+ w3 s2 Y; i* u1 K& ?" Z- u+ i16
6 R e* s9 K7 _4 T0 ^6 p17
) [4 \) L5 f- V7 ^9 w( o18
! e9 ?2 n7 g0 J% K$ ]- U E19
5 X* @# _+ V3 a20
' p) r; J8 ~6 `3 d1 R- e1 k4 b# Y21$ C5 B$ |/ ?3 D% y& b3 @" u; M
22
% W/ ^2 t1 u5 \ f- ]- h: O$ c8 Y23. C6 [; @/ f( U5 Z1 M: N
24; N( U( p# S+ e( q) Q1 A, J
251 t% N: {3 {2 T+ T: F5 S2 m& }
261 u* M/ X0 r t- x
27
( T* V+ N, ]0 K" t; }8 K1 f28
+ `& n. {$ f9 D, ~1 N. R29
( u/ I* H2 ?& ^5 ?$ M30
1 h9 O/ r, L6 M: y31; Y; `8 S2 K; I6 Z, w( m3 g& U& S
所谓的合并就是利用这样尾插的思路,我们就想到要把原数组分解成两个有序子序列来合并,那么如何将原数组分解成有序子序列呢?容易想到用递归,其实非递归(迭代)也能实现,我们接下来具体来看看实现方法。) C- }; w8 k1 ?. `: a
4 j; t( T Y- A
递归实现
* f6 a3 v( @9 Z8 `; s$ J. I 通过二分分割出两个子序列,然后进行递归,先左后右,不断分割直到子序列仅有一个元素时子序列一定有序,这时候就可以往回退了,等到左右子序列都退回后就可以归并了,不过不能直接归并到原数组,因为会覆盖而丢失值,不妨归并到另一个辅助数组,归并后再拷贝回原数组,思想就是前面讲的合并的思想。
1 x* H( x# U/ V1 f5 M! a! H' [( I3 Y' @) t' R# U
7 j/ R) `7 u j* ~/ y3 U6 Z* B( e) j
% l, I3 A0 j, f$ O' x9 P' J3 a3 g$ |5 b2 A6 O
8 Z8 E9 H6 r' ^
void _MergeSort(int* arr, int* tmp, int left, int right)8 N5 `& Q# ^7 Z! @8 y. ~
{
" R7 c! v/ A3 M2 w assert(arr);: ?( F# x0 s/ ~ g$ H1 t
/ ^; k$ f+ _: z3 c! g, i u if (left >= right)//递归结束条件不要漏了
( b, q, K2 O/ s. V2 D return;5 f3 l( i+ W9 Q, _5 S/ o) X
6 x- H, B8 Y; X5 w2 o; F int mid = (right - left) / 2 + left;- A; t U4 q, E$ r$ S
* X6 A% N/ D P$ E3 {: n //划分左右子区间[left, mid]和[mid + 1, right]2 M+ S, g& I) P- B3 Y+ x
_MergeSort(arr, tmp, left, mid);
9 z u+ [6 v$ y( w, i _MergeSort(arr, tmp, mid + 1, right);
/ A5 ~4 Z7 J+ _9 r1 e) i% V! X L, x% m0 w) v
//归并
, }* ]) f. I% U5 t/ y int begin1 = left, end1 = mid;
; Y0 m ~9 w+ g& ~# E, i/ d" n* G int begin2 = mid + 1, end2 = right;1 `3 {/ |7 t* D: L* }1 Q$ B6 A
int i = left;
4 I P: Y( m6 \" |. R% P while (begin1 <= end1 && begin2 <= end2)4 r$ B) J+ b& q5 ?* C t/ g
{
7 u r9 K8 a2 J5 i! j7 d: k if (arr[begin1] < arr[begin2])2 v5 `5 E9 S; P+ `
tmp[i++] = arr[begin1++];7 b! W! L) G& V; d R6 Z
else# j" c, q+ b8 E# \5 _3 n3 [
tmp[i++] = arr[begin2++];
% I5 {! f! ^$ J) l' C. o }9 J; C7 Y6 H$ i+ D
. P2 l3 t8 [9 T1 ~( i while (begin1 <= end1)
* M D8 Q: y& _1 R, h+ y$ F tmp[i++] = arr[begin1++];
7 G7 @. ^4 A9 `. H while (begin2 <= end2)
1 ?: k5 l$ F1 C) s6 E tmp[i++] = arr[begin2++];
0 `9 @$ |$ g& j4 i, v * e5 r3 [$ z) s& j
//拷贝回原数组——归并哪部分就拷贝哪部分回去
# b$ S e$ I1 A2 g8 `% [) O5 z //而不是拷贝整个数组回去
/ T. S) Z' J; n memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));9 y( y$ G- D& j
}3 g& N) I3 P8 W5 e
1 i' ?$ }4 K' N3 k+ Tvoid MergeSort(int* arr, int left, int right)) g2 g. k1 X+ \$ l% E8 V
{* |7 X5 v4 F0 H
assert(arr);
0 |; [: J+ r% t7 s$ ]; F8 T
9 S- B+ U! q9 o; @: T+ ^ int* tmp = (int*)malloc((right - left + 1) * sizeof(int));! L) y% [/ q, ^) V8 G. c ~: S
if (tmp == NULL)# w9 {- E0 {# N# ^9 U; |3 n
{
# y+ D9 h! H7 g _4 S p perror("malloc fail");
0 l3 T& O! `& m" d% j# X$ q return;
2 g, O& i0 T: o4 f M4 U1 z5 g }" l/ p* q: E( \- y
& Q& t6 l* A5 O3 D: t6 Y5 U _MergeSort(arr, tmp, left, right);
4 w" P0 A) Y1 y. _
f. y8 o5 X4 }8 Z( b/ \* e0 R free(tmp);
% D1 f. f: l* S! \4 J# S8 S2 u tmp = NULL;
! x5 I: f; J# a1 B) q}
; I) m4 w/ N; h4 X
* |" o; Y/ ^ h( p/ S- k1$ l6 o* x2 x0 L7 X& H7 d
2
% Q; D1 @) z: J% N3
, f# P. @% I9 f, b4
h4 J* O0 y& d6 x5
# N# Q& F0 [6 Z* C' n66 Z5 S' o* q$ [$ W
7& }6 s6 b8 i9 y' \, t$ H( X
8
# C9 _ h1 E4 S9
, z* u: m7 V; s( n10
# n! p) M+ b1 I: e) O11
' i- w" X0 i$ e& ]0 O" f12
8 z* f9 G, u+ p/ H13
" C/ \ L) b0 G" Z* ~14
% G8 E3 d. P9 m1 G9 z152 L# O: [* r& Q6 S0 Q2 A
16) ^' Z3 }8 o2 f4 C# o l& v9 T
17$ L; r) l& X; o q. i
18
5 G. G* K6 y8 s5 C g8 \19; F' v9 L/ W7 c7 b5 _4 E8 q& Q/ z# P
20- ~8 w1 ?8 N% P4 i5 v- D
21& W/ N( D7 k# G- j1 r1 @
22
) o! s$ Y' \ M/ e23
* h, c8 m" n/ ]/ d! G( d24
' g* r/ C5 J0 R. @2 w251 f8 ?+ w M& F* Y% J* z
26" P/ n# J) a# Y R: E2 H; U% F3 V
27/ a: M2 n# X7 j
28
" T# V: P) R$ ^; S- S9 q. r6 K29# y0 ]4 q; U- t( D/ V$ {2 W: I+ ?2 l
308 y5 `2 V& L! f. p* ?5 L1 ~
31* P, _5 a% p3 C, {
32
1 G8 j# m' V1 j) k1 u. w33% t3 k' Z ]3 D l
34
& B) c- E* R$ e* Q% V350 Q/ v( e/ `6 i* `, F; t; r- i
36
# {; i0 r: N) i; D( v6 o7 m# H, w37 q/ `) Y/ S8 C" @- Z5 V0 N
389 ?) G! F3 h% K( C1 N7 q* [9 n
39
1 c0 j! P( R5 }& \: Q: ]40
9 Z& N3 Q! [* p K) ^* F7 g6 O410 A8 j4 @; U5 b" z; V7 {9 h# Z1 i
42
. l# J( P3 C% ?2 Y7 z43
]' N0 y; g2 v& Q44/ P9 S q+ t: a6 h" D0 O+ D. H
45
& k- ~( }9 Z( P1 l46, T" l! B+ t& n
47) g# G* H8 B8 v. w! [7 f4 F
48+ y8 F# C Q6 T: U$ j
49 v1 h0 a. y& A
50
0 I! V* j1 a: o3 x514 B- K; F; h6 s
非递归实现
; c8 Z! v8 A! H4 L0 \ 直接在原数组基础上归并,设gap是子区间元素个数,从gap = 1开始,因为仅有一个元素的子区间一定有序。为了方便,我们把gap=1叫做第一层,以此类推。0 S( D$ E/ h/ C, d- s7 c
! G5 W# o8 _ \. E5 E* w3 l1 Y
% U+ r7 l+ {# u1 z/ w
7 }2 W- s6 [, L( X# ~5 t 不同的gap值代表所在层数不同,每一层都是从左到右两组为一对地取对配对归并,i就是每对起始位置,之所以更新i的时候要i += 2 * gap是因为每队两组、每组gap个元素,所以要让i跑到下一对的起始位置的话不就要跳过一整对的空间嘛。
1 P" Q/ C4 d+ j! D1 M# o* q$ W% }& X+ n* _# \) G$ b$ p
还要注意区间的取值,每个区间就是一组,就有gap个元素。. F2 ^9 B( [' J$ r( l
2 Z# T2 f1 \! i8 C& p# F5 h
整体拷贝遇到越界就会比较难搞,所以我们这里用部分拷贝的思路,每次归并后直接拷贝,要注意一下指针偏移量不是begin1而是i,因为begin1已经在归并过程中被改变了。4 l1 l3 W! f( k# C; b4 Z; e
* X8 U8 J% o0 L, D+ z& K
代码实现. H# q9 l: b4 w
* M# F5 C8 C* K: n) x9 Q
void MergeSortNonR(int* arr, int sz)
# @0 F8 z( l4 L/ }; B, U ^{
$ p8 _ `, j" u8 G' C2 q8 N assert(arr);8 ?: j9 h8 D2 c
3 p, y' g" i3 X% {* f. F( A& l int* tmp = (int*)malloc(sz * sizeof(int));
$ ~5 q% P9 D. w1 M9 V if (tmp == NULL)
: g1 Z/ Q6 v$ c- V; \ {/ C/ U; U4 b1 Y5 n7 S5 J" J
perror("malloc fail");
* ?$ x+ M3 y' t; T1 u4 i) }/ C" | return;: _( t3 b5 K/ w* E3 I
} d1 S$ R+ v6 T( {7 W
+ R4 h7 k. o6 f1 x9 I
int gap = 1;- \( f% \$ o& ^! s4 M& b0 Z
while (gap < sz)
$ }& |/ J# P: t5 O. q. k1 v( J+ S1 @0 |6 M {: E( @- A% `' a- S/ Y& q
for (int i = 0; i < sz; i += 2 * gap)( U8 P5 ]9 v5 X: F, f8 ?: _
{
: G6 \* r Y, f int begin1 = i, end1 = begin1 + gap - 1;. I" V5 L( D1 P
int begin2 = end1 + 1, end2 = begin2 + gap - 1;9 i0 I2 Y6 i" Z1 i5 j% l
int j = begin1;
H* G. n# B" D h4 y) V, b2 ?% N) ~# |. U
//归并" v- V, @" d, v" I v- n
while (begin1 <= end1 && begin2 <= end2)$ k @: j$ Z" m) X& T1 j
{; r3 l: p3 m& b( ?" N8 N7 Q
if (arr[begin1] < arr[begin2])3 V2 A' Y* D% V# j- Q6 L, O7 L
tmp[j++] = arr[begin1++];
R' W8 p' N( E2 M3 n, [; g" A else
& x+ z% m7 J5 A9 ]. {9 W tmp[j++] = arr[begin2++];
) n$ l9 F0 B Z4 M p* O. _ }/ b! K: Z8 f' H& D+ ]* i$ y
1 g4 Q1 j% t; h- T
while (begin1 <= end1)1 J% I. n0 h9 i- z
tmp[j++] = arr[begin1++];
: d: _* y9 C1 u" O# K( S7 o while (begin2 <= end2)7 J7 R5 g: Z' Y* L- C
tmp[j++] = arr[begin2++];
: \, G# U9 _$ ^" r4 E# S! G
' A" f( c" F" N: f //拷贝回原数组——归并哪部分就拷贝哪部分回去
6 s0 M9 M9 o6 D' j, O. d memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));
3 h8 m: D) Q% w" H6 }* p3 i }% s9 f4 t; {! Q
gap *= 2;
; d" I& x, f4 i5 c, y) u }
S0 x g* G3 r& h$ {+ ?* f3 @0 o, m6 @( Y: d+ Q3 _
}
6 V3 i1 Z7 v# ~' a$ M9 s% p) h
" n* i( b/ U2 [% S$ s8 G& @1# M' m) R! s) y9 C$ t# A
2
( t: p4 i8 c4 g: ?# l3
% _" A; \. d9 N0 _$ m* h4
" r/ U+ t( J# J5 A54 Q$ n" Y, F6 C/ J: p
6* L, R2 H8 e- ]5 c8 p
7
( i9 @: a$ d1 o2 Y- ?8
6 m* z5 c& Q) s$ {9% K. M J* X2 B4 }, g9 I* w
10
% w" J" {. Q- k% x$ Y1 o5 `2 C11/ J' l: V5 {+ S' k; g4 c4 `
128 o. Y) U) R/ l" J, c4 X3 T! ?
13
* K0 S9 [" @* O" V14
8 d4 j% R5 Z2 s, I8 O' b& A15
9 M# T1 q1 z: o) D t166 I A) x0 [7 i! O+ x: r, u
179 x3 H( g+ D% q) Z
180 ]$ e% c7 v, E* t, x. i3 r
19: L0 W$ y, C( P7 K5 l
20
( G$ C" u, U# h3 `21
. o/ S/ A2 k( ]22
) s2 `/ J$ T& ~: j239 j2 k$ V: x4 _# p! B# b
245 ^( O. ^# k/ A7 n7 d4 M
25/ w) M, X+ F) [5 E4 w- ?0 Y
26& T# g3 [/ X6 s4 `0 z
279 n8 O) F' J8 Q. a. E
28
5 L' _7 g. {# F3 y9 F9 X7 m3 ]29
% S$ _0 F4 U! k" }# V% m30
% g! n: W* r7 Z& \& v2 Q- Z31* q) @) R8 z8 V Z
32. C) \( M# U; Z& Y9 {
337 U, I' e! P7 U/ |. L- I9 s
34: O; E3 [$ I* R9 j( ^. H( l
35
$ D8 L8 v" ? L( q, j" W3 `+ E365 Z; n9 Z) Q0 T# o/ r6 E9 p
37
6 p$ E" `4 B: X P$ i/ d2 P38" Q) l) H a" x6 ^! H$ `2 H. j# I
39" L8 n4 S. _6 ~+ h) _" J
40' C+ H- x z5 _ W# w4 W! s$ _
41. T N" D* U2 w4 @- h' L
边界问题
/ _; p& P. O/ w3 ]. @ 实际上还需考虑是否越界的问题,上面那段代码并没有考虑,所以还需一些改进。为什么会存在越界的可能呢?因为我们是以gap的整数倍去取区间来归并的,而区间个数不一定总能满足两两配对。 g# a, j9 s% h% U- Y% \$ b) l8 r$ G
" h, g/ t* N7 S8 ^/ A0 W. q0 \. d) L举个例子,就把前面的那个数组后面加上个元素5,没有越界检测时出现的情况:3 D; r& c- H# P; f* e7 B
) s5 {% u- `! V, s G8 E0 \
" B0 X/ ]5 |: g; n. G! w8 U& y1 Y" ^9 K+ S/ Q
由上图可知越界分为三类(这里将[begin1, end1]、[begin2, end2]分别作为第一和第二组)
* N; I9 W" R" e* O( J( |7 H! ~' P ^8 b% W0 X/ \2 D _7 e: d
第一组越界(即end1越界)4 V; @/ Q3 \; n2 j! O$ B8 [
- A- x3 a( Z0 F) y5 E5 j% s6 `
应对方法:这种情况一般介于第一层和最后一层之间,break跳出for循环,不让越界值被访问。
9 _) f$ u3 v- u. u+ y6 n# r
- _- A9 C( N/ g" _9 \第二组全部越界(即begin2和end2越界)
# ~6 \6 K, j2 s! D& _
* k6 f: c9 w( h3 H3 D应对方法:这种情况一般在第一层,break跳出for循环,不让越界值被访问。. D7 z0 _5 l. L+ l9 j0 |8 v8 p
' m/ S3 z0 U( C& m第二组部分越界(即end2越界) }5 ~8 m3 h# F- ^
* C5 i0 G! c: w8 o X7 {
应对方法:实际上这时候就到了最后一层了,把end2修正为sz - 1,不跳出for循环而继续归并。1 T/ ~( o2 V$ s* u4 x
4 c" C( x) Y; H3 m' a# ], L
其实第一种情况和第二种情况可以合并为一种情况,原因:3 ~: i! A" b: U8 q
% P7 ^5 S4 Y9 z9 ^/ O end1越界时begin2和end2由于比end1大,它们两个肯定也越界了,也就是说发生第一组越界时满足end1、begin2和end2都越界,即包括了第二组越界的条件,这两种情况都满足判断条件begin2 >= sz && end2 >= sz,同时第一和第二种情况的操作都一样——break跳出for循环,所以可以合并为只判断第二组是否全部越界。
- x, O5 t" r% g" _6 h9 R, h! _8 e& g/ F# @
拿两个数组试一下:
( k% Q9 \* Y& K; K3 g/ ?' h$ W
1 ]: a" j" {8 |) m2 O/ K; `3 ]8 J, q3 t: f: x2 ]% T
9 V9 Q! r4 I! \" E: \- K: \$ X+ t* |
' K1 q+ \7 G/ J B代码实现; E5 F+ L: G- Q3 y
( r4 G3 }7 S; u+ fvoid MergeSortNonR(int* arr, int sz)
( o4 M, q; D: \. V% m{
1 \2 C8 O( d" P3 S assert(arr);- R3 n' _9 E6 L) E/ g
) e3 K4 K" i& Q: K
int* tmp = (int*)malloc(sz * sizeof(int));
+ G- x0 A# o) o/ K if (tmp == NULL)
' r+ ~( D% \, K& z {" W7 W# ]* v! A# o
perror("malloc fail");* h0 \7 L0 r7 `
return;
8 F4 [/ V* f2 B D& F+ L1 v }
$ k, Z o2 N4 s# @
1 L& B/ u; E, t$ J J8 B$ f int gap = 1;
3 _ i9 q4 E0 j while (gap < sz); v2 a+ l1 R- z0 w2 b5 z+ C7 m
{
0 j2 [0 R# G. t m for (int i = 0; i < sz; i += 2 * gap)5 h! A, |! c* k6 k+ @8 y
{( x3 h* l) D2 o9 C& T
int begin1 = i, end1 = begin1 + gap - 1;
" ~# {' @6 [% E int begin2 = end1 + 1, end2 = begin2 + gap - 1;% X) k9 p( C$ n! f8 _( r( b4 w) o
int j = begin1;: t! G/ r# |. B* A2 X* |0 N- W
//越界检测' {# b# w9 Y( U% ~
if (begin2 >= sz && end2 >= sz)+ D& h$ o E9 M
break;0 M: [9 t; |% f' _8 C. E% `- R
if (end2 >= sz)
* Q% Y3 H$ ~1 P* Z- c7 g P7 M end2 = sz - 1;
$ W# E1 w: a6 {. M4 C //归并! r; o& }* @2 ^/ |% M
while (begin1 <= end1 && begin2 <= end2)
3 B& T' b) M( x- E {; \& x E5 s) a2 J: ^
if (arr[begin1] < arr[begin2])
7 ?$ C5 A+ s' K+ U* T4 X9 x0 C tmp[j++] = arr[begin1++];- | t5 P( L) s% K
else
+ Y: ^8 i7 [: X' J tmp[j++] = arr[begin2++];
" \3 S+ @, Z9 {- K6 r1 E( N% p; l }: z0 |/ c- r% V2 g5 j1 d+ t
, f/ o- }7 y' R while (begin1 <= end1)5 V/ E! H4 J5 ?* n
tmp[j++] = arr[begin1++];
8 d9 m' m5 U& F& u) X while (begin2 <= end2)
! L$ i, l0 S% I' P& E; E. n$ `% e tmp[j++] = arr[begin2++];
# z- L; f. _$ p9 M. X5 ]
. A* y2 l. Y: q7 b6 L0 Z! x //拷贝回原数组——归并哪部分就拷贝哪部分回去" v; [$ Q& A) f# Y" t7 ~4 H
memcpy(arr + i, tmp + i, sizeof(int) * (end2 - i + 1));# |7 b* u% L, w+ T6 n: j. P* J! y
}
2 J6 x# c- Q* y gap *= 2;
5 G+ c# A9 I5 Y; M* z k: U }
2 P! S# o2 Z H
) b1 \* s! i0 r- E" I/ P3 g}5 Z% a5 U- N8 P- h8 P$ N
; l+ ~4 Y' z0 G0 L1
( {# ?1 U0 j4 ?; w6 d2
! c2 k4 }5 g' t2 A3+ ] [. }3 V" K
4
+ m8 s9 {2 Z0 }+ s1 Y2 H+ ^5; X. c/ |1 o) a$ r$ B- I: u# x" n/ ~
6) E, x& ?/ g* L: X& i& P6 C7 ~8 q
7) g$ w. U- T/ o3 Y: p
82 F' H) Y6 Y! F% Z
9
3 x' r" X9 c8 v! Z10
' j) ~7 K9 U H& Y( f" B( H11
4 F( j* j2 t: m1 F12- b( W3 F! |* q, R: R
138 e b6 _. G0 J! r0 q0 J
140 M4 `) e$ s8 H, ]- j3 N
15' f& z8 s# v3 M' A' b
164 C! S# D% P4 i! ]1 G: b
17
. |5 V, ~- A4 H9 |% k180 e+ p9 g i+ X w3 Q( s2 e
19. S7 U* z' Y! I& z* f& w. c5 s$ F. m
20
0 j0 w# O3 [0 F21; L$ w, |% z& |' S& Y
226 Z5 L0 ~7 Q% R
23 }; S! {+ u) t O" ^( }
24
5 ~5 \ c% _2 _4 M7 S9 m% Q& j25
) t5 \ w* ~ n+ }# }* A0 v* J26( N* [( o! i+ R/ K, E3 G
27
. ?" X) @' H* p) O$ [; W28
% { F4 M0 O }' q8 ]- j29, R( p. f. z b( a2 T# |1 H
30
$ |! ?; _& i8 ]' g7 Y% K3 n; }31
# @, i# o, t$ d32
6 N8 J- m( H5 b- C33& r, |- \& ~: \ H3 G: Q1 ]5 W& ?
34
6 n( K0 ~1 t! z, l6 E, B, U35
6 w; F+ p6 V" V, Y+ g$ g36
5 p7 a8 |8 q" e37: I7 F5 n% {9 M0 `
38) `( ?/ G% z1 g1 z/ T: _% `! _
39
) m: j. z" E( o) L0 B4 S40
7 X o6 ~, {4 t6 Y41" ]! N: C/ ]0 W& w0 C+ }3 n
422 x+ p1 O7 J$ P3 e7 W2 \
43; c' r% t* y+ t6 H5 {. g
44
h& I9 _1 c3 o' {) ^45
0 Q+ h% Z" Z: L归并排序的特性总结:! R7 v9 ]. B7 n" T0 T
0 f. W3 R( o0 T% S' D归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。' V+ R& T2 E( ^
时间复杂度:O(N*logN)
# E6 j0 y' V4 t: U3 ]6 N) e6 D空间复杂度:O(N). L7 C" p6 A1 G! V) U% Y7 C
稳定性:稳定
1 e; J L% ^' R i: ]
5 ?: a, |" _% ?$ j6 r: U, ]: \. J, r9 S4 D————————————————
% V# `7 s% G- L版权声明:本文为CSDN博主「桦秋静」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
+ |" X k' M/ @7 Q) V原文链接:https://blog.csdn.net/weixin_61561736/article/details/126796657, R/ ^- W: B4 G$ u, L7 _
( _3 n# ~6 m* N$ g
8 s% o: n! C0 I& s
|
zan
|