第2章 算法--程序的灵魂


前言

本章的内容十分重要,是学习后面章节的基础。


一、程序 = 算法 + 数据结构

一个程序主要包括以下两方面的信息:

  • 对数据的描述(数据结构):在程序中要指定用到哪些数据,以及这些数据的类型和数据的组织形式
  • 对操作的描述(算法):要求计算机进行操作的步骤

数据是操作的对象,操作的目的是对数据进行加工处理,以得到期望的结果。

算法 + 数据结构 = 程序
一个过程化的程序除了以上两个要素之外,还应当采用结构化程序设计方法进行程序设计,并且用某一种计算机语言表示。

算法是解决“做什么”和“怎么做”的问题。

二、什么是算法

不要认为只有“计算”问题才有算法。广义地说,为解决一个问题而采取的方法和步骤,就称为“算法”

计算机算法可分为两大类别:

  • 数值运算算法:数据运算的目的是求数值解
  • 非数值运算算法:非数值运算的种类繁多,要求各异,难以做到全部都有现成的答案,因此只有一些典型的非数值运算算法(例如排序算法、查找搜查算法等)有现成的、成熟的算法可供使用。

三、简单的算法举例

1.求1*2*3*4*5

#include<stdio.h>
int main() {
	int rst = 1;
	for (int i = 1; i <= 5; i++) {
		rst *= i;
	}
	printf("1 * 2 * 3 * 4 * 5 = %d", rst);
	return 0;
}

2.有50个学生,要求输出成绩在80分以上的学生的学号和成绩

#include<stdio.h>
int main() {
	for(int i = 0; i < 50; i++) {
		int sn, sc;
		scanf("%d %d", &sn, &sc);
		if (sc >= 80) {
			printf("学号:%d 成绩:%d\n", sn, sc);
		}
	}
	return 0;
}

3.判定2000~2500年中的每一年是否为闰年,并将结果输出

闰年的判定条件:
1.能被4整除,但不能被100整除
2.或者能被400整除

#include<stdio.h>
int main() {
	for (int year = 2000; year <= 2500; year ++) {
		if (year % 4 == 0) {
			if (year % 100 != 0) { // 能够被4整除但是不能被100整除
				printf("%d年是闰年\n", year);
			} else {
				if (year % 400 == 0) { // 能够被400整除
					printf("%d年是闰年\n", year);
				} else {
					printf("%d年不是闰年\n", year);
				}
			}
		} else {
			printf("%d年不是闰年\n", year);
		}
	}
	return 0;
}

4.求1-1/2+1/3-1/4+…+1/99-1/100

#include<stdio.h>
int main() {
	int sign = 1;
	double sum = 0;
	for (int i = 1; i <= 100; i++) {
		sum += sign * 1.0 / i; //类型向上转换
		sign *= -1;
	}
	printf("1-1/2+1/3-1/4+...+1/99-1/100 = %.2lf\n", sum);
	return 0;
}

5.给出一个大于或等于3的正整数,判定它是不是一个素数

素数:是指除了1和该数本身之外,不能被其他任何整数整除的数。

#include<stdio.h>
#include<math.h>
int main() {
	int n;
	scanf("%d", &n);
	bool flag = true;
	for (int i = 2; i <= sqrt(n); i++) {
		if (n % i == 0) {
			flag = false;
			break;
		}
	}
	if (flag) {
		printf("%d是素数\n", n);
	} else {
		printf("%d不是素数\n", n);
	}
	
	return 0;
}

n不必被2~(n-1)的数整除,只须被2~n/2的数整除即可,甚至只须被2~(n开根号)的数整除即可

四、算法的特性

1.有穷性:

  • 一个算法应包含有限的操作步骤,而不能是无限的。
  • “有穷性”往往指“在合理的范围之内”

2.确定性

  • 算法中的每一个步骤都应当是确定的,而不应当是含糊的、模棱两可的
  • 算法中的每一个步骤应当不致被解释成不同的含义,而应是明确无误的
  • 也就是说,算法的含义应当是唯一的,而不应当产生“歧义性”

3.有零个或多个输入

  • 所谓输入是指在执行算法时需要从外界取得必要的信息

4.有一个或多个输出

  • 算法的目的是为了求解,“解”就是输出

5.有效性

  • 算法中的每一个步骤都应当能有效地执行,并得到确定的结果

五、怎样表示一个算法

1.用自然语言表示算法

  • 自然语言就是人们日常使用的语言
  • 用自然语言表示通俗易懂,但文字冗长,容易产生歧义
  • 自然语言表示的含义往往不大严格,要根据上下文才能判断其正确含义
  • 用自然语言来描述包含分支和循环的算法不大方便
  • 除了那些很简单的问题以外,一般不用自然语言表示算法

2.用流程图表示算法

  • 流程图就是用一些图框来表示各种操作
  • 用图形表示算法,直观形象,易于理解

常用的流程图符号:
在这里插入图片描述

  • 菱形框:对一个给定的条件进行判断,根据给定的条件是否成立决定如何执行其后的操作。它有一个入口,两个出口
  • 连接点(小圆圈):用于将画在不同地方的流程线连接起来。用连接点可以画不下分开来画。用连接点可以避免流程线交叉或过长,使流程图清晰
  • 注释框:不是流程图中必要的部分,不反应流程和操作,只是为了对流程图中某些框的操作做必要的补充说明

1.求1*2*3*4*5

在这里插入图片描述

2.有50个学生,要求输出成绩在80分以上的学生的学号和成绩

在这里插入图片描述

3.判定2000~2500年中的每一年是否为闰年,并将结果输出

在这里插入图片描述

4.求1-1/2+1/3-1/4+…+1/99-1/100

在这里插入图片描述

5.给出一个大于或等于3的正整数,判定它是不是一个素数

在这里插入图片描述

3.三种基本结构和改进的流程图

1.传统流程图的弊端

  • 传统的流程图用流程线指出各框的执行顺序,对流程线的使用没有严格限制。
  • 因此,使用者可以不受限制地使流程随意地转来转去,使流程图变得毫无规律,阅读时要花很大精力去追踪流程,使人难以理解算法的逻辑
  • 这种如同乱麻一样的算法成为BS型算法,意为一碗面条(a bowl of spaghetti)

为了提高算法的质量,使算法的设计和阅读方便,必须限制箭头的滥用,即不允许无规律地使流程随意转向,只能顺序地进行下去。

  • 但是,算法上难免会包含一些分支和循环,而不可能全部由一个个顺序框组成。
  • 为了解决这个问题,人们规定出几种基本结构,然后由这些基本结构按一定规律组成一个算法结构

2.三种基本结构

1.顺序结构:A和B两个框是顺序执行的
即在执行完A框所指定的操作后,必然接着执行B框所指定的操作

2.选择结构:又称选取结构或分支结构
此结构中必包含一个判断框。根据给定的条件P是否成立而选择执行A框或B框

3.循环结构:又称重复结构,即反复执行某一部分的操作

  • 当型(while型)循环结构:当给定的条件P1成立时,执行A框操作
  • 直到型(until型)循环结构:先执行A框,然后判断给定的P2条件是否成立,如果P2条件不成立,则再执行A

以上3种基本结构,有以下共同特点:

  1. 只有一个入口
  2. 只有一个出口:一个判断框有两个出口,而一个选择结构只有一个出口
  3. 结构内的每一部分都有机会被执行到:对每一个框来说,都应当有一条从入口到出口的路径通过它
  4. 结构内不存在“死循环”

由以上3种基本结构顺序组成的算法结构,可以解决任何复制的问题

  • 由基本结构所构成的算法属于“结构化”算法,它不存在无规律的转向,只在基本结构内才允许存在分支和向前和向后的跳转

4.用N-S流程图表示算法

既然用基本结构的顺序组合可以表示任何复杂的算法结构,那么,基本结构之间的流程线就是多余的了

N-S结构化流程图:完全去掉了带箭头的流程线。全部算法写在一个矩形框内,在该框内还可以包含其他从属于它的框,或者说,由一些基本的框组成一个大的框

N-S流程图用以下的流程图符号:

  • 1.顺序结构:
    在这里插入图片描述
  • 2.选择结构:
    在这里插入图片描述
  • 3.循环结构:
    当型循环结构:
    在这里插入图片描述

直到型循环结构:
在这里插入图片描述

A框或B框,可以是一个简单的操作(如读入数据或打印输出等),也可以是3种基本结构之一

1.求1*2*3*4*5

在这里插入图片描述

2.有50个学生,要求输出成绩在80分以上的学生的学号和成绩

在这里插入图片描述

3.判定2000~2500年中的每一年是否为闰年,并将结果输出

在这里插入图片描述

4.求1-1/2+1/3-1/4+…+1/99-1/100

在这里插入图片描述

5.给出一个大于或等于3的正整数,判定它是不是一个素数

在这里插入图片描述

5.用伪代码表示算法

  • 用传统的流程图和N-S图表示算法直观易懂,但画起来比较费事,在设计一个算法时,可能要反复修改,而修改流程图是比较麻烦的。
  • 流程图适于表示一个算法,但在设计算法过程中常用一种称为伪代码的工具
  • 伪代码是用介于自然语言和计算机语言之间的文字和符号来描述算法
  • 用伪代码写算法并无固定的、严格的语法规则,只要把意思表达清楚,便于书写和阅读即可,书写的格式要写成清晰易读的形式
  • 但是用伪代码写算法不如流程图直观,可能会出现逻辑上的错误(例如循环或选择结构的范围弄错等)

6.用计算机语言表示算法

  • 要完成一项工作,包括设计算法和实现算法两个部分。
  • 在用流程图或伪代码描述一个算法后,还要将它转换成计算机语言程序
  • 用计算机语言表示算法必须严格遵循所用的语言的语法规则

六、结构化程序设计方法

  • 一个结构化程序就是用计算机语言表示的结构化算法,用3种基本结构组成的程序必然是结构化程序
  • 结构化程序设计强调程序设计风格和程序结构的规范化,提倡清晰的的结构
  • 结构化程序设计方法的基本思路是:把一个复杂问题的求解过程分阶段进行,每个阶段处理的问题都控制在人们容易理解和处理的范围内

采取以下方法来保证得到结构化的程序:

  1. 自顶向下
  2. 逐步细化
  3. 模块化设计
  4. 结构化编码

自顶向下、逐步细化:这种设计方法的过程是将问题求解由抽象逐步具体化的过程

  • 在程序设计中常采用模块设计的方法,尤其当程序比较复杂时,更有必要。
  • 程序中的子模块在C语言中通常用函数来实现
  • 程序中的子模块一般不超过50行,这样的规模便于组织,也便于阅读
  • 划分子模块时应注意模块的独立性,即使用一个模块完成一项功能,耦合性越少越好
  • 模块设计的思想实际上是一种“分而治之”的思想,把一个大任务分为若干个子任务,每一个子任务就相对简单了

结构化编码:将已设计好的算法用计算机语言来表示,即根据已经细化的算法整齐地写出计算机程序


总结

本章只是初步介绍了有关算法的基本知识

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值