24/05/16(1115) 函数递归和数组概念回顾

                                函数递归

编写一个函数不允许创建临时变量,求字符串长度.

(字符串是一种特殊的字符数组.必须以 \0 结尾)C语言设计中最大的败笔,就是这个字符串 \0 的设定.

字符串长度:不计算 \0

字符串数组长度(占内存的字节数):算 \0

先写一个创建临时变量的:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//void printNum(unsigned int num){
//    if (num > 9){
//        printNum(num / 10);
//    }
//    printf("%d ", num % 10);
//}


int Strlen(char str[]){
    int i = 0;
    //for (; str[1] != '\0'; i++);
    while (str[i] != '\0'){
        i++;
    }
    return i;
}

int main(){
    char str[] = "hehe";
    int len = Strlen(str);
    printf("%d\n", len);

    system("pause");
    return 0;
}

如果遇到不让创建临时变量/不让使用循环 => 递归

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//void printNum(unsigned int num){
//    if (num > 9){
//        printNum(num / 10);
//    }
//    printf("%d ", num % 10);
//}


//int Strlen(char str[]){
//    int i = 0;
//    //for (; str[1] != '\0'; i++);
//    while (str[i] != '\0'){
//        i++;
//    }
//    return i;
//}

int Strlen(char str[]){
    if (str[0] == '\0'){
        return 0;
    }
    return 1 + Strlen(str + 1);
}

int main(){
    char str[] = "abcd";
    int len = Strlen(str);
    printf("%d\n", len);

    system("pause");
    return 0;
}

 ......

递归程序的特点:

1.一定都有递归结束条件.

2.每次递归之后,都会距离这个结束条件更近(收敛).

写递归程序往往就是进行问题的不断拆分.

用递归求 n 的阶乘 3! = 3 * 2 * 1

int ji(unsigned int n){
    if (n == 1){
        return 1;
    }
    return n * ji(n - 1);
}

int main(){
    
    printf("%d\n", ji(5));

    system("pause");
    return 0;
}

求第n个斐波那契数

生兔子:初始情况下有一对小兔子

第一个月,还是一对兔子

第二个月,还是一对兔子

第三个月,两对兔子(一对成年,一对幼年)小兔子第三个月成年生下一对小兔子.

第n个月的时候当前有多少对兔子?

1 1 2 3 5 8 13 21 24(任何一项都是前两项之和)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//void printNum(unsigned int num){
//    if (num > 9){
//        printNum(num / 10);
//    }
//    printf("%d ", num % 10);
//}


//int Strlen(char str[]){
//    int i = 0;
//    //for (; str[1] != '\0'; i++);
//    while (str[i] != '\0'){
//        i++;
//    }
//    return i;
//}

//int Strlen(char str[]){
//    if (str[0] == '\0'){
//        return 0;
//    }
//    return 1 + Strlen(str + 1);
//}

//问题拆分
//n! => n * n-1!
//n == 1 1! => 1

int ji(unsigned int n){
    if (n == 1){
        return 1;
    }
    return n * ji(n - 1);
}

int Fib(int n){
    if (n == 1){
        return 1;
    }
    if (n == 2){
        return 1;
    }
    return Fib(n - 1) + Fib(n - 2);
}

int main(){
    
    printf("%d\n", Fib(7));

    system("pause");
    return 0;
}

计算时间非常长,数字太大了.使用非递归版本避免重复运算.

//使用非递归可以通过其他变量保存中间结果避免重复运算
int Fib(int n){
    if(n == 1){
        return 1;
    }
    if(n == 2){
        return 1;
    }
    //当前项的前一项
    int last1 = 1;
    //当前项的前两项
    int last2 = 1;
    //当前项
    int cur = 0;
    for (int i = 3; i <= n; i++){
        cur = last2 + last1;
        last2 = last1;
        last1 = cur;
    }
    return cur;
}

int main(){
    
    printf("%d\n", Fib(3));
    
    system("pause");
    return 0;
}

Fib 函数第二个版本为啥速度变快了?

通过两个变量保存了中间结果,避免重复运算.和 递归 非递归 没有直接的关系.

栈空间多大 字节为单位.

VS默认程度栈空间大小大概就是1M,它是可配置的.

我们当前讨论的栈,是操作系统中的栈.和数据结构中的栈不一样.他俩的堆也不一样.

函数调用也是有开销的,只不过这个开销比较小而一般忽略不计.但递归的调用非常频繁而不能忽略不计,所以平时编程中一般选择非递归函数.

 数组

1.一维数组的创建和初始化

2.一维数组的使用

3.一维数组在内存中的存储

4.二维数组的创建和初始化

5.二维数组的使用

6.二维数组在内存中的存储

7.数组作为函数参数

8.数组的应用实:三子棋 扫雷

一维数组的创建和初始化:

数组是批量创建一组相同类型(C语言里是这么要求)的变量.

type_t  arr_name [const_n];

数组定义的时候,[]中的表达式也不一定非得是常量表达式.

在C89中要求必须是常量.在C99中允许使用变量表达式.

初始化 和 赋值 不一样.

在创建变量的同时设定值 这叫初始化.

变量已经创建完了,再去设定值,这叫赋值.

普通的数组只能使用{}初始化.字符数组处理使用{}还可以使用""的形式初始化,相当于在初始化一个字符串.

int main(){
    int arr1[] = { 'a', 'b', 'c' };
    int arr2[] = "abc";
    printf("%d\n", sizeof(arr1));
    printf("%d\n", sizeof(arr2));
    system("pause");
    return 0;
}

arr1 是3;arr2 是4

像arr1这个数组里面没有 \0 就不是一个字符串.不该对他使用strlen.如果强行使用,最终结果不可预期.这叫做未定义行为.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值