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);
______________________________________________________________________
}