第31章 数论算法:元素的幂以及模取幂

元素的幂:

在这里介绍求元素的幂X^n(X和n均为非负整数)的两种算法,一个是递归求解,另外一个是用反复平方法

递归求解:

当我们计算X^n时,当n=0,结果为1,这可以看做递归的基准情况,当n为偶数时,X^n=(X^2)^(N/2),当n是基数时,X^n=(X^2)^((n-1)/2)*X。代码如下:

bool isEven(unsigned int n)
{
        if(n%2==0) return true;
        else return false;
}
unsigned long pow(unsigned long x,unsigned int n)
{
        if(n==0) return 1;//基准情况
        if(isEven(n))   return pow(x*x,n/2);
        else return pow(x*x,n/2)*x;
}

不难得出,递归求解元素幂的时间复杂度为O(log n).

反复平方法:

我们是要求X^n,假设n可以用二进制表述出来,即n(k-1)…n(0)(n(i)=0或1),则n=2^(k-1)* n(k-1)+…+2^0* n(0);
这样的话,X^n=X^(2^0* n(0))* X^(2^1* n(1))…. *X^(2^k n(k))
我们迭代k次,即可得出X^n。不难得出k=O(log n),所以反复平方法的时间复杂度为O(log n)。代码如下:

unsigned long pow(unsigned long x,unsigned int n)
{
        unsigned long ret=1;
        unsigned long tmp=x;

        while(n!=0){
                if(n%2!=0)
                        ret*=tmp;
                tmp=tmp*tmp;
                n/=2;
        }

        return ret;
}

模取幂:

模取幂是计算(a^b)%c这类问题(a,b 为非负整数,c为正整数),在这里介绍三种计算模取幂的三种算法。

第一种算法:

模运算具有这样的性质:(m*n)%d= ((m%d)*n)%d
所以a^b%c可写成((((((1*a)%c)*a)%c)*a)%c…*a)%c(有b个a)。因此依据这个等式,可以写成如下代码:

unsigned long  mod_1(unsigned long a, unsigned long b, unsigned long c)
{
        unsigned long ret=1;

        while(b--)
                ret=(ret*a)%c;

        return ret;
}

第二种算法:

模运算除了上面说的具有(m*n)%d= ((m%d)*n)%d这样的性质外,还具有这样的性质:

N=N1N2N3...Nn,(N mod m)=[1(N1 mod m)(N2 mod m)(N3 mod m)...(Nn mod m)] mod m

把上面两个性质结合在一起的话,N mod m可以写成如下形式:
(Nmodm)=((((((1)(N1 mod m)) mod m(N2 mod m))) mod m(N3 mod m)) mod m...(Nn mod m)) mod m

并且
if Ni=Ni1Ni1,(Ni mod m)={[Ni1 mod m][Ni1 mod m]} mod m

当我们计算a^b%c时,b可以写成如下的形式:
b=p(0)*2^0+ p(1)*2^1+…p(i)*2^i+…+p(n-1)*2^n-1 (p(i)=0 or 1)

则a^b可以写成如下形式:
a^b=a^(p(0) * 2^0))* ..* a^(p(i) * 2^i) * … * a^(p(n-1)*2^n-1)。因此求解a^b%c的代码可以写成如下形式:

unsigned long mod_2(unsigned long a, unsigned long b, unsigned long c)
{
        unsigned long ret=1;
        unsigned long tmp=a%c;

        while(b!=0){
                if(b%2!=0)
                        ret=(ret*tmp)%c;
                b/=2;
                tmp=(tmp*tmp)%c;
        }

        return ret;
}

第三种算法:

第三种算法也就是第二种算法的递归版本,代码如下:

unsigned long mod_2Recursive(unsigned long a,unsigned long b,unsigned long c)
{
        if(b==1)
                return a%c;

        unsigned long tmp=mod_2Recursive(a,b/2,c);
        unsigned long ret=(tmp*tmp)%c;
        if(b%2==1)
                ret=(ret*a)%c;

        return ret;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值