- 程序设计的实质:数据表示和数据处理
-
(1)如何存储:数据要能被计算机处理,首先必须能够存储在计算机的内存中,这项任务称为 数据表示 ,其核心是 数据结构
-
(2)如何处理:一个实际问题的求解必须满足各项处理要求,这项任务称为 数据处理 ,其核心是 算法
-
1.1 数据结构在程序设计中的作用
- 图灵奖获得者沃斯给出的公式:程序 = 数据结构 + 算法
1.2 本书讨论的主要内容
-
计算机能够求解的问题一般可以分为 数值问题 和 非数值问题
- 数值问题抽象出的数据模型通常是数学方程
- 非数值问题抽象出的数据模型通常是线性表、树、图等数据结构
-
非数值问题的数据组织和处理
-
(1)数据的逻辑结构:线性表、树、图等数据结构,其核心是如何组织待处理的数据以及数据之间的关系的
-
(2)数据的存储结构:如何将线性表、树、图等数据结构存储到计算机的存储器中,其核心是如何有效的存储数据以及数据之间的逻辑关系的
-
(3)算法:如何基于数据的某种存储结构实现插入、删除、查找等基本操作,其核心是如何有效的处理数据
-
(4)常用数据处理技术:包括查找技术、排序技术、索引技术
-
1.3 数据结构的基本概念
1.3.1 数据结构
-
数据:是信息的载体,在计算机科学中是指所有能输入到计算机中并能被计算机程序识别和处理的符号集合
- 分类:两类
- (1)数值数据:整数、实数等
- (2)非数值数据:文字、声音、图形和图像等
- 分类:两类
-
数据元素:是 数据的基本单位 ,在计算机程序中通常作为一个整体进行考虑和处理
-
数据项:构成数据元素的不可分割的最小单位
- eg:档案中的一条学生记录(数据元素)中的姓名(数据项)
-
数据元素定义:一般来说,能独立、完整的描述问题世界的一切实体都是数据元素
- eg:对弈中的棋局、一年中的四季、教学计划中的一门课程、一次学术报告、遗产足球比赛
-
-
数据结构:指相互之间存在一定关系的数据元素的集合。根据视点的不同分为逻辑结构(人)和存储结构(计算机)两种。
视点 分类 特点 面向问题 数据的逻辑结构(通俗来讲的“数据结构”) 是从具体问题抽象出来的数据模型,反映了数据元素之间的关联方式或邻接关系 面向计算机 数据的存储结构 基本目标是将数据及其逻辑关系存储到计算机的内存中 -
注意:数据元素是讨论数据结构时涉及的最小数据单位,数据项一般不考虑
-
(1)数据的逻辑结构:指数据元素之间逻辑关系的整体
-
根据数据元素之间的逻辑关系(关联方式或邻接方式)不同,数据结构分为以下四类
序号 名称 含义 1⃣ 集合 数据元素之间就是“属于同一个集合”,除此之外,没有任何关系 2⃣ 线性结构 数据元素之间存在着 一对一 的线性关系 3⃣ 树结构 数据元素之间存在着 一对多 的层次关系 4⃣ 图结构 数据元素之间存在着 多对多 的任意关系 -
逻辑结构常用 逻辑关系图 表示:数据元素作为节点,使用有向/无向连线链接
-
-
(2)数据的存储结构:又称为物理结构,是数据及其逻辑结构在计算机中的表示。换言之,存储结构除了存储数据元素之外,必须隐式或显式的存储数据元素之间的逻辑关系。
-
1⃣ 顺序存储结构(隐式):用一组 连续 的存储单元 依次 存储数据元素,数据元素之间的逻辑关系由元素的 存储位置 来表示
-
2⃣ 链接存储结构(显式):用一组 任意 的存储单元存储存储数据元素,数据元素之间的逻辑关系用 指针 来表示
-
-
1.3.2 抽象数据类型
1、数据类型
-
定义:是一组 值的集合 以及定义于这个值集之上的 一组操作 的总称
-
作用:规定了该类型数据的取值范围和对这些数据所能采取的操作
- eg:int类型的表示整数运算,能够进行算术运算、关系运算(==、<等)、逻辑运算(||、&&等)
2、抽象
-
定义:所谓抽象,就是抽出问题本质的特征而忽略非本质的细节,是对具体事物的一个概括
- eg:地图是对所描述地域的抽象
-
作用:一旦一个抽象的问题得到结局,则很多同类的具体问题便可迎刃而解
- eg:将重复执行的代码抽象出一个函数
3、抽象数据类型
-
定义:抽象数据类型(abstract data type,简称ADT)是一个数据结构以及定义在该结构上的一组操作的总称
-
数据类型与ADT的区别:数据类型指的是高级程序设计语言支持的 基本数据类型 ,而ADT指的是自定义的数据类型(eg:Java中的引用数据类型)
1.4 算法及算法分析
1.4.1 算法及其描述方法
1、什么是算法
-
定义:算法是对特定问题求解步骤的一种描述,是指令的有限序列
-
算法必须满足的5个重要特性:
-
(1)输入:一个算法有零个或多个输入(即算法可以没有输入)
- 这些输入通常取自于某个特定的对象集合
-
(2)输出:一个算法有一个或多个输出(即算法必须要有输出)
- 通常输出与输入之间有着某种特定的关系
-
(3)有穷性:一个算法必须总是(对任何合法的输入)在执行有穷步之后结束,且每一步都在有穷时间内完成
-
(4)确定性:算法中的每一条指令必须有确切含义,不存在二义性。并且,在任何条件下,对于相同的输入只能得到相同的输出
-
(5)可行性:算法描述的操作可以通过已经实现的基本操作执行有限次来实现
-
-
程序与算法的关系:程序是对一个算法使用某种程序设计语言的具体实现,原则上,算法可以用任何一种程序设计语言实现
- 算法的有穷性意味着不是所有的计算程序都是算法(eg:无限循环)
2、什么是“好”算法
-
(1)正确性:对于任何合法的输入、算法都会得出正确的输出
-
(2)鲁棒性(健壮性):对非法输入的抵抗能力,即对于错误的输入,算法应能识别并作出处理,而不是产生错误动作或陷入瘫痪
-
(3)简单性:算法容易理解和实现
-
(4)抽象分级
-
(5)高效性:具有较短的执行时间并占用较少的辅助空间
3、算法的描述方法
-
(1)自然语言
-
(2)流程图
-
(3)程序设计语言
-
(4)伪代码
1.4.2 算法分析
1、度量算法效率的方法
-
(1)事后统计
-
方法:先将算法实现,然后输入适当的数据运行,测算其时间和空间开销
-
缺点:
- 1⃣ 编写程序实现算法将花费较多的时间和精力
- 2⃣ 所得的实验结果依赖于计算机的软硬件等环境因素
-
-
(2)事前分析估算
- 方法:渐进复杂度,它是对算法所消耗资源的一种估算方法
2、算法的时间复杂度
-
影响算法时间代价的主要因素——问题规模:指输入量的多少
-
eg:找出100以内的素数,问题规模是100
-
运行算法所需要的时间T是问题规模n的函数,记做 T(n)
-
-
基本语句:是执行次数与整个算法的执行次数成正比的语句
- 为了客观的反映一个算法的执行时间,可以用算法中基本语句的执行次数来度量算法的工作量
-
时间复杂度:算法中 基本语句的执行次数 在渐进意义下的阶,称作算法的渐进时间复杂度,简称时间复杂度,通常用大“O”表示
-
在计算时,可忽略所有低次幂,以及高次幂的常系数
-
eg:
- 1⃣ 常量阶:++x,时间复杂度为O(1)
- 2⃣ 线性阶:单个循环体n次循环执行++i,时间复杂度为O(n)
- 3⃣ 平方/立方阶:两个/三个循环体嵌套n的平方或立方次执行++i,时间复杂度为O(n²)/O(n³)
- 4⃣ 对数阶:
基本语句执行次数T(n)<= log2n (2为底),时间复杂度为O(log2n)(2为底)for(int i = 1; i <= n; i = 2 * i) { ++x; }
-
常见的时间复杂度:
O(log2n)(2为底) < O(n) < O(n * log2n)(2为底) < O(n²) < O(n³) < ··· < O(2的n次方) < O(n!)
- 具有多项式时间复杂度的算法是可以接受的、可使用的算法
- 具有指数时间复杂度的算法,只有当问题规模足够小时才是可以使用的算法
-
3、最好、最坏和平均情况
-
出现原因:对于某些算法,即使问题规模相同,如果输入数据不同,其时间开销也不同
-
应用:
- (1)最好情况:出现概率较大时的分析
- (2)最坏情况:实时系统
- (3)平均情况:已知数据分布(通常假设等概率分布)
4、算法的空间复杂度
- 定义:算法的空间复杂度是指在算法的执行过程中,需要的 辅助空间 数量
- 通常记做:
S(n) = O(f(n))
- 通常记做: