C语言程序设计 数组(8.2.4)--使用循环和数组代替递归
C语言程序设计全套教学教程完整版电子课件最全ppt电子教案

上一页 下一页
目录
8.1 指针的概念、定义和引用 8.1.1 指针的概念 8.1.2 指针变量的定义 8.1.3 指针变量的引用 8.2 指针与函数 8.2.1 指针变量作函数参数 8.2.2 返回值为指针的函数 8.2.3 通过指针调用函数
上一页 下一页
Hale Waihona Puke 目录8.3 指针与数组 8.3.1 指针与数组的关系 8.3.2 数组名作函数参数的指针解释 8.3.3 指针数组 8.3.4 多级指针 8.4 指针与字符串 8.4.1 字符串的表示形式 8.4.2 字符串指针作函数参数
2.汇编语言
汇编语言的指令与机器语言的指令基本上保持了一一对应的关系。与 机器语言比起来,汇编语言易记、易读、易检查、易修改,但却不能 被计算机直接识别和执行,必须由翻译程序翻译成机器语言程序后才 能执行。汇编语言仍然是面向特定计算机的语言,也仍然是低级语言
下一页
返回
1.1 程序设计语言概述
3.高级语言 高级语言是接近人类自然语言和数学语言的程序设计语言,具有以下
上一页 下一页
目录
5.2 do-while语句 5.3 for语句 5.4 break和continue语句 5.5 多重循环 5.6 综合应用举例 第6章 数组 6.1 数组概述 6.2 一维数组
上一页 下一页
目录
6.2.1 一维数组的定义 6.2.2 一维数组的引用 6.2.3 一维数组的初始化 6.2.4 一维数组的程序举例 6.3 二维数组 6.3.1 二维数组的定义 6.3.2 二维数组的引用 6.2.3 二维数组的初始化
翻译成目标程序,然后执行该目标程序。解释方式是把源程序逐句翻
上一页 下一页 返回
1.1 程序设计语言概述
c语言循环结构程序设计

c语言循环结构程序设计以C语言循环结构程序设计为标题在C语言中,循环结构是一种常用的程序设计方式,可以重复执行一段代码,从而实现某种特定的功能。
循环结构使得程序更加灵活和高效,能够处理大量重复性的任务。
本文将介绍C语言中常用的循环结构,以及一些常见的循环结构程序设计的示例。
一、循环结构的基本概念循环结构是一种控制结构,它允许程序重复执行某个代码块,直到满足退出循环的条件。
在C语言中,常见的循环结构有while循环、do-while循环和for循环。
1. while循环:while循环先判断条件是否成立,如果条件成立,则执行循环体中的代码,然后再次判断条件是否成立,如此循环下去,直到条件不成立时,退出循环。
示例代码:```int i = 0;while (i < 10) {printf("%d\n", i);i++;}```2. do-while循环:do-while循环先执行循环体中的代码,然后再判断条件是否成立,如果条件成立,则继续执行循环体中的代码,如此循环下去,直到条件不成立时,退出循环。
示例代码:```int i = 0;do {printf("%d\n", i);i++;} while (i < 10);```3. for循环:for循环在执行前先进行初始化,然后判断条件是否成立,如果条件成立,则执行循环体中的代码,然后执行循环迭代语句,再次判断条件是否成立,如此循环下去,直到条件不成立时,退出循环。
示例代码:```for (int i = 0; i < 10; i++) {printf("%d\n", i);}```二、循环结构程序设计示例1. 计算1到100的累加和```int sum = 0;for (int i = 1; i <= 100; i++) {sum += i;}printf("1到100的累加和为:%d\n", sum); ```2. 判断一个数是否为素数```int num;printf("请输入一个正整数:");scanf("%d", &num);int isPrime = 1;for (int i = 2; i <= num / 2; i++) {if (num % i == 0) {isPrime = 0;break;}}if (isPrime == 1) {printf("%d是素数\n", num);} else {printf("%d不是素数\n", num);}```3. 打印九九乘法表```for (int i = 1; i <= 9; i++) {for (int j = 1; j <= i; j++) {printf("%d * %d = %d\t", j, i, j * i); }printf("\n");}```三、总结循环结构是C语言中常用的程序设计方式,能够有效地处理重复性的任务。
C语言中斐波那契数列的三种实现方式(递归、循环、矩阵)

C语⾔中斐波那契数列的三种实现⽅式(递归、循环、矩阵)⽬录⼀、递归⼆、循环三、矩阵《剑指offer》⾥讲到了⼀种斐波那契数列的 O(logN) 时间复杂度的实现,觉得挺有意思的,三种⽅法都记录⼀下。
⼀、递归⼀般来说递归实现的代码都要⽐循环要简洁,但是效率不⾼,⽐如递归计算斐波那契数列第n个元素。
long long Fibonacci_Solution1(unsigned int n) {// printf("%d ", n);if (n <= 0) return 0;if (n == 1) return 1;return Fibonacci_Solution1(n - 1) + Fibonacci_Solution1(n - 2);}如果计算数列的第4个位置上(从0开始)的数(0 1 1 2 3),也就是3,上边的 printf 输出应该是 4 3 2 1 0 1 2 1 0,这是因为计算 F(4) 要计算 F(3) 和 F(2),⽽计算 F(3) 的时候⼜要计算 F(2) 和 F(1),所以会有很多重复计算。
⽤下图可以更好地说明。
递归虽然有简洁的优点,但它同时也有显著地缺点。
递归由于是函数调⽤⾃⾝,⽽函数调⽤是有空间和时间的消耗的:每⼀次函数调⽤,都需要在内存栈中分配空间以保存参数、返回地址及临时变量,⽽且往栈⾥压⼊数据和弹出数据都需要时间。
⽽且除了效率问题之外,递归可能引起调⽤栈溢出,因为需要为每⼀次函数调⽤在内存栈中分配空间,⽽每个进程的栈的容量是有限的。
当蒂固的层级太多,就会超出栈的容量,导致栈溢出。
⽐如上边的代码,输⼊40,可以正确返回 12502500,但是输⼊ 5000 就会出错。
⼆、循环最常规的正确做法就是⽤循环从⼩到⼤计算。
long long Fibonacci_Solution2(unsigned n) {if (n <= 1) return n;long long fib1 = 1, fib0 = 0, fibN = 0;for (unsigned int i = 2; i <= n; ++i) {fibN = fib1 + fib0;fib0 = fib1;fib1 = fibN;}return fibN;}或者下边这种long long Fibonacci_Solution2(unsigned n) {if (n <= 1) return n;long long a = 0, b = 1;for (unsigned int i = 2; i <= n; ++i) {b = a + b;a =b - a;}return b;}三、矩阵数中提到了⼀种 O(logN) 时间复杂度的算法,就是利⽤数学公式计算。
C语言的递归函数原理和应用场景

C语言的递归函数原理和应用场景递归是编程中一种强大而常用的技巧,尤其在C语言中,递归函数被广泛应用。
递归函数是指在函数体内调用函数本身的一种函数形式。
通过不断调用自身,递归函数能够解决一些需要重复执行的任务,使得代码更加简洁、易读、易于理解。
一、递归函数的原理递归函数的原理可以通过以下步骤来理解:1. 基本条件:递归函数中需要有一个基本条件,当满足这个条件时,递归函数将不再调用自身,结束递归。
2. 自调用:在递归函数体中,通过函数自身的调用来实现重复执行的效果。
3. 函数参数:递归函数在每次调用自身时,往往会传入不同的参数,这些参数可以决定递归的结束条件或下一次递归的运算逻辑。
4. 递归调用:递归函数在函数体内部通过调用自身来实现循环执行的效果。
二、递归函数的应用场景递归函数在编程中有许多实际应用场景,下面列举了一些常见的应用场景来说明递归函数的实用性。
1. 阶乘计算:递归函数可以非常方便地求解阶乘。
例如,对于n的阶乘可以表示为n! = n * (n-1)!,其中(n-1)!可以通过递归函数来计算。
2. 斐波那契数列:斐波那契数列是一个经典的递归问题。
数列中的每个数都是前两个数的和,即fib(n) = fib(n-1) + fib(n-2)。
通过递归函数可以很容易地计算出斐波那契数列的值。
3. 文件系统遍历:递归函数可以用来遍历文件系统中的目录结构。
通过递归调用函数来进入子目录,逐层遍历文件和文件夹,实现对整个文件系统的扫描。
4. 数据结构操作:递归函数也可以用于对各种数据结构的操作。
比如,针对树形结构的遍历、查找等操作,递归函数能够更加简洁地实现。
5. 图算法:在图算法中,递归函数常用于深度优先搜索(DFS)的实现。
通过递归调用函数,可以遍历图的各个节点,查找目标节点,或者找到所有可能的路径。
总结:递归函数是一种基于函数自身调用的编程技巧,通过重复调用自身,递归函数能够解决一些需要重复执行的任务。
C语言程序设计第三版微课版-C语言程序设计(第3版微课版)

C语⾔程序设计第三版微课版,C语⾔程序设计(第3版微课版)⽬ 录第1章 C语⾔概述 11.1 程序及程序设计语⾔ 11.1.1 程序及程序设计 11.1.2 程序设计语⾔ 21.2 C语⾔的发展及特点 31.2.1 C语⾔的发展概述 31.2.2 C语⾔的特点 41.3 C语⾔程序的基本结构 51.4 C语⾔字符集、标识符和关键字 91.4.1 C语⾔字符集 91.4.2 C语⾔标识符 101.4.3 C语⾔关键字 111.5 C语⾔程序的开发环境 121.5.1 Visual C++ 6.0集成开发环境介绍 121.5.2 在Visual C++ 6.0环境下建⽴和运⾏C语⾔程序的步骤 13本章⼩结 16易错提⽰ 17习题1 17第2章 C语⾔数据类型和表达式 202.1 C语⾔的数据类型 202.1.1 整型数据 212.1.2 实型数据 232.1.3 字符型数据 242.2 常量和变量 272.2.1 常量 272.2.2 变量 292.3 运算符和表达式 322.3.1 算术运算符和算术表达式 322.3.2 赋值运算符与赋值表达式 332.3.3 ⾃增⾃减运算符和⾃增⾃减表达式 342.3.4 逗号运算符和逗号表达式 35 2.3.5 条件运算符和条件表达式 36 2.4 数据类型转换 372.4.1 ⾃动转换 382.4.2 赋值转换 382.4.3 强制转换 402.5 位运算 402.5.1 位运算概述 412.5.2 按位取反运算 412.5.3 移位运算 412.5.4 按位与、或和异或 42本章⼩结 43易错提⽰ 44习题2 44第3章 顺序结构程序设计 493.1 程序设计的基本概念 493.2 C语⾔的语句 513.3 格式化输⼊/输出函数 523.3.1 格式化输出函数printf() 53 3.3.2 格式化输⼊函数 563.4 字符输⼊/输出函数 593.5 程序设计举例 61本章⼩结 64易错提⽰ 65习题3 65第4章 选择结构程序设计 714.1 关系运算符与关系表达式 71 4.1.1 关系运算符 714.1.2 关系表达式 724.2 逻辑运算符与逻辑表达式 72 4.2.1 逻辑运算符 724.2.2 逻辑表达式 744.3 if语句 744.3.1 单分⽀if语句 754.3.2 双分⽀if语句 774.3.3 多分⽀if语句 784.3.4 if语句的嵌套 814.4 switch语句 834.5 程序设计举例 86本章⼩结 89易错提⽰ 89习题4 90第5章 循环结构程序设计 985.1 while语句 995.2 do-while语句 1035.3 for语句 1045.4 for语句与while语句和do-while语句⽐较 107 5.5 break语句和continue语句 1085.5.1 break语句 1085.5.2 continue语句 1095.5.3 break语句和continue语句的区别 1115.6 循环的嵌套结构 1125.6.1 双重循环的嵌套 1125.6.2 多重循环的嵌套 1145.7 程序设计举例 115本章⼩结 123习题5 123第6章 数组 1346.1 ⼀维数组 1366.1.1 ⼀维数组的定义 1366.1.2 ⼀维数组的引⽤ 1386.1.3 ⼀维数组赋初值 1396.1.4 ⼀维数组的应⽤ 1416.2 ⼆维数组 1496.2.1 ⼆维数组的定义和注意事项 1496.2.2 ⼆维数组的引⽤ 1516.2.3 ⼆维数组的赋值 1526.2.4 ⼆维数组的应⽤ 1536.3 字符数组 1586.3.1 字符数组的定义 1586.3.2 字符数组初始化 1596.3.3 字符数组输⼊输出 1616.3.4 字符串处理函数 1636.4 程序举例 168本章⼩结 173易错提⽰ 173习题6 174第7章 函数与编译预处理 1857.1 模块化程序设计 1867.2 定义函数 1887.2.1 标准库函数 1887.2.2 函数的定义 1897.3 函数的调⽤ 1917.3.1 函数调⽤形式 1917.3.2 函数调⽤⽅式 1927.3.3 函数调⽤过程 1957.3.4 函数调⽤结果的返回 1967.4 函数间数据传递 1987.4.1 普通变量作为实参的值传递 199 7.4.2 数组名作为实参的地址传递 201 7.4.3 字符串作为实参的传递 2027.5 函数的嵌套调⽤ 2037.6 递归函数与递归调⽤ 2067.7 变量作⽤域与存储⽅式 2137.7.1 变量作⽤域 2137.7.2 变量的存储⽅式 2177.8 编译预处理 2207.8.1 宏定义 2207.8.2 ⽂件包含 2237.8.3 条件编译 225本章⼩结 227习题7 228第8章 指针 2378.1 指针与指针变量 2378.1.1 指针的概念 2378.1.2 指针变量 2398.1.3 指针变量的定义 2398.1.4 指针变量初始化 2408.1.5 指针运算符 2418.1.6 指针运算 2438.1.7 多级指针 2478.2 指针与数组 2478.2.1 ⼀维数组元素的指针访问 248 8.2.2 ⼆维数组元素的指针访问 253 8.2.3 指向⼀维数组的指针 2588.2.4 指针数组 2618.3 字符指针与字符串 2648.3.1 字符串的表现形式 2648.3.2 ⽤字符指针处理字符串 266 8.4 指针与函数 2698.4.1 指针作为函数参数 2698.4.2 指向函数的指针 2708.4.3 返回指针值的函数 2728.4.4 带参数的main()函数 2738.5 动态指针 2748.6 指针程序设计举例 276本章⼩结 279易错提⽰ 280习题8 281第9章 结构体与共⽤体 2909.1 结构体的概念 2909.1.1 结构体类型的定义 2909.1.2 结构体类型变量的定义 291 9.1.3 结构体类型变量的引⽤ 295 9.1.4 结构体类型变量的初始化 298 9.2 结构体数组与链表 2989.2.1 结构体数组的定义与引⽤ 298 9.2.2 结构体数组初始化和应⽤ 300 9.2.3 链表 3009.3 共⽤体的概念 3079.3.1 共⽤体类型的定义 3079.3.2 共⽤体类型变量的定义 3089.3.3 共⽤体类型变量的引⽤ 3099.4 程序设计举例 311本章⼩结 316习题9 316第10章 ⽂件 32410.1 ⽂件的概述 32410.1.1 ⽂件的分类 32410.1.2 ⽂件的缓冲区 32510.1.3 ⽂件的存取⽅式 32610.1.4 ⽂件类型的指针 32610.2 ⽂件的常⽤操作 32710.2.1 ⽂件的打开与关闭 32710.2.2 ⽂件的读写 32910.2.3 ⽂件的定位 33510.2.4 ⽂件的其他操作 337本章⼩结 338习题10 338第11章 综合实训 34111.1 简单的银⾏⾃动取款机系统 341 11.1.1 问题描述 34111.1.2 总体设计 34111.1.3 详细设计 34211.1.4 设计代码 34911.1.5 系统运⾏界⾯ 35411.1.6 系统测试 35711.2 学⽣成绩管理系统 35711.2.1 设计要求 35711.2.2 设计架构 35711.2.3 设计⽅法 35911.2.4 代码设计 36211.3 电话簿管理系统 36211.3.1 设计要求 36211.3.2 设计架构 36211.3.3 设计⽅法 36311.3.4 代码设计 36511.4 综合实训题⽬ 365附录I 常⽤字符与ASCII码对照表 367附录II C语⾔运算符的优先级和结合⽅向 368附录III 常⽤C语⾔库函数 369参考⽂献 373。
c程序设计第四版复习

c程序设计第四版复习C程序设计第四版是计算机科学领域的经典教材,由Brian W. Kernighan和Dennis M. Ritchie共同撰写,通常被称为K&R C。
这本书不仅介绍了C语言的基本语法和编程技巧,还涵盖了高级编程概念和实践。
以下是对C程序设计第四版的复习要点:1. C语言基础- 变量和数据类型:理解整型、浮点型、字符型等基本数据类型及其使用。
- 运算符:熟悉算术运算符、关系运算符、逻辑运算符、位运算符等。
- 控制语句:掌握if语句、switch语句、while循环、for循环和do-while循环的使用。
2. 函数- 定义和调用:理解函数的定义方式和如何调用函数。
- 参数传递:了解值传递和引用传递的区别。
- 递归:学习如何使用递归解决复杂问题。
3. 数组- 一维数组:掌握数组的声明、初始化和访问。
- 多维数组:了解二维数组的声明和使用。
- 指针和数组:理解指针与数组的关系,以及如何使用指针操作数组。
4. 指针- 指针基础:理解指针的概念和指针变量的声明。
- 指针和函数:学习如何通过指针传递函数参数。
- 指针数组和函数指针:掌握指针数组的使用和函数指针的概念。
5. 结构体和联合体- 结构体:理解结构体的声明、初始化和成员访问。
- 联合体:了解联合体的概念和使用场景。
- 结构体和指针:掌握如何使用指针访问结构体成员。
6. 预处理器- 宏定义:学习如何使用#define进行宏定义。
- 文件包含:了解如何使用#include包含其他文件。
7. 输入和输出- 标准库函数:熟悉printf和scanf等标准输入输出函数。
- 格式化输入输出:掌握如何使用格式化字符串进行输入输出。
8. 动态内存分配- malloc和free:学习如何使用malloc进行动态内存分配和使用free释放内存。
9. 文件操作- 文件指针:理解文件指针的概念。
- 打开和关闭文件:掌握如何使用fopen和fclose操作文件。
c语言数组内数据循环

c语言数组内数据循环循环是编程中常用的一种控制结构,用于重复执行一段代码。
在C 语言中,循环可以用来遍历数组中的数据,实现对数组元素的操作。
数组是一种存储相同类型的多个元素的数据结构,在C语言中,数组下标从0开始,可以通过索引值访问数组元素。
对于循环遍历数组,常用的方式有for循环和while循环。
1. for循环遍历数组:for循环是一种经典的循环结构,通过设置循环变量的起始值、终止值和步长,可以很方便地遍历数组。
以下是一个示例代码:```c#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};for (int i = 0; i < 5; i++) {printf("%d ", arr[i]);}return 0;}```在上述示例中,我们定义了一个大小为5的整型数组arr,并使用for循环遍历数组元素。
循环变量i的起始值为0,终止值为4,步长为1。
在循环体内,使用printf函数逐个输出数组元素的值。
2. while循环遍历数组:while循环是另一种常见的循环结构,它的特点是先判断循环条件,然后执行循环体。
以下是一个使用while循环遍历数组的示例代码:```c#include <stdio.h>int main() {int arr[5] = {1, 2, 3, 4, 5};int i = 0;while (i < 5) {printf("%d ", arr[i]);i++;}return 0;}```在上述示例中,我们同样定义了一个大小为5的整型数组arr,并使用while循环遍历数组元素。
循环变量i的初始值为0,循环条件为i < 5。
在循环体内,先输出arr[i]的值,然后将i自增1。
循环遍历数组可以对数组元素进行各种操作,例如求和、查找最大值/最小值、统计某个特定值的出现次数等。
苏小红c语言程序设计第二版课后答案

苏小红c语言程序设计第二版课后答案苏小红教授所著的《C语言程序设计》第二版是计算机科学与技术专业学生学习C语言的经典教材之一。
该书不仅系统地介绍了C语言的基础知识,还通过丰富的实例和练习题帮助学生加深理解。
以下是部分课后习题的答案,以供参考:第一章:C语言概述1. 问题一:简述C语言的特点。
- 答案: C语言是一种结构化编程语言,具有高效性、灵活性和可移植性等特点。
它支持多种数据类型,拥有丰富的运算符,并且能够直接访问内存地址。
2. 问题二:为什么说C语言是高级语言?- 答案: C语言被称为高级语言是因为它抽象了底层硬件操作,使得程序员可以不必关心计算机的硬件细节,而专注于程序的逻辑结构。
第二章:数据类型、运算符和表达式1. 问题一:说明C语言中基本数据类型的种类及其特点。
- 答案: C语言中的基本数据类型包括整型(int)、字符型(char)、浮点型(float和double)。
每种类型都有其特定的取值范围和占用内存大小。
2. 问题二:解释赋值运算符的右结合性。
- 答案:赋值运算符的右结合性意味着当多个赋值运算符同时出现时,从右向左进行计算。
例如,a = b = c; 会先计算 b = c,然后将结果赋值给 a。
第三章:控制结构1. 问题一:什么是条件语句?举例说明。
- 答案:条件语句是程序中根据条件是否满足来决定执行哪一段代码的结构。
例如,if语句就是典型的条件语句。
2. 问题二:循环语句有哪些?它们各自的特点是什么?- 答案: C语言中有三种循环语句:for循环、while循环和do-while循环。
for循环常用于已知循环次数的情况;while循环适用于循环次数未知,需要在循环体内部判断是否继续循环;do-while循环至少执行一次循环体,然后在循环末尾判断是否继续。
第四章:数组1. 问题一:一维数组和多维数组的区别是什么?- 答案:一维数组是线性的,只有一个索引来访问数组元素;而多维数组可以看作是数组的数组,需要多个索引来定位元素。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
int main() {
int f[10001] = {0, 1, 2, 3}; int n, m, i; while(scanf("%d%d", &n, &m) == 2) {
if(n == 0 && m == 0) {
break; } else if(n >= 0) {
printf("%d\n", f[n] % m); } return 0; }
再输入 n=10000,m=999 时,就能够获得 433 这一正确的结果。大功告成! 但是很不幸,程序仍然有错!这是什么原因呢?进一步仔细思考,发现前面的 程序都没有考虑 n 为负数的情况,依题意当 n 为负数时,f(n)的值为 n,此时负 数 f(n)对 m 求余时,按 C 语言求余运算得到的结果为使商尽可能大的负余数, 例如因为-7=(-2)*3+(-1),商是-2,余数是-1,所以(-7)%3=-1。依题意,我们需要 求的是使商尽可能小的正余数,例如将-7 表示为-7=(-3)*3+2,商是-3,余数是 2,所以(-7)%3=2。此时需要使用公式(m - (-n) % m) % m 获得题目要求的负数的 正余数。因此,最终代码修改为:
再回过头来仔细理解题目,我们最终需要获得的并非 f[n]的具体值,而是 f[n] % m 的结果,我们会发现, f[n] % m 与(f[n-1] % m + f[n-3] % m) % m 的值 是一样的,而后者就不会出现溢出的情况。因此,代码进一步修改为:
代码 3: #include <stdint f[10001] = {0, 1, 2, 3}; int n, m, i; while(scanf("%d%d", &n, &m) == 2) {
if(n == 0 && m == 0) {
break; } for(i = 4; i <= n; i++) {
f[i] = f[i - 1]%m + f[i - 3]%m; }
代码 2: #include <stdio.h>
int main()
{ int f[10001] = {0, 1, 2, 3}; int n, m, i; while(scanf("%d%d", &n, &m) == 2) { if(n == 0 && m == 0) { break; } for(i = 4; i <= n; i++) { f[i] = f[i - 1] + f[i - 3]; } printf("%d\n", f[n] % m); } return 0;
教 学 案 例 — 递 归 (Recursive)
【任务描述】
已知 f(n)的值由下面的递归公式定义: f(n) = f(n-1) + f(n-3), n > 3 f(n) = n, n <= 3 写出一个程序,计算 f(n) % m 的值(使商尽可能小的正余数)。其中: n <= 10000, 2 <= m <= 10000. 输入:
此教学案例包括的知识点: 1、 递归函数在处理层级较多的递归任务时,并不合适; 2、 可以使用循环和数组代替递归函数; 3、 数据过大时,会出现溢出的情况; 4、 如果掌握余数的性质,能够避免溢出; 5、 负数求正余数的方法;
至此,绝大部分学生都会认为已经圆满的解决了该问题,但是还会有部分 爱动脑筋、善于思考的学生会追问,这就是最优解了么?还有没有更快的办法呢 答案是确定的,以上的代码还能够进一步优化,从而加快运行速度。如对于 f 数 组,仅需要计算一次,以后再需要计算 f(n)时,直接从中取第 n 个元素即可。这 就省去了重新计算的时间,这种思想也是今后要学习的动态规划算法的本质。具 体代码,就留给感兴趣的学生自己编写了。
}
该代码执行速度极快,但是通过对执行结果的观察,发现当输入的 n 较小 时,例如 1,程序能够获得正确的输出结果。但是当输入较大的 n,例如当 n=10000,m=999 时,输出结果却为-657,显然出现了错误。这是什么原因呢? 这是由于当 n 较大时,f[n]的结果会变得很大,直至出现溢出的情况,即使将 f[n]的类型定义为 long,问题仍然不能够得到有效解决。
for(i = 4; i <= n; i++) {
f[i] = f[i - 1]%m + f[i - 3]%m; } printf("%d\n", f[n] % m); } else { printf("%d\n", (m - (-n) % m) % m); } } return 0; }
【教学指导】
代码 1: #include <stdio.h>
int f(int n) {
if(n <= 3) {
return n; }
return f(n-1) + f(n-3); }
int main() {
int n, m; while(scanf("%d%d", &n, &m) == 2) {
if(n == 0 && m == 0) {
有多组测试样例,每个样例包括两个整数 n 和 m。n = 0 和 m = 0 表示输入 结束,无需处理。(注:本题为 ACM 竞赛试题) 输出:
对于每个样例,打印 f(n) % m 的值。 输入样例: 12 10000 999 -7 3 00 输出样例: 1 433 2
【任务分析】
该题目初看就是一个非常典型的递归问题,使用课堂上介绍的递归函数, 能够非常容易的写出如下代码:
break; } printf("%d\n", f(n) % m); } return 0; }
该代码在输入较小的 n 时,能够获得正确的结果,同时运行时间也非常短。 然而,当输入的 n 较大时,会出现程序运行时间过长的问题。仔细思考造成这一 问题的原因,可见随着 n 的增大,递归调用的级数会成指数增长,必然会造成 运算速度慢,同时内存消耗大的问题。这也是递归函数在实际应用中的缺点。知 道了问题所在,将程序进行修改,使用循环和数组代替递归,并写出如下代码: