函数递归
程序调用自身的编程技巧称为递归;主要思考方式在于:把大事化小
递归的两个必要条件
1.存在限制条件,当满足这个限制条件的时候,递归便不再继续
2.每次递归调用后越来越接近这个限制条件
常见错误:
栈溢出Stack overflow即栈区里的可以被占用的空间被占满了
引出内存分为:
栈区(放局部变量与函数形参)、堆区(动态开辟的内存)、静态区(全局变量与static修饰的变量)
程序员的“知乎”网站:https://stackoverflow.com/
写一个程序,任意输入一正整数,依次分数位输出
void print(int n)
{
if(n>9)
{
printf(n/10); //相当于循环找到最后一位,再依次打印头一位解循环出去
}
priintf("%d ",n%10);
}
int main()
{
unsigned int num=0; //unsigned指无符号
scanf("%d",&num);
print(num);
return 0;
}
假如输入23542
即输出2 3 5 4 2
编写函数不允许创建临时变量,求字符串的长度
int my_strlen(char* str)
{
if(*str!=’\0’) //这条是限制条件
return 1+my_strlen(str+1); //即先从左往右扫描字符个数生成一个一个的套,再从最后的返回值0依次加1开
始解套
//str+1可以让地址从左边第一个字符往右依次扫描下一个字符
else
return 0;
}
int main()
{
char arr[]="bit";
int len=my_strlen(arr);
printf("len=%d\n",len);
return 0;
}
递归与迭代
求n的阶乘(不考虑溢出)
int Fac(int n)
{
if(n<=1)
return 1;
else
return n*Fac(n-1);
}
int main()
{
int n=0;
int ret=0;
scanf("%d",&n);
ret=Fac(n);
printf("%d\n",ret);
return 0;
}
描述第n个斐波那契数(从1,1开始之后每个数等于前两个数之和)
运用TDD方法(测试驱动开发)即先想怎么用,再想怎么实现这个函数,先构造主体,再细化分支
递归解决(会发现n大了以后,会出现大量重复的计算,效率下降,不好)
int Fid(int n)
{
if(n-2)
return 1;
else
retun Fib(n-1)+Fib(n-2);
}
int main()
{
int n=0;
int ret=0;
scanf("%d",&n);
ret=Fib(n);
printf("ret=%d\n",ret);
reeturn 0;
}
循环解决
int Fib(int n) //注意这里n为整型,有固定大小,要是后面所需运算能力过大会使答案不对
{
int a=1,b=1,c=1;
while(n>2)
{
c=a+b;
a=b;
b=c;
n--;
}
return c;
}
int main()
{
int n=0;
int ret=0;
scanf("%d",&n);
ret=Fib(n);
printf("ret=%d\n",ret);
reeturn 0;
}
自主研究:1.汉诺塔问题2.青蛙跳台阶问题
《剑指offor》67道笔试题记得做
数组
一维数组的创建和初始化
数组的创建
type_t arr_name [const_n]
元素类型 数组名 常量表达式,用来指定数组大小
int arr[10]={1,2,3}; //这样叫做不完全初始化,剩下的元素默认初始化为0
提醒:sizeof计算所占空间的大小,单位是字节(算\0)
strlen只能计算字符串长度(不算\0,要头文件 )
区分sizeof与strlen,以及字符串的初始化分别
char arr1[]=’abc’; //初始化为a b c \0
char arr2[]={‘a’,’b’,’c’}; //初始化为a b c
printf("%d\n",sizeof(aee1)); //sizeof是所占空间大小,因为有四个元素,所以是4
printf("%d\n",sizeof(aee2)); //同理为3
printf("%d\n",strlen(aee1)); //strlen计算字符串长度,是\0之前的元素,所以是3
printf("%d\n",strlen(aee2)); //此时strlen在后面找不到\0,所以是随机值
答案为
4
3
3
随机值
一维数组的使用
int main()
{
char arr[]="abcdef"; //[a][b][c][d][e][f][\0]
int i=0;
int len=strlen(arr); //用sizeof时记得i的初始值,以及它还有\0
for(i=0;i<len;i++)
{
printf("%c",arr[i]); //定义数组时不能用变量,但是这里是常变量,做下标用
}
return 0;
}
总结:
1.数组是使用下标来访问的,下标是从0开始
2.数组的大小可以通过计算得到
一维数组在内存中的存储
在数组的地址中
10进制 0-9
16进制 0-9 a b c d e f(a表示10,之后同理)
一维数组在内存中是连续存放的,从低地址0,1,2...到高地址6,7,8...
二维数组的创建与初始化
int arr[3][4]={1,2,3,4,5}; //1 2 3 4
5 0 0 0
0 0 0 0
从左往右顺序填充,之后默认为0
int arr[3][4]={{1,2,3},{4,5,6}}; //1 2 3 0
4 5 6 0
0 0 0 0
int arr[][]={1,2,3,4,5};
或者int arr[][]={{1,2,3},{4,5}}
或int arr[4][]={1,2,3,4}都是不可以的,
即列不能省略
二维数组的使用
通过下标(类似坐标系),存储的地址也是连续的
int main()
{
int arr[2][3]={1,2,3,4,5,6};
int i,j;
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
printf("%d\t",arr[i],[j]);
}
printf("\n");
}
数组作为函数参数
对arr从左到右排列升序
void bubble_sort(int arr[])
{
int i=0; //确定冒泡排序的趟数
for(i=0;i<sz-1;i++)
{ //每一趟冒泡排序
int flag=1; //假设这一趟要排列的数据已经有序
int j=0
for(j=0;j<sz-1-i;j++) // 控制趟数
{
if(arr[j]>arr[j+1])
{
int tmp=arr[j]; //冒泡排序内容,相邻两个数比较,将大的换位到后面
arr[j]=arr[j+1];
arr[j+1]=tmp;
flag=0; //本趟排列的数据其实不完全有序
}
}
if(flag==1)
break; //此处break跳出的是for循环,不是跳if
}
}
int main()
{
int arr[]={9,8,7,6,5,4,3,2,1,0};
int sz=sizeof(arr)/sizeof(arr[0]);
bubble_sort(arr);
return 0;
}
如果不加flag这样会有多余的计算过程,因为它会一个一个比较
数组名地址与数组首元素地址一样
(有两个例外
- sizeof(数组名)此时计算的是整个数组的大小,单位是字节
- &数组名,数组名代整个数组,&数组名,取出的是整个数组的地址,虽然显示的是首元素地址)
首元素地址下标为0