C++经典排序(三):分而治之
一个优秀的排序算法,在处理数据量较大的任务时能简化复杂度,缩减完成任务的时间。
备战期末之余,学学排序算法吧!
![c1a1cce0fbed8f341eb057b9c87dbf37.png](https://i-blog.csdnimg.cn/blog_migrate/268d7fedb23cd977533714a6e7225945.png)
分而治之,出自《群经平议·周官二》。指利用手段使国家、民族或宗教等产生分裂,然后对其进行控制和统治。可以理解为将大的问题分开来解决,以达到统一。
0 1归并排序
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
归并排序由冯·诺依曼提出,时间复杂度为O(nlogn),空间复杂度为T(n)。
它的内存占用较高,是一种非常稳定的排序算法。
0 2算法概念1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
2、设定两个指针变量,最初位置分别指向两个已经排好序的数组序列的起始位置;
3、比较两个指针所指向的元素,选择相对小的元素放入到申请的合并空间里,并移动此指针到下一位置;
4、继续重复步骤3直到某一指针达到序列尾;
5、当一个指针到达一个序列尾时,将另一序列剩下的所有元素直接复制到合并序列尾。
通俗地讲,就是割,割,割,数组被割到不能再割的时候再两两合并起来。
归并排序示意图![21d96722936bae40d664009dff191d92.png](https://i-blog.csdnimg.cn/blog_migrate/c6c945c1030c4b8bdcc5638aa9b8f0f3.png)
对于上图神似二叉树结构的流程图,我们分成两个阶段。
“分”阶段采用递归/迭代,将数组拆分。递归深度为log2n。
“治”阶段就显得比较复杂,类似于插入操作,子序列有n个元素,最多操作n次,时间复杂度为θ(n);总的时间复杂度为:T(n)=2T(n/2)+θ(n)。由递归树得时间复杂度为O(nlog n)。
//代码示例
1//归并排序
2 void MergeArray(int* arr, size_t left, size_t mid,size_t right, int* temp) //归并过程
3 {
4 if(arr==NULL) return;
5
6 size_t i=left,j=mid+1,k=0;
7 while(i<=mid && j<=right)
8 {
9 if(arr[i]<=arr[j])
10 {
11 temp[k++]=arr[i++];
12 continue;
13 }
14
15 temp[k++]=arr[j++];
16 }
17
18 while(i<=mid)
19 temp[k++]=arr[i++];
20
21 while(j<=right)
22 temp[k++]=arr[j++];
23
24 memcpy(&arr[left],temp,k*sizeof(int));
25
26 return;
27 }
28
29 void MMergeSort(int* arr, size_t left, size_t right, int* temp)
30 {
31 if(left<right)
32 {
33 size_t mid=(left+right)/2;
34 MMergeSort(arr, left, mid, temp);
35 MMergeSort(arr, mid+1,right, temp);
36 MergeArray(arr,left, mid, right, temp);
37 }
38 }
39
40 void MergeSort(int* h, size_t len)
41 {
42 if(h==NULL) return;
43 if(len<=1) return;
44 int* temp=(int*)calloc(len,sizeof(int));
45 MMergeSort(h, 0, len-1, temp);
46
47 memcpy(h,temp,sizeof(int)*len);
48
49 free(temp);//释放了辅助数组temp的内存
50
51 return;
52 }
眼花缭乱了吗?别急,回到实例,康康图解!
![dea642b13514c28fad7cbd57efbf6a5a.png](https://i-blog.csdnimg.cn/blog_migrate/422baff608d4d57bb73c0003ae0d417b.png)
什么?还没学会!
那回到下面这个数组
8 4 5 7 1 3 6 2
思考一下,信手拈来!
void Merge(int r[], int r1[], int s, int m, int t)
{
int i = s;
int j = m + 1;
int k = s;
while (i <= m && j <= t)
{
if (r[i] <= r[j])
r1[k++] = r[i++];
else
r1[k++] = r[j++];
}
if (i <= m)
while (i <= m)
r1[k++] = r[i++];
else
while (j <= t)
r1[k++] = r[j++];
for (int n = s; n <= t; n++)
r[n] = r1[n];
}
void MergeSort(int r[], int r1[], int s, int t)
{
if (s
{
int m = (s + t) / 2;
MergeSort(r, r1, s, m);
MergeSort(r, r1, m + 1, t);
Merge(r, r1, s, m, t);
}
}
int main()
{
int r[8] = {8, 4, 5, 7, 1, 3, 6, 2}, r1[8]
MergeSort(r, r1, 0, 7);
for (int q = 0; q
std::cout <
return 0;
}
//这段代码里,r与r1其实是上文中*arr与temp的另一种表达,简化了变量名,s、t则为原始数组的左右下标。//
归并排序看似复杂,在理解原理之后稍加琢磨即可拿下!
它时间复杂度是 O(nlogn)。正因为它采取了切分-排序-合并的思路,使得遍历和交换成员的次数减少,是实际工程中可选的排序方案。
你,学废了吗 w(゚Д゚)w !
本期内容到这里就结束啦,更多的算法介绍将会在下期专题带给大家!
喜欢的小伙伴点个在看哦!
![8c814c7e68bafae90093efb9f2b24d84.png](https://i-blog.csdnimg.cn/blog_migrate/cfd42597af2c9acffe3bae956167e2d8.jpeg)
文字:四季豆
排版:四季豆
审核:杨荣佳
我就知道你“在看”![7b8b2a0ea811ba3402050a9c1be73543.gif](https://i-blog.csdnimg.cn/blog_migrate/2c89d1fceeb58c3b96c361f1c06eae96.gif)