第二章:算法——程序的灵魂,本章主要介绍的是程序由什么组成、什么是算法、算法的特性以及如何去写一个算法。
友情提示:有的题目可能没写,因为我感觉没必要,还有就是下面的所有回答专业性的名词解释使用人工智能或Baidu的,程序是完全自己写的,主要是用来记笔记方便以后复习用的,希望对大家有帮助,共勉!
首先介绍一下概念性的东西
-
什么是程序:程序是由 数据结构 + 算法 这两个核心的要素组成
-
什么是数据结构:数据结构是程序用来组织、存储和管理数据的方式,它关注数据的逻辑关系和存储方式。
-
什么是算法:是用来解决特定问题或执行特定任务的一系列步骤或方法。
-
算法的特性:
-
有穷性: 算法必须在有限个步骤后结束,并且每个步骤都在有限时间内完成。
-
确定性:算法的每一个步骤都必须是明确且无歧义的,确保每一步都有唯一的执行方式。
-
可行性:算法中的每个步骤都应该是可行的,并且能在有限次运算内完成。
-
输入:算法可以有零个或多个输入,这些输入是算法执行所需的数据或条件。
-
输出:算法至少有一个输出,这是算法执行后的结果或结论。
-
怎样表示一个算法
-
自然语言表示算法:使用日常语言描述算法的主要步骤和逻辑,直观易懂
-
流程图表示:通过图形化的符号和流程线展示算法的执行顺序和逻辑,形象直观,有助于理解算法的整体流程。
-
N-S流程图表示法(盒式图表示法):使用特定的盒子和箭头来表示算法中的各个步骤和决策点,结构清晰,强调程序的模块化结构。
-
伪代码表示法:类似于编程语言但更为简洁的表示方式,描述算法的逻辑和步骤,既保留了算法的核心思想,又具有一定的可读性。
-
计算机语言表示法:使用具体的计算机语言,如C语言、Java语言、C++等
题目1:什么叫算法?试从日常生活中找3个例子,描述他们的算法。
算法:是用来解决特定问题或执行特定任务的一系列步骤或方法。
例子1:烹饪食谱:
-
算法:烹饪一道菜的食谱。
-
例子:制作番茄炒蛋。
-
算法步骤:
-
准备食材:番茄、鸡蛋、盐、油。
-
打碎鸡蛋并搅拌均匀。
-
切开番茄成块。
-
加热油锅。
-
倒入鸡蛋液,翻炒至熟后盛出。
-
在同一锅中加入番茄块翻炒。
-
当番茄稍微变软时,加入炒好的鸡蛋。
-
加入适量盐调味。
-
翻炒均匀后出锅。
-
例子2:洗衣服的流程:
-
算法:洗衣服的步骤。
-
例子:手洗衣物。
-
算法步骤:
-
分类衣物(按颜色、材质等)。
-
准备洗涤用品(如洗衣液、柔顺剂等)。
-
将衣物放入洗衣盆或桶中。
-
加入适量的水和洗涤用品。
-
浸泡衣物一段时间。
-
搓洗衣物,特别注意污渍处。
-
倒掉脏水,用清水多次漂洗。
-
拧干衣物,或用脱水机甩干。
-
晾晒衣物。
-
例子3:公交出行路线规划:
-
算法:规划从起点到终点的最优公交路线。
-
例子:从家到公司的公交路线规划。
-
算法步骤:
-
确定起点和终点。
-
查看可用的公交线路和班次。
-
根据时间和换乘次数筛选线路。
-
选择最优线路(例如,最少换乘次数、最短总时间)。
-
记住或记录站点和换乘信息。
-
根据规划出行。
-
题目2:什么是结构化算法?为什么提倡结构化的算法?
结构化算法:由一些基本结构,如顺序结构、选择结构、循环结构等,按照一定规则和层次组成的算法结构。
注意:这里的基本的结构在谭浩强书后面的第4和第5章有介绍,初学者不会的话先别急,一步一个脚印,先了解,后面都有的。
为什么提倡:
-
可重用性强:由于每个步骤都是独立的,结构化的算法更易于被其他算法或程序重用。
-
易于维护和修改:将复杂的问题分解成若干个步骤,每个步骤之间相互独立,这使得算法的维护和修改变得更为简单。
-
可读性强(即容易理解):结构化的算法按照一定的规则和层次进行分解,使得算法易于理解和阅读。
-
适应性强:结构化的算法适用于各种编程语言和计算机平台,具有广泛的适应性。
题目3:试述3种基本结构的特点,请另外设计两种基本结构(要符合基本结构的特点)
3种基本结构特点如下:
-
顺序结构:顺序结构是最基础的控制结构,特点是按照代码的顺序,从上到下依次执行,不会有跳跃的情况。
-
选择结构:选择结构的特点是根据条件的真假来选择执行的路径。一旦选择了一条路径,其他路径就不会执行。
-
循环结构:循环结构的特点是重复执行某一段代码,直到满足退出条件。这种结构可以大大简化代码,避免重复的工作。
设计的两种基本结构:
声明:不是自己设计的,也不是自己想的,是在计算机科学和软件工程领域中已有深入的研究和广泛的应用。
-
并发结构:并发结构是一种在多任务环境下的控制结构,它允许两个或者多个任务同时执行。这种结构的主要特点是能够提高系统的效率和响应速度。
-
异常处理结构:用来处理程序运行时错误的控制结构。它允许程序在发生错误时,能够跳出正常的执行流程,转到专门的错误处理代码段进行处理。
题目4:用伪代码表示求解以下问题的算法。
提示:这里的题目我给改了,实际上这个是题目6的问题,我觉得书本上的题目4和题目5使用的流程图和N-S图并不重要,没有写的必要,以后工作基本写的是伪代码和计算机语言实现的具体代码,没见过上面两种,所以在这里就不写了,感兴趣的可以去看谭浩强书的答案解析
(1)有两个瓶子A和B,分别盛放醋和酱油,要求将它们互换(即A瓶原来盛醋,现改盛酱油,B瓶则相反)。
将 A 瓶的内容倒入空瓶子 C
将 B 瓶的内容倒入 A 瓶
将 C 瓶的内容倒入 B 瓶
(2)依次将10个数输人,要求输出其中最大的数
设 max 为负无穷大
重复 10 次:
读取一个数 num
如果 num 大于 max,那么将 max 设为 num
输出 max
(3)有3个数a,b,c,要求按大小顺序把它们输出。
读取三个数 a, b, c
如果 a > b,交换 a 和 b
如果 a > c,交换 a 和 c
如果 b > c,交换 b 和 c
输出 a, b, c
(4)求1+2+3+…+100。
初始化 sum 为 0
对于每个从 1 到 100 的整数 i:
将 i 加到 sum 上
输出 sum
(5)判断一个数"能否同时被3和5 整除。
读取一个数 num
如果 num 能被 3 整除且能被 5 整除:
输出 "能被同时被3和5整除"
否则:
输出 "不能被同时被3和5整除"
(6)将 100~200 之间的素数输出。
对于每个从 100 到 200 的整数 num:
如果 num 是素数:
输出 num
(7)求两个数m和n的最大公约数
读取两个数 m 和 n
当 n 不等于 0:
让 m 和 n 分别变为 n 和 m 除以 n 的余数
输出 m
(8)求方程式ax'+bx+c=0的根。分别考虑:
① 有两个不等的实根;
② 有两个相等的实根:
读取 a, b, c
计算 Δ = b*b - 4*a*c
如果 Δ 大于 0(有两个不等的实根):
计算并输出两个实根 (-b + sqrt(Δ)) / (2*a) 和 (-b - sqrt(Δ)) / (2*a)
否则如果 Δ 等于 0(有两个相等的实根):
计算并输出一个实根 -b / (2*a)
否则:
输出 "无实根"
题目5:什么叫结构化程序设计?他的主要内容是什么?
结构化程序设计:通过使用顶部-底部设计和逐步细化,以及通过将程序划分为相互独立的子程序或函数来增强程序的可理解性、可维护性和可修改性。
主要内容:
-
清晰的控制结构:结构化程序设计强调使用清晰的控制结构,如顺序、选择(if-else、switch)和循环(for、while、do-while)来组织代码。
-
模块化:将程序分解为小模块或函数,每个模块负责执行特定的任务。
-
自顶向下设计:结构化程序设计从高层次开始,从整体到细节逐步设计程序。首先确定主要功能,然后逐步细化细节,以确保程序的逻辑正确性。
-
模块独立性:每个模块应该是相对独立的,即使修改一个模块也不会对其他模块造成严重影响。
题目6:用自顶向下、逐步细化的方法进行以下算法的设计
(1)输出 1900-2000年中是闰年的年份,符合下面两个条件之一的年份是闰年
① 能被4整除但不能被 100 整除;
② 能被 100 整除且能被 400 整除。
#include <stdio.h>
// 辅助函数:判断是否为闰年
// 体现逐步细化:将判断闰年的逻辑封装到一个单独的函数中
int is_leap_year(int year) {
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
return 1;
} else {
return 0;
}
}
// 函数:输出1900-2000年间的闰年
// 体现自顶向下:首先定义输出闰年的主函数,然后调用辅助函数实现细节
void print_leap_years() {
for (int year = 1900; year <= 2000; year++) {
// 调用辅助函数判断当前年份是否为闰年
if (is_leap_year(year)) {
printf("%d\n", year);
}
}
}
int main() {
// 调用函数开始执行程序
print_leap_years();
return 0;
}
(2)求ax^2 + bx + c = 0 的根。分别考虑 d = b^2 - 4ac大于0、等于0和小于0这3种情况
#include <stdio.h>
#include <math.h>
// 辅助函数:计算二次方程的根
// 体现逐步细化:将计算二次方程根的逻辑封装到一个单独的函数中
void solve(double a, double b, double c) {
//计算🔺根的判别式
double discriminant = b * b - 4 * a * c;
if (discriminant > 0) {
// 两个不相等的实根
double root1 = (-b + sqrt(discriminant)) / (2 * a);
double root2 = (-b - sqrt(discriminant)) / (2 * a);
printf("两个不相等的实根:%.2f 和 %.2f\n", root1, root2);
} else if (discriminant == 0) {
// 两个相等的实根
double root = -b / (2 * a);
printf("两个相等的实根:%.2f\n", root);
} else {
// 没有实根
printf("没有实根\n");
}
}
int main() {
double a, b, c;
printf("请输入二次方程的三个系数a, b, c: ");
scanf("%lf %lf %lf", &a, &b, &c);
// 调用辅助函数开始计算二次方程的根
solve(a, b, c);
return 0;
}
(3)输人 10 个数,输出其中最大的一个数
#include <stdio.h>
// 辅助函数:从数组中找出最大值
// 体现逐步细化:将寻找最大值的逻辑封装到一个单独的函数中
int find_max_number(int numbers[], int size) {
int max_number = numbers[0];
for (int i = 1; i < size; i++) {
if (numbers[i] > max_number) {
max_number = numbers[i];
}
}
return max_number;
}
// 函数:输入10个数,输出最大值
// 体现自顶向下:首先定义函数,然后调用辅助函数来找到最大值
void input_and_find_max() {
int numbers[10];
printf("请输入10个数:\n");
for (int i = 0; i < 10; i++) {
scanf("%d", &numbers[i]);
}
// 调用辅助函数找到最大值
int max_number = find_max_number(numbers, 10);
printf("最大的数是:%d\n", max_number);
}
int main(){
input_and_find_max();
return 0;
}