函数递归

程序调用自身的编程技巧称为递归;主要思考方式在于:把大事化小

递归的两个必要条件

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这样会有多余的计算过程,因为它会一个一个比较

 

数组名地址与数组首元素地址一样

(有两个例外

  1. sizeof(数组名)此时计算的是整个数组的大小,单位是字节
  2. &数组名,数组名代整个数组,&数组名,取出的是整个数组的地址,虽然显示的是首元素地址)

首元素地址下标为0