练习
1、计算n的阶乘。n!=1×2×3×......×(n-1)×n
int main(){
int i=0;
int n=0;
scanf("%d",&n);//n为想要输入的值,这时就需要输入函数scanf
int ret=1; //ret不能为0,若为0,0不管乘任何数都为0
for(i=1;i<=n;i++){
ret=ret*i;
}
printf("ret=%d\n",ret);
return 0;
}
如:输入5,则ret=120。
但要注意,若n=100时,则会出现错误,因为100的阶乘在整形可能放不下;所以这串代码是在不考虑溢出的情况下运行的。
2、计算1!+2!+3!+......+10!
当我们想求出几个阶乘之和时,正确写法如下:
int main(){
int i=0;
int n=0;
int ret=1; //对应外围的循环,不影响内部的
int sum=0;
for(n=1;n<10;n++){
for(i=1;i<=n;i++){
ret=ret*i;
}
sum=sum+ret;
}
printf("sum=%d\n",sum);
return 0;
}
这里要加上ret=1;才会得出正确答案。
假设我们要算1!+2!+3!阶乘的和——
n<=3时,打印结果为15;但我们知道1!+2!+3!=9
这是因为,当n=1时,ret=1×1;当n=2时,ret=1×1×2;当n=3时,ret=2×1×2×3=12;
因为ret没有被初始化,所以会累计下来。
这个代码麻烦在它将每个阶乘都算一遍;其实,只要算出前面的阶乘在乘后一个阶乘数既可。
如:算出4!的阶乘后,求5!的阶乘,只需4!的阶乘再乘5既可。如——5!=4!×5
所以优化后的代码:
int main(){
int i=0;
int n=0;
int ret=1;
int sum=0;
for(n=1;n<=3;n++){
ret=ret*i;
sum=sum+ret;
}
printf("sum=%d\n",sum);
return 0;
}
3、在一个有序数组中查找具体的某个数字n。
编写——
int binsearch(int x,intv[],int n);
功能:在v[0]<=v[1]<=v[2]<=......<=v[n-1]的数组中查找x。
int main(){
int arr[]={1,2,3,4,5,6,7,8,9,10}
int k=7;
int i=0;
int sz=sizeof(arr)/sizeof(arr[0]);//计算数组元素个数
for(i=0;i<sz;i++){
if(k==arr[i]){
printf("找到了,下标是:%d\n",i);
break;
}
}
if(i==sz)
printf("找不到\n");
return 0;
}
以上代码我们发现这样查找不太高效。
因为如果你要查较大的数,这样,最坏的情况下,你要找n次。
比如一双鞋子的价格·范围在1~500之间,如果按第一种方法,就得从1开始往后查询,直至找到想要的数。(这样就比较麻烦)
因为我们知道一双鞋子不可能价格很低,所以我们会来猜一个数(一般从中间数开始)
250~500?如果说250低,则往上猜。
350~500?如果说350过高,这样将价格锁定到250~350之间。
250~350相较于1~500而言,范围就小了,更接近准确值了。
回到上述问题,1~10也是同样,如果想找7;就假设从5开始~8结束
而这种方法又叫——折半查找算法或二分查找算法
对比12345678910(从前往后的算法复杂度是n);这种算法只需4次,算法复杂度是㏒₂ⁿ【如:㏒₂ⁿ的n为10的话,整体值为约等于3~4之间,接近4,所以约为4】
1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7 8 9 ——下标
算0~9的中间值为4,而下标4对应5,又因5<7;所以下标4向前一位5~9中间值为7,下标7→8,所以锁定范围6~8
以上是查找次数。
用折半查找算法的话只需㏒₂ⁿ次,按顺序的话要n次。
所以代码为:
int main(){
int arr[]={1,2,3,4,5,6,7,8,9,10}
int k=7;
int sz=sizeof(arr)/sizeof(arr[0]);//计算数组元素个数
int left=0;//左下标
int right=sz-1;//右下标
while(left<right){
int mid=(left+right)/2;
if(arr[mid]>k){
right=mid-1;
}
else if(arr[mid]<k){
left=mid+1;
}
else{
printf("找到了,下标是:%d\n",mid);
break;
}
}
if(left>right)
printf("找不到\n");
return 0;
}
因为如果数组里没有想要的数,那计算下标的时候会可能交错。
1 2 3 4 5 6 8 9 10 11
0 1 2 3 4 5 6 7 8 9
5~9:7
5~6:5.1
6~5:
7~4:
因此要有left<=right。
【注:若有相同的数时,只会优先打印最前的数。就比如数组中两个数值7】
以上是二分查找算法的写法,二分查找算法可以用函数的方式写。
4、编写代码,演示多个字符从两端移动,向中间汇聚。
如:
welcome to bit ! ! ! ! ! !
####### ## ########
w###........................#!
we#..........................#!!
.......
达到这样的效果——把第一块空间的数组从两端开始依次往下遮盖。
那如何实现呢?——这其实要用到上面所学的二分查找算法。
left =0; right=n;
left++; right--;
char arr1[ ]="welcome to bit ! ! !"
char arr2[ ]="###############"
【注:字符串中包括一个“\0”。】
元素个数不给定,拿后面字符串来初始化它,用字符串来判断数组开辟多大空间。
左下标:int left=0;
右下标:int right =sizeof(arr1)/sizeof(arr[0]-2);这里要减2,不能减1.
假设char arr[ ]="abc";
这个数组其实是有4个元素。
a b c \0
0 1 2 3 ——对应下标
【注意:\0并不是上一个数组的“!”,“!”后还有一个“\0”。】
“c的下标是2,然计算这个数组的元素个数会是4;而4-1=3,又因下标3对应的是\0,所以要4-2才对。
【注:以上大家可以试着用这种方法去敲出代码。】
这里还可换另一种方法:
将sizeof换成strlen。【注;strlen函数求字符串长度,不包括“\0”。】
如:
int right=strlen(arr1)-1;
往下思考:
arr1——"welcome to bit!!!"
arr2——"#############"
可以用:
arr2[left]=arr1[left];
arr2[right]=arr1[right];
赋值给它。
总结得出——
#include<stdio.h>
#include<string.h>
#include<windows.h>
int main(){
char arr1[]="welcome to bit!!!";
char arr2[]="#################";
int left=0;
int right=strlen(arr)-1;
while(left<=right){
arr2[left]=arr1[left];
arr2[right]=arr1[right];
printf("%s\n",arr2);
sleep(1000);//单位是毫秒,表示休息间隔1000毫秒,也就是1秒。
left++;
right++;
}
printf("%s\n",arr2);//循环外添加,要想保留的话得加上。
return 0;
}
sleep函数——这样打印出来就有了时间递进效果,不然会很快闪现出来。
这串代码还可以用上system函数——
system("cls");
这个会清空屏幕内容。
system函数用来执行系统命令。
cls——清空屏幕。
但要主要用上此函数要引用对应头文件——#include<stdlib.h>
5、编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则提示登录成功,如果三次均输入错误,则退出程序。)
#include<stdio.h>
#include<string.h>
int main(){
int i=0;
char password[20]={0};
for(i=0;i<3;i++){
printf("请输入密码:>");
scanf("%s",password);
if(strcmp(password,"123456"==0){
printf("登录成功\n");
break;
}
}
else{
printf("密码错误\n");
}
if(i==3)
printf("三次密码均错误,退出程序\n");
return 0;
}
【注:==双等号不能用来比较两个字符串是否相等,应该使用一个库函数strcmp。】
strcmp库函数比较password与123456如果相等,则会返回一个值0;如果第一个字符串大于第二个,会返回一个大于0的数;小于的话,则相反。
strcmp函数对应的头文件是——#include<string.h>