分治法(基础版)

1.合(归)并排序

将待排序序列分解成规模大致相等的子序列,直到子序列中所含元素个数为1;单个元素本身有序,此时进行合并最后得到完整有序序列。
数组A[]表示原始序列

合并操作

void Merge(int A[],int low,int mid,int high)
{ //A[low:mid]与A[mid+1:high]为两个待排序合并序列
    int *B=new int[high-low+1]; //B存放排序合并后的辅助数组
    int i=low,j=mid+1,k=0;
    while(i<=mid&&j<=high)
    {
        if(A[i]<=A[j])   B[k++]=A[i++];
        else    B[k++]=A[j++];
    }
    while(i<=mid) B[k++]=A[i++]; //处理A[low:mid]剩余元素
    while(j<=high) B[k++]=A[j++]; //处理A[mid+1:high]剩余元素
    for(i=low,k=0;i<=high;i++) //将排序合并好的序列B复制到原来的序列A中
    A[i]=B[k++];
    delete B;
}

分解、排序合并

void MergeSort(int A[],int low,int high)
{
    if(low<high)
    {
        int mid=(low+high)/2;
        MergeSort(A,low,mid);
        MergeSort(A,mid+1,high);
        Merge(A,low,mid,high);
    }
}

输入初始无序序列并合并排序输出结果

int main()
{  int n; //元素个数
   cin>>n;
   for(int i=0;i<n;i++)
     cin>>A[i];
   MergeSort(A,0,n-1);
   cout<<"合并排序结果"<<endl;
   for(int i=0;i<n;i++)
      cout<<A[i]<<" ";
}

2.大整数乘法

在计算机上处理一些大数据相乘时,由于计算机硬件的限制,不能直接进行相乘得到想要的结果。可以将一个大的整数乘法分而治之,将大问题变成小问题,变成简单的小数乘法再进行合并,从而解决上述问题。
;‘’;‘

大整数的存储结构

#define M 100
typedef struct Node
{
    int s[M]; //存储大整数各位数
    int l; //字符串长度
    int c; //次幂
}Node;

大致框架:初始化(以字符串输入转为数字,倒序存储在s[]数组中);
调用函数分治;输出结果

int main()
{
    char sa[M];
    char sb[M];
    Node a,b,ans;
    cin>>sa;
    cin>>sb;
    a.l=strlen(sa);
    b.l=strlen(sb);
    int z=0,i;
    for(i=a.l-1;i>=0;i--) //倒序存储
    a.s[z++]=sa[i]-'0';
    a.c=0;
    z=0;
    for(i=b.l-1;i>=0;i--) //倒序存储
    b.s[z++]=sb[i]-'0';
    b.c=0;
    mul(a,b,ans); //调用函数分治ans存储最终结果
    for(i=ans.l-1;i>=0;i--) //输出结果
    cout<<ans.s[i];
}

分解(划分函数)

void cp(Node src,Node &des,int st,int l) //划分函数
{
    //src:待分解数 des:分解好的数 st:待分解的初始分解位置(开始取数的位置) l:取数长度
    int i,j;
    for(i=st,j=0;i<st+l;i++,j++)
    {
        des.s[j]=src.s[i];
    }
    des.l=l;
    des.c=st+src.c;
}

乘法运算:利用划分函数不断将大数分解,直到有一个乘数为1时停止,让两数相乘并记录回溯过程

void mul(Node &pa,Node &pb,Node &ans)
{
    //pa,pb表示还需继续分解或分解完待乘的两个数,ans表示乘积结果
    int ma=pa.l/2;
    int mb=pb.l/2;
    if(!ma||!mb) //两个数有一个位数为1
    {
        if(!ma) //pa为一位数,pa、pb交换,保证pa的长度>=pb的长度
        {
            Node temp;
            temp=pa;
            pa=pb;
            pb=temp;
        } //交换后b的长度为1
        ans.c=pa.c+pb.c; //结果的次幂等于两乘数次幂之和
        int w=pb.s[0]; //一位数的数字
        int i,cc=0; //进位
        for(i=0;i<pa.l;i++)
        {
            ans.s[i]=(w*pa.s[i]+cc)%10; //存储相乘结果的个位,十位做进位处理
            cc=(w*pa.s[i]+cc)/10; //进位
        }
        if(cc) //最后还有超出位数的进位
        ans.s[i++]=cc;
        ans.l=i;
    }
}

合并相加:将所有的得到的乘法运算结果相加合并

void add(Node &pa,Node &pb,Node &ans)
{
    // pa,pb表示待相加合并的两个数,ans表示相加合并结果
    if(pa.c<pb.c) //交换保证pa的次幂大
    {
        Node temp;
        temp=pa;
        pa=pb;
        pb=temp;
    }
    ans.c=pb.c; //相加结果的次幂为两数中小的次幂
    int cc=0; //初始化进位数字
    int k=pa.c-pb.c; //k为pa左侧需补零的个数
    int alen=pa.l+pa.c;
    int blen=pb.l+pb.c;
    int len=max(alen,blen); //取pa,pb长度最大值为做加法的总位数
    len=len-pb.c; //结果长度为pa、pb中总长度的最大值减去最低次幂
    int i,ta,tb; //ta、tb:相加后pa、pb对应位上的数
    for(i=0;i<len;i++)
    {
        if(i<k)  
           ta=0; //a左侧补零
        else   
           ta=pa.s[i-k]; //i=k时补零结束,从pa数组中第0位开始取数字
        if(i<pb.l)  
           tb=pb.s[i]; //从pb数组中第0位开始取数字
        else
           tb=0; //pb先取完,pb右侧补零
        if(i>=pa.l+k) //pa先取完,pa右侧补零
           ta=0;
        ans.s[i]=(ta+tb+cc)%10;
        cc=(ta+tb+cc)/10;
    }
    if(cc) //最高位依旧有进位
    ans.s[i++]=cc;
    ans.l=i;
}

利用以上三个函数进行分治:在mul函数中调用分治回溯

void mul(Node &pa,Node &pb,Node &ans)
{
    //pa,pb表示还需继续分解或分解完待乘的两个数,ans表示乘积结果
    int ma=pa.l/2;
    int mb=pb.l/2;
    Node ah,al,bh,bl;
    Node t1,t2,t3,t4,z;
    if(!ma||!mb) //两个数有一个位数为1
    {
        if(!ma) //pa为一位数,pa、pb交换,保证pa的长度>=pb的长度
        {
            Node temp;
            temp=pa;
            pa=pb;
            pb=temp;
        } //交换后b的长度为1
        ans.c=pa.c+pb.c; //结果的次幂等于两乘数次幂之和
        int w=pb.s[0]; //一位数的数字
        int i,cc=0; //进位
        for(i=0;i<pa.l;i++)
        {
            ans.s[i]=(w*pa.s[i]+cc)%10; //存储相乘结果的个位,十位做进位处理
            cc=(w*pa.s[i]+cc)/10; //进位
        }
        if(cc) //最后还有超出位数的进位
        ans.s[i++]=cc;
        ans.l=i;
        return ;
    }
 ——————————————————————————————————————————————————————————————————————
   //分治核心
    cp(pa,ah,ma,pa.l-ma); //分解
    cp(pa,al,0,ma);
    cp(pb,bh,mb,pb.l-mb);
    cp(pb,bl,0,mb);
                     //相乘
    mul(ah,bh,t1);
    mul(ah,bl,t2);
    mul(al,bh,t3);
    mul(al,bl,t4);
                    //相加合并
    add(t3,t4,ans);
    add(t2,ans,z);
    add(t1,z,ans);
 ______________________________________________________________________
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值