当前位置:   article > 正文

C语言学习笔记22/08/17_c语言中fac(n)

c语言中fac(n)
求n的阶乘。(不考虑溢出)
  1. //有一些功能:可以使用迭代的方式实现,也可以使用递归
  2. int Fac(int n)
  3. {
  4. if (n <= 1)
  5. return 1;
  6. else
  7. return n * Fac(n - 1);
  8. }
  9. int main()
  10. {
  11. int n = 0;
  12. scanf("%d", &n);
  13. int ret = Fac(n);
  14. printf("%d\n", ret);
  15. return 0;
  16. }

迭代

        对计算机特定程序中需要反复执行的子程序*(一组指令),进行一次重复,即重复执行程序中的循环,直到满足某条件为止,亦称为迭代。

求第 n 个斐波那契数。(不考虑溢出)
效率太低的代码
  1. int count = 0;
  2. //递归可以求解,但是效率太低
  3. int Fib(int n)
  4. {
  5. //统计第3个斐波那契数的计算机次数
  6. if (n == 3)
  7. count++;
  8. if(n <= 2)
  9. return 1;
  10. else
  11. return Fib(n - 1) + Fib(n - 2);
  12. }
  13. int main()
  14. {
  15. int n = 0;
  16. scanf("%d", &n);
  17. int ret = Fib(n);
  18. printf("%d\n", ret);
  19. printf("count = %d\n", count);
  20. return 0;
  21. }

        理论上假设int可以存无限大的数,求到100的阶乘也没有问题。而实际上要运行这段程序,必须要考虑溢出,因为溢出是客观存在的。代码显示为0本质还是因为溢出,一开始溢出的位数不多所以低位会显示一个数,溢出的多了,低位全是0了,所以会显示0。

用迭代的代码效率高

  1. int Fib(int n)
  2. {
  3. int a = 1;
  4. int b = 1;
  5. int c = 0;
  6. while (n > 2)
  7. {
  8. c = a + b;
  9. a = b;
  10. b = c;
  11. n--;
  12. }
  13. return c;
  14. }
  15. int main()
  16. {
  17. int n = 0;
  18. scanf("%d", &n);
  19. int ret = Fib(n);
  20. printf("%d\n", ret);
  21. return 0;
  22. }

这个代码即使输入10000都能显示一个数字,但数字是错误的,因为要考虑溢出的问题。

斐波那契数列

        指的是这样一个数列:1,1,2,3,5,8,13,21,34,55,89...自然中的斐波那契数列,这个数列从第3项开始,每一项都等于前两项之和。

还有两个拓展问题上网搜的:

汉诺塔问题:

        源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?

解题思路:
首先,我们把三根金刚石柱子编号为A、B、C,其中编号为A的柱子摞着64片黄金圆盘,B、C为空柱,其中,C柱子作为最终摆放圆盘的柱

        首先,我们可以把64个黄金圆盘看作由两个部分组成 :第64个黄金圆盘和其上的63个黄金圆盘 ,这样我们只要把63个黄金圆盘组成的部分移到编号为B的柱子,然后就可以将第64个黄金圆盘移到C柱上。
        同样,我们也可以把编号为B柱上的63个黄金组成的部分再次分为两个部分,第63个黄金圆盘和其上的62个黄金圆盘,这时,借助编号为A的柱子,将62个黄金圆盘移到A柱上。然后,在把第63个黄金盘移到C柱上,依此类推,这样我们就可以将剩下的黄金圆盘都移到C柱上。
————————————————
版权声明:本文为CSDN博主「Rookie on the road」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45045399/article/details/100580330

青蛙跳台阶:
        一只青蛙可以一次跳 1 级台阶或一次跳 2 级台阶。问要跳上第 n 级台阶有多少种跳法?

解题思路
我们设台阶数位N;
当N=1时,当然只有1种跳法;
当N=2时,青蛙可以跳2次1层和跳1次2层;
当N=3时,当有3层台阶时,青蛙可以选择先跳1层,剩下2层台阶,所以此时就是有2层台阶时的跳法,有2种;当青蛙选择第一次跳2层台阶时,剩下1层台阶,此时有1层台阶时的跳法,所以3层台阶时的方法是:2层台阶的方法 + 1层台阶的方法。
当N=4时,具体跳法为: 1、先跳1层 若先跳1层,则剩下3层,接下来就是3层台阶的跳法。 2、先跳2层 若先跳2层,则剩下2层,接下俩就是2层台阶的跳法,所以4层台阶的方法为:3层台阶的方法+2层台阶的方法。

以此类推,当N=n时,n层台阶的方法为: n-1层台阶的方法+ n-2 层台阶的方法。

  1. int frog(int n)
  2. {
  3.    if(n == 1)
  4.    {
  5.       return 1;
  6.    }
  7.    if(n == 2)
  8.    {
  9.       return 2;
  10.    }
  11.    return frog(n-1) + frog(n-2);
  12. }
  13. int main()
  14. {
  15.    int n;
  16.    scanf("%d",&n);
  17.    int ways = frog(n);
  18.    printf("%d\n",ways);
  19.    return 0;
  20. }


————————————————
版权声明:本文为CSDN博主「RanieMiss」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_52606524/article/details/113037147

一维数组

        数组是一组相同类型元素的集合。

  1. type_t arr_name[const_n];
  2. //type_t:数组元素类型
  3. //arr_name:数组名
  4. //const_n:常量表达式,用来指定数组的大小

数组的初始化

        在创建数组的同时给数组的内容一些合理初始值(初始化)。

  1. int arr1[10] = {1,2,3};
  2. int arr2[] = {1,2,3,4};
  3. int arr3[5] = {12345};
  4. char arr4[3] = {'a',98, 'c'};
  5. char arr5[] = {'a','b','c'};
  6. char arr6[] = "abcdef";

strlen() 和sizeof的区别

        strlen() 是一个库函数,计算的是字符串的长度,并且只能作用于字符串,关注点在于字符串中是否有\0 ,计算的是字符串\0 之前的字符个数;
        sizeof 是一个操作符,sizeof 是用来计算变量所占空间大小的,任何类型都可以使用,只关注空间大小,不在乎内存中是否有\0, 而且单位是字节;

一维数组的使用:

  1. int main()
  2. {
  3. int arr[10] = { 0 };
  4. arr[4] = 5;//[] - 下标引用操作符
  5. printf("%d\n", arr[4]);
  6. return 0;
  7. }
5

  1. int main()
  2. {
  3. int arr[10] = { 0 };//数组的不完全初始化
  4. //计算数组的元素个数
  5. int sz = sizeof(arr) / sizeof(arr[0]);
  6. //对数组内容赋值,数组是使用下标来访问的,下标从0开始。所以:
  7. int i = 0;//做下标
  8. for (i = 0; i < 10; i++)//这里写10,好不好?
  9. {
  10. arr[i] = i;
  11. }
  12. //输出数组的内容
  13. for (i = 0; i < 10; ++i)
  14. {
  15. printf("%d ", arr[i]);
  16. }
  17. return 0;
  18. }

 1 2 3 4 5 6 7 8 9
  1. int main()
  2. {
  3. //printf("%x\n", 0x12);
  4. //printf("%p\n", 0x12);
  5. int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  6. int* p = arr;//数组名是数组首元素的地址
  7. int i = 0;
  8. for (i = 0; i < 10; i++)
  9. {
  10. printf("%d " , *p);
  11. p++;
  12. }
  13. return 0;
  14. }
1 2 3 4 5 6 7 8 9 10

  • 数组是使用下标来访问的,下标是从0开始的;
  • 数组的大小可通过计算得到;
  • 一维数组在内存中是连续存放的;
  • 数组随着下标的增长,地址由低到高变化

一堆数组在内存中的存储

  1. int main()
  2. {
  3. int arr[10] = { 0 };
  4. int i = 0;
  5. int sz = sizeof(arr) / sizeof(arr[0]);
  6. for (i = 0; i < sz; ++i)
  7. {
  8. printf("&arr[%d] = %p\n", i, &arr[i]);
  9. }
  10. return 0;
  11. }
  1. &arr[0] = 006CFE60
  2. &arr[1] = 006CFE64
  3. &arr[2] = 006CFE68
  4. &arr[3] = 006CFE6C
  5. &arr[4] = 006CFE70
  6. &arr[5] = 006CFE74
  7. &arr[6] = 006CFE78
  8. &arr[7] = 006CFE7C
  9. &arr[8] = 006CFE80
  10. &arr[9] = 006CFE84
仔细观察输出的结果,我们知道,随着数组下标的增长,元素的地址,也在有规律的递增。
由此可以得出结论: 数组在内存中是连续存放的。

 二维数组的创建和初始化

  1. //数组创建
  2. int arr[3][4];
  3. char arr[3][5];
  4. double arr[2][4];
  1. //数组初始化
  2. int arr[3][4] = {1,2,3,4};
  3. int arr[3][4] = {{1,2},{4,5}};
  4. int arr[][4] = {{2,3},{4,5}};//二维数组如果有初始化,行可以省略,列不能省略

二维数组的使用

        二维数组的使用也是通过下标的方式。

  1. int main()
  2. {
  3. int arr[3][4] = { 0 };
  4. int i = 0;
  5. for (i = 0; i < 3; i++)
  6. {
  7. int j = 0;
  8. for (j = 0; j < 4; j++)
  9. {
  10. arr[i][j] = i * 4 + j;
  11. }
  12. }
  13. for (i = 0; i < 3; i++)
  14. {
  15. int j = 0;
  16. for (j = 0; j < 4; j++)
  17. {
  18. printf("%d ", arr[i][j]);
  19. }
  20. }
  21. return 0;
  22. }
0 1 2 3 4 5 6 7 8 9 10 11

二维数组完全转换

  1. int main()
  2. {
  3. //初始化 - 创建的同时给赋值
  4. int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
  5. return 0;

监视窗口显示

二维数组不完全转换

  1. int main()
  2. {
  3. //初始化 - 创建的同时给赋值
  4. int arr[3] [4] = { 1,2,3,4,5,6,7 };
  5. return 0;
  6. }

监视窗口显示

二维数组里面用{}转换

  1. int main()
  2. {
  3. //初始化 - 创建的同时给赋值
  4. int arr[3][4] = { {1,2},{3,4},{4,5} };
  5. return 0;
  6. }

二维数组在内存中的存储

  1. int main()
  2. {
  3. int arr[3][4];
  4. int i = 0;
  5. for(i=0; i<3; i++)
  6. {
  7. int j = 0;
  8. for(j=0; j<4; j++)
  9. {
  10. printf("&arr[%d][%d] = %p\n", i, j,&arr[i][j]);
  11. }
  12. }
  13. return 0; }
  1. &arr[0][0] = 012FF798
  2. &arr[0][1] = 012FF79C
  3. &arr[0][2] = 012FF7A0
  4. &arr[0][3] = 012FF7A4
  5. &arr[1][0] = 012FF7A8
  6. &arr[1][1] = 012FF7AC
  7. &arr[1][2] = 012FF7B0
  8. &arr[1][3] = 012FF7B4
  9. &arr[2][0] = 012FF7B8
  10. &arr[2][1] = 012FF7BC
  11. &arr[2][2] = 012FF7C0
  12. &arr[2][3] = 012FF7C4
通过结果我们可以分析到,其实二维数组在内存中也是连续存储的。

数组越界

        数组的下标是有范围限制的。 数组的下规定是从0开始的,如果数组有 n 个元素,最后一个元素的下标就是 n-1 。 所以数组的下标如果小于0 ,或者大于 n-1 ,就是数组越界访问了,超出了数组合法空间的访问。
        C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的, 所以程序员写代码时,最好自己做越界的检查。 二维数组的行和列也可能存在越界。
  1. #include <stdio.h>
  2. int main()
  3. {
  4. int arr[10] = {1,2,3,4,5,6,7,8,9,10};
  5.    int i = 0;
  6.    for(i=0; i<=10; i++)
  7.   {
  8.        printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
  9.   }
  10. return 0;
  11. }
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. -858993460

数组作为函数参数
        往往我们在写代码的时候,会将数组作为参数传个函数。
数组名是什么?
        数组名是数组首元素的地址。

两个例外:

        sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组。

        &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。

  1. int main()
  2. {
  3. int arr[10] = { 1,2,3,4,5 };
  4. printf("%p\n", arr);
  5. printf("%p\n", &arr[0]);
  6. printf("%d\n", *arr);
  7. //输出结果
  8. return 0;
  9. }
  1. 008FFC40
  2. 008FFC40
  3. 1

冒泡排序的思想
        两两相邻的元素进行比较,并且可能的话需要交换!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/在线问答5/article/detail/850134
推荐阅读
相关标签
  

闽ICP备14008679号