数据结构的基本概念
程序设计=数据结构+算法
数据结构研究啥?
- 数据结构是一门研究非数值计算的程序设计中计算机的操作对象以及它们之间的关系和操作的学科。
基本概念
数据
- 数据:能够输入计算机并被处理的符号(数值型数据与非数值型数据)(概念最大)
- 数据元素:像是一个结构体,经常作为一个整体来考虑(结点、顶点、记录)(概念第三)例如课程
- 数据项:组成数据元素的数据项,类似于成员变量(概念第四)例如课程的具体信息
- 数据对象:性质相同的数据元素的集合(概念第二)例如课程表
注意关系:
- 数据元素是数据的基本组成,是数据这个集合中的个体
- 而数据对象是由数据元素组成的集合,是数据这个集合中的子集
数据结构
- 数据结构:数据元素相互之间的关系称为数据结构(带结构的数据元素的集合)
- 数据结构分为以下三个方面
- 逻辑结构(独立于计算机,是数学模型)
- 物理结构(在计算机中表示)
- 数据的运算与实现(施加操作)
- 逻辑结构是数据结构的抽象、存储结构是具体实现
-
逻辑结构
(1)线性结构(线性表、栈、队列、串)
(1)非线性结构(树、图)
-
存储结构
(1)顺序存储结构
(2)链式存储结构
(3)索引存储结构
(4)散列存储结构
数据类型和抽象数据类型
-
数据类型的作用:约束取值范围与操作
-
数据类型:一组性质相同的值的集合以及定义于这个集合上的一组操作
-
抽象数据类型(ADT):看本质,其实是一个数学模型以及操作
- 逻辑结构
- 抽象运算
- 不依赖具体实现
-
抽象数据类型定义:(D,S,P)三元组表示 :D—数据对象 S—关系 P—操作
-
ADT 抽象数据类型名{ 数据对象:<数据对象的定义> 数据关系:<数据关系的定义> 基本操作:<基本操作的定义> }ADT 抽象数据类型名
-
举例说明(Circle的定义)
-
ADT Circle{ 数据对象:D={r,x,y|r,x,y均为实数} 数据关系:R={<r,x,y>|r是半径,<x,y>是圆心坐标} 基本操作: Circle(&C,r,x,y):构造一个圆 double Area(C): 初始条件:圆已存在 操作结果:计算面积 double Circumference(C): 初始条件:圆已存在 操作结果:计算周长 }ADT Circle
-
举例说明(复数的定义)
-
ADT Complex{ 数据对象:D={r1,r2|均为实数} 数据关系:R={<r1,r2>|r1是实部,r2是虚部} 基本操作: assign(&Z,v1,v2):构造一个复数 destroy(&Z): 初始条件:复数已存在 操作结果:销毁复数 }ADT Complex
抽象数据类型的实现
-
typedef struct{ float realpart; float imagpart; }Complex; void assign(Complex *A,float real,float imag); void add (Complex *c,Complex A,Complex B); void minus (Complex *A,float real,float imag); void multiply (Complex *A,float real,float imag); void divide(Complex *A,float real,float imag); void assign(Complex *A,float real,float imag) { A->realpart=real; A->imagpart=imag; } void add (Complex *c,float real,float imag) { c->realpart=A.realpart+B.realpart; c->imagpart=A.imagpart+B.imagpart; }
算法和算法分析
算法
- 算法的描述
- 自然语言(求解一元二次方程)
- 流程图(传统流程图,NS流程图)
- 伪代码(类C语言)
- 程序代码
- 算法与程序的关系
- 算法是一个解题过程,将输入转为输出,一个问题可以有多种算法
- 程序是用从程序设计语言对算法的具体实现(程序=数据结构+算法)
- 算法特性
- 有穷性(时间有限才有意义)
- 确定性(没有其他理解方式,不能模棱两可)
- 可行性(屁用没有可不行)
- 输入(可以有可以没有)
- 输出(必须要有,没有你玩个屁)
- 算法设计的要求
- 正确性(不正确设计个啥:是个人)
- 可读性(你得写人话吧:长得还行)
- 健壮性(你得身体健康)
- 高效性(你得足够有用,否则就会被淘汰)
算法分析
在基本满足正确性、可读性、健壮性的前提下,我们考虑算法的效率
-
算法分析要从以下两个方面考虑
- 时间效率
- 空间效率
- 往往是矛盾的
-
算法时间效率的度量
- 事后统计:实际运行所得,受到机器的影响大
- 事前分析:预测其运行时间
-
事前分析方法
-
算法运行时间=一个简单操作时间*次数
-
简单的操作时间我们默认相同,现在就是看次数多少了
-
举例分析:
-
for (int i=1;i<=n;i++) //n+1 { for (int j=1;j<=n;j++) //n(n+1) { c[i][j]=0; //n*n for (int k=1;k<=n;k++) //n*n*(n+1) { c[i][j]+=a[i][k]*b[k][j];// n*n*n } } }
-
T ( n ) = 2 n 3 + 3 n 2 + 2 n + 1 T(n)=2n^3+3n^2+2n+1 T(n)=2n3+3n2+2n+1
这是一个关于n的函数&这种方法过于繁琐
-
为了方便,我们采用比较数量级的方法
-
若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于0的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度(O for order,数量级),简称时间复杂度。
-
-
分析算法时间复杂度的基本方法
- 找出语句频度最大的那条语句作为基本语句
- 计算基本语句的频度得到问题规模n的某个函数f(这是重点)
- 取其数量级用符号O表示
-
同样的数据规模,时间复杂度与算法的选择有关,也与输入的数据集有关
-
时间复杂度可以分为最好时间复杂度&最坏时间复杂度&平均时间复杂度
-
对于复杂的算法,可以将它分成几个容易估算的部分,然后利用加法法则与乘法法则计算
- 加法法则:取最大的
- 乘法法则:相乘
-
时间复杂度的比较
-
空间复杂度:S(n)=O(f(n))