递归算法经典实例_学无止境:C++经典排序(三)

C++经典排序(三):分而治之

一个优秀的排序算法,在处理数据量较大的任务时能简化复杂度,缩减完成任务的时间。

备战期末之余,学学排序算法吧!

c1a1cce0fbed8f341eb057b9c87dbf37.png

     分而治之,出自《群经平议·周官二》。指利用手段使国家、民族或宗教等产生分裂,然后对其进行控制和统治。可以理解为将大的问题分开来解决,以达到统一。

0 1

归并排序

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

   归并排序由冯·诺依曼提出,时间复杂度为O(nlogn),空间复杂度为T(n)。

   它的内存占用较高,是一种非常稳定的排序算法。

0 2算法概念

1、申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;

2、设定两个指针变量,最初位置分别指向两个已经排好序的数组序列的起始位置;

3、比较两个指针所指向的元素,选择相对小的元素放入到申请的合并空间里,并移动此指针到下一位置;

4、继续重复步骤3直到某一指针达到序列尾;

5、当一个指针到达一个序列尾时,将另一序列剩下的所有元素直接复制到合并序列尾。

  通俗地讲,就是割,割,割,数组被割到不能再割的时候再两两合并起来。

归并排序示意图 21d96722936bae40d664009dff191d92.png

a94d2329c6406a5e40cb93062544a654.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

1ad34f94adb9cf5f5f8b85e6ff7faa5e.png

ecb3239395de7c1dacb085588c971431.gif

什么?还没学会!

那回到下面这个数组

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 !

5ed62a6d03090db3d5242cd802fbcdc7.png

    本期内容到这里就结束啦,更多的算法介绍将会在下期专题带给大家!

    喜欢的小伙伴点个在看哦!

8c814c7e68bafae90093efb9f2b24d84.png

文字:四季豆               

排版:四季豆  

审核:杨荣佳    

我就知道你“在看” 7b8b2a0ea811ba3402050a9c1be73543.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值