基本思想

建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

算法原理

归并操作指的是将两个已经排序的序列合并成一个序列的操作,归并操作步骤如下:

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

设定两个指针,最初位置分别为两个已经排序序列的起始位置

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

重复步骤3直到某一指针到达序列尾

将另一序列剩下的所有元素直接复制到合并序列尾

特点

数据结构:数组

稳定性:稳定

过程

https://blog.csdn.net/weixin_43272781/article/details/85013461

排序过程            宏观过程

复杂度与辅助空间

最差时间复杂度:O(nlogn)

最优时间复杂度:O(nlogn)

平均时间复杂度:O(nlogn)

所需辅助空间:O(n)

源程序

//将有二个有序数列a[first...mid]和a[mid...last]合并。
void mergearray(int a[], int first, int mid, int last, int temp[])
{
int i = first, j = mid + ;
int m = mid, n = last;
int k = ; while (i <= m && j <= n)
{
if (a[i] <= a[j])
temp[k++] = a[i++];
else
temp[k++] = a[j++];
} while (i <= m)
temp[k++] = a[i++]; while (j <= n)
temp[k++] = a[j++]; for (i = ; i < k; i++)
a[first + i] = temp[i];
}
void mergesort(int a[], int first, int last, int temp[])
{
if (first < last)
{
int mid = (first + last) / ;
mergesort(a, first, mid, temp); //左边有序
mergesort(a, mid + , last, temp); //右边有序
mergearray(a, first, mid, last, temp); //再将二个有序数列合并
}
} bool MergeSort(int a[], int n)
{
int *p = new int[n];
if (p == NULL)
return false;
mergesort(a, , n - , p);
delete[] p;
return true;
}

一、圆周率π计算

  1.  
    /*
  2.  
    *@Author: STZG
  3.  
    *@Language: C++
  4.  
    */
  5.  
    #include <bits/stdc++.h>
  6.  
    using namespace std;
  7.  
    long a=10000,b,c=56000,d,e,f[56001],g;
  8.  
    int main(){
  9.  
    for(;b-c ; )f[b++]=a/5;
  10.  
    for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)
  11.  
    for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);
  12.  
    //cout << "Hello world!" << endl;
  13.  
    return 0;
  14.  
    }

二、数学公式

π = 2 + 1/3 * (2 + 2/5 * (2 + 3/7 * (2 + ...  (2 + k/2k+1 * (2 + ... ))...)))

三、分析

  1.  
    #include <stdio.h>
  2.  
    int a=10000,b,c=2800,d,e,f[2801],g;
  3.  
    main() {
  4.  
    int i;
  5.  
    for(i=0;i<c;i++)
  6.  
         f[i]=a/5;
  7.  
    while(c!=0)
  8.  
         {
  9.  
             d=0;
  10.  
             g=c*2;
  11.  
             b=c;
  12.  
             while(1)
  13.  
                {
  14.  
                    d=d+f[b]*a;
  15.  
                    g--;
  16.  
                    f[b]=d%g;
  17.  
                    d=d/g;
  18.  
                    g--;
  19.  
                    b--;
  20.  
                    if(b==0) break;
  21.  
                    d=d*b;
  22.  
                }
  23.  
             c=c-14;
  24.  
             printf("%.4d",e+d/a);
  25.  
             e=d%a;
  26.  
        }
  27.  
    }

要想计算出无限精度的PI,我们需要上述的迭代公式运行无数次,并且其中每个分数也是完全精确的,这在计算机中自然是无法实现的。那么基本实现思想就是迭代足够多次,并且每个分数也足够精确,这样就能够计算出PI的前n位来。上面这个程序计算800位,迭代公式一共迭代2800次。

int a=10000,b,c=2800,d,e,f[2801],g;

这句话中的2800就是迭代次数。

由于float或者double的精度远远不够,因此程序中使用整数类型(实际是长整型),分段运算(每次计算4位)。我们可以看到输出语句printf("%.4d",e+d/a); 其中%.4就是把计算出来的4位输出,我们看到c每次减少14( c=c-14;),而c的初始大小为2800,因此一共就分了200段运算,并且每次输出4位,所以一共输出了800位。

由于使用整型数运算,因此有必要乘上一个系数,在这个程序中系数为1000,也就是说,公式如下:

1000*pi = 2K+ 1/3 * (2K+ 2/5 * (2K+ 3/7 * (2K+ ... (2K+ k/2k+1 * (2K+ ... ))...)))

这里的2K表示2000,也就是f[2801]数组初始化以后的数据,a=10000,a/5=2000,所以下面的程序把f中的每个元素都赋值为2000:
for(i=0;i<c;i++)
f[i]=a/5;

你可能会觉得奇怪,为什么这里要把一个常数储存到数组中去,请继续往下看。我们先来跟踪一下程序的运行:

  1.  
    while(c!=0)  //假设这是第一次运行,c=2800,为迭代次数
  2.  
         {
  3.  
             d=0;
  4.  
             g=c*2;  //这里的g是用来做k/(2k+1)中的分子
  5.  
             b=c;  //这里的b是用来做k/(2k+1)中的分子
  6.  
             while(1)
  7.  
             while(1)
  8.  
                {
  9.  
                    d=d+f[b]*a;  //f中的所有的值都为2000,这里在计算时又把系数扩大了a=10000倍。这样做的目的稍候介绍,你可以看到输出的时候是d/a,所以这不影响计算
  10.  
                    g--;
  11.  
                    f[b]=d%g;  //先不管这一行
  12.  
                    d=d/g;  //第一次运行的g为2*2799+1,你可以看到g做了分母
  13.  
                    g--;
  14.  
                    b--;
  15.  
                    if(b==0) break;
  16.  
                    d=d*b;  //这里的b为2799,可以看到b做了分子。
  17.  
                }
  18.  
             c=c-14;
  19.  
             printf("%.4d",e+d/a);
  20.  
             e=d%a;
  21.  
        }
  22.  
     

只需要粗略的看看上面的程序,我们就大概知道它的确是使用的那个迭代公式来计算Pi的了,不过不知道到现在为止你是否明白了f数组的用处。如果没有明白,请继续阅读。
d=d/g,这一行的目的是除以2k+1,我们知道之所以程序无法精确计算的原因就是这个除法。即使用浮点数,答案也是不够精确的,因此直接用来计算800位的Pi是不可能的。那么不精确的成分在哪里?很明显:就是那个余数d%g。程序用f数组把这个误差储存起来,在下次计算的时候使用。现在你也应该知道为什么d=d+f[b]*a;中间需要乘上a了吧。把分子扩大之后,才好把误差精确的算出来。
d如果不乘10000这个系数,则其值为2000,那么运行d=d/g;则是2000/(2*2799+1),这种整数的除法答案为0,根本无法迭代下去了。
现在我们知道程序就是把余数储存起来,作为下次迭代的时候的参数,那么为什么这么做就可以使得下次迭代出来的结果为接下来的数字呢?
这实际上和我们在纸上作除法很类似:

   0142
  /———
 7/ 1
   10
    7
——————
    30
    28
——————
    20
    14
——————
     6
.....

我们可以发现,在做除法的时候,我们通常把余数扩大之后再来计算,f中既然储存的是余数,而f[b]*a;则正好把这个余数扩大了a倍,然后如此循环下去,可以计算到任意精度。
这里要说明的是,事实上每次计算出来的d并不一定只有4位数,例如第一次计算的时候,d的值为31415926,输出4位时候,把低四位的值储存在e中间,e=d%a,也就是5926。

最后,这个c=c-14不太好理解。事实上没有这条语句,程序计算出来的仍然正确。只是因为如果迭代2800次,无论分数如何精确,最后Pi的精度只能够达到800。
你可以把程序改为如下形式尝试一下:

  1.  
    for(i=0;i<800;i++)
  2.  
         {
  3.  
         {
  4.  
             d=0;
  5.  
             g=c*2;
  6.  
             b=c;
  7.  
             while(1)
  8.  
                {
  9.  
                    d=d+f[b]*a;
  10.  
                    g--;
  11.  
                    f[b]=d%g;
  12.  
                    d=d/g;
  13.  
                    g--;
  14.  
                    b--;
  15.  
                    if(b==0) break;
  16.  
                    d=d*b;
  17.  
                }
  18.  
           //c=c-14;  //不要这句话。
  19.  
             printf("%.4d",e+d/a);
  20.  
             e=d%a;
  21.  
        }

最后的答案仍然正确。
不过我们可以看到内循环的次数是c次,也就是说每次迭代计算c次。而每次计算后续位数的时候,迭代次数减少14,而不影响精度。

归并排序(Merge_Sort)的更多相关文章

  1. 疯子的算法总结(六) 复杂排序算法 ① 归并排序 merge_sort()

    归并排序采取了分治的思想,每次分别排左半边和右半边,不断递归调用自己,直到只有一个元素递归结束,开始回溯,调用merge函数,合并两个有序序列,再合并的时候每次给末尾追上一个最大int这样就不怕最后一 ...

  2. 归并排序merge_sort

    将区间递归分解,直到区间只有2个元素,然后比较大小,排序,等递归回来的时候就将排序好的子区间再排序合并....一直排序合并,最后就排序完成了. (可以做范围大的逆序数的题) #include < ...

  3. 【Algorithm】自顶向下的归并排序

    一. 算法描述 自顶向下的归并排序:采用分治法进行自顶向下的程序设计方式,分治法的核心思想就是分解.求解.合并. 先将长度为N的无序序列分割平均分割为两段 然后分别对前半段进行归并排序.后半段进行归并 ...

  4. Open Data Structure Templates

    数据结构模板 Chen 2016/12/22 前言 本篇博客的模板,全部是我纯手打的,如果有发现错误,请在下方留言指正:).欢迎大家参考. 有一些地方还不是很完善,等过一阵子用C++实现和部分重构下. ...

  5. 给一已经排序数组A和x,求A中是否包含两个元素之和为x

    亲爱的大神老爷们,这是小渣第一次写blog,欢迎大家来喷(批评指正),算法渣因为面试中连这道题都不会写就自己琢磨了一下,也参考了网上大家的做法 解法一: 思路:从首尾向目的靠拢,因为已经排序,[假设存 ...

  6. JAVA:数组,排序,查找<4>

    一.数组 1.一维数组 (1).数组的定义 数据类型 数组名[]=new 数据类型[大小] public class Demo1 { public static void main(String[] ...

  7. Java学习第四篇:数组,排序,查找

    一.数组 1.一维数组 (1).数组的定义 数据类型 数组名[]=new 数据类型[大小] public class Demo1 { public static void main(String[] ...

  8. ###Maintainable C++

    点击查看Evernote原文. #@author: gr #@date: 2014-08-15 #@email: forgerui@gmail.com 记录一些标准规范.让自己的编码更可读,更可维护. ...

  9. MERGE_SORT归并排序C++实现

    大家好,我是小鸭酱,博客地址为:http://www.cnblogs.com/xiaoyajiang 以下实现归并排序,第一部分含有哨兵(算法来自<算法导论>),第二部分不含哨兵 第一部分 ...

随机推荐

  1. 热修复设计之AOT/JIT&dexopt 与 dex2oat (一)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680本篇文章将先从AOT/JIT&dexopt 与 dex2o ...

  2. exsi 回收虚拟机磁盘

    用客户端登陆服务端,用下面命令停止虚拟机机器 esxcli vm process list    用如下命令关闭一台虚拟机: esxcli vm process kill --type=[soft,h ...

  3. k8s 组件介绍-API Server

    API Server简介 k8s API Server提供了k8s各类资源对象(pod,RC,Service等)的增删改查及watch等HTTP Rest接口,是整个系统的数据总线和数据中心. kub ...

  4. 【数据驱动】python之mysql的操作

    1.准备工作 在本篇中,我们使用python版本为python3.7.在python3中,连接mysql数据库我们需要使用pymysql这个第三方库.我们可以直接使用pip命令来安装,安装的命令为: ...

  5. [fw]awk求和

    suse11:~ # cat tmp.lst 4096 4 4096 4 4096 2 4096 4 8192 1 8192 4 8192 4 8192 4 8192 4 8192 4 8192 4 ...

  6. poj2752Seek the Name, Seek the Fame(next数组)

    题目传送门 Seek the Name, Seek the Fame Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 2439 ...

  7. K8S入门系列之必备扩展组件--> coredns(四)

    摘要: 集群其他组件全部完成后我们应当部署集群 DNS 使 service 等能够正常解析,1.11版本coredns已经取代kube-dns成为集群默认dns. https://github.com ...

  8. oracle中Varchar2和nvarchar2的区别

    在oracle 11g下测试了下varchar2与nvarchar2这两种类型,网上有很多关于这两种类型的区别的帖子,我还是自己测试了下. varchar2(size type),size最大为400 ...

  9. emqtt 分布集群及节点桥接搭建

    目录 分布集群 emq@s1.emqtt.io 节点设置 emq@s2.emqtt.io 节点设置 节点加入集群 节点退出集群 节点发现与自动集群 manual 手动创建集群 基于 static 节点 ...

  10. Primeng UI框架ionic3 中下拉选择插件p-dropdown 插件的使用方法

    1.html引入: <p-dropdown float-right [options]="sortOption" [(ngModel)]="sortNow" ...