C++学习(24)

1.下列程序共调用x(int n)有 18次。

#include<iostream>
using namespacestd;
int cnt=0;
       int x(int n) {
       cnt++;
       if(n<=3)
              {
                     return 1;   
              }
       else
              {
              return  x(n-2)+x(n-4)+1;}
       }
int main() {
 
       x(x(8));
       cout<<cnt;
       return 0;
}

2. 

#include<iostream>
using namespacestd;
 
int main() {
       int a[]={2,4,6,8,10},*p,**k;
       p=a;
       cout<<p<<""<<*p<<endl;
       k=&p;
       cout<<*(p++)<<endl;
       cout<<k<<""<<*k<<" "<<**k<<endl;
       return 0;
}

3.

#include<iostream>
#include<string.h>
using namespacestd;
 
int main() {
       int a[][3]={{1},{3,2},{4,5,6},{0}};
       cout<<sizeof(a);
       return 0;
}
 


4.两个等价线程并发执行下列程序,a为全局变量,初始为0,假设printf++--操作都是原子性的,则输出肯定不是哪个?

 void foo() {
       if(a<=0) {
              a++;
       }
       else {
              a--;
       }
       printf("%d",a);
}


a有关的语句有3个:a<=0,判断语句,从内存取值,不写回内存;a++/a--,从内存取值,有对a的赋值,结果要写回内存;printf打印a,要从内存取值。

1)、线程P1执行完foo(),线程P2再执行foo()。结果是10

2)、线程P1从内存取出a=0,执行判断语句后等待;线程P2从内存取出a=0,执行判断语句后等待;线程P1再执行a++a变为1,写回内存,等待;线程P2从内存取出a=1,再执行a++a变为2,写回内存,等待;线程P1执行printf,输出2,线程P2执行printf,输出2。结果是22

3)、线程P1从内存取出a=0,执行判断语句后等待;线程P2从内存取出a=0,执行判断语句后等待;线程P1再执行a++a变为1,写回内存,继续执行printf,输出1,等待;线程P2从内存取出a=1,再执行a++a变为2,写回内存,继续执行printf,输出2。结果是12

4)、还有种可能是00。但不会是01

 

分析二:        

原子操作指的是这个过程或者直白点说,这句函数不会被中断。因此printf++--这三个操作之间排列两个线程就行。

A、如果要第一个值输出0,线程1进入判断并实现++,线程2此时进入判断实现--a=0,两个线程下一句都是print,结果将是00;(考虑到线程并发和内存抢占的情况,暂不考虑一个线程print0以后还是这个线程执行一遍程序打印出1,而是由另一个线程来print0

B、线程1判断,执行++,打印1,线程2判断,执行--,打印0,结果10

C、线程1进入判断,线程2进入判断,线程1执行++,打印1,线程2执行++,打印2,结果12

D、线程1进入判断,线程2进入判断,线程1执行++,线程2执行++,各自打印出2,结果22

 


5. 求最大公约数的最常用的算法是欧几里得算法,也称为辗转相除法.点击打开链接

问题定义为求ij的最大公约数gcd(i,j),其中ij是整数,不妨设i>j.

算法可以递归的表示:

1.如果j能整除i,那么gcd(i,j)=j;

2.j不能整除i,r=i%j,那么gcd(i,j)=gcd(j,r).

使用C语言实现:

int gcd(int i, intj) {     int r = i % j;     return r == 0 ? j : gcd(j, r);}正确性分析:

算法的步骤1,显然成立(最大公约数定义).关键是要证明步骤2.

dij的最大公约数,

那么i=md,j=nd,mn互质(否则d不是最大公约数).

r=i%j可以得到i=kj+r,k=m/n,k1(我们前面假设过i>j).

i=md,j=nd代入得到

md=knd+r

那么

r=(m-kn)d

m-knm也是互质的.

所以得到djr的最大公约数.

 

时间复杂度分析:

逆着看该算法,最后的余数是0,倒数第二次余数是d,倒数第三次是kd,k>1…

由于组成了一个数列,{0,d,kd,nkd+d,…}

数列的n项加上n+1项,比n+2项要小,所以比斐波纳契数列增长的要快.

我们已知斐波纳契数列增长速度是指数,那么待分析的数列也是指数增长.

设欧几里得算法需要k次,那么j=O(2^k),则k=O(lg j).

所以欧几里得算法求最大公约数的时间复杂度是对数量级的,速度非常快.

 

7. 以下代码会调用多少次拷贝构造函数?

Widget f(Widget u){
       Widget v(u);
       Widget w=v;
       return w;
}
main() {
       Widget x;
       Widget y=f(f(x));
}

分析:y=f(f(x)) 有两层 f() ,为了说明过程,把里面的一层标明为 f_1 ,外面一层标明为 f_2 。则 7 次调用分别是:

x -> f_1 u

f_1 u->f_1 v

f_1 v-> f_1 w

f_1 w->f_2 u

f_2 u->f_2 v

f_2 v->f_2 w

f_2 w->y

 

分析二:

1),可能有朋友对Widget w=v;有疑惑。
这里的 =号,是v去初始化w。对象的初始化当然是去调用构造函数了,而不是重载的=运算符。
如果,
Widget w;
w=v;
那么此时=号调用的是Widget operator=(constWidget&)赋值函数 因为 Widget w;已经把w初始化过了。
2),单个的 f(x) 执行时,会调用4次copy constructer.
本题中,f(x)的返回值直接又作了f()的参数。f(f(x))的返回值又去初始化y,共7次

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值