注:定义方面了解即可,不会考
一、什么是数据结构
1、名词术语
(1)数据:描述客观事物的数字、字符以及一切能够输入到计算机中,并且能够被计算机程序处理的符号的集合
(2)数据元素:数据这个集合中的一个一个的元素
(3)数据对象:具有相同特性的数据元素的集合
(4)结构:数据元素之间具有的关系(联系)
2、举例
(1)数列:(2,13,21,35,80,52,7)
(2)字母表:(’A’,’B’,’C’,…,’Z’)
(3)数据文件:
以数据文件为例,每一行代表某个人的个人信息,即一个数据元素,每一列分别代表学号、姓名、性别、年龄等,是一个数据项,一个数据元素由若干个数据项组成
3、数据结构的定义
1、数据元素之间的联系称之为结构,数据结构就是具有结构的数据元素的集合。
2、数据结构是一个二元组
Data-Structure=( D, R )
其中,D是数据元素的有限集合,R是D上的关系的集合(D为某一数据对象)
1、逻辑结构
数据元素之间具有的逻辑关系(结构)
(1)线性关系
如线性表、堆栈、队列、串、文件等
(2)非线性关系
如树、二叉树、图、集合等
2、存储结构
具有某种逻辑结构的数据在计算机存储器中的存储方式(存储映象)
(1)顺序存储结构
用一组地址连续的存储单元依次存放数据元素,数据元素之间的逻辑关系通过元素的地址直接反映
(2)链式存储结构
用一组地址任意的存储单元依次存放数据元素,数据元素之间的逻辑关系通过指针间接地反映
(3)索引存储结构
- 构造原理:利用数据元素的索引关系来确定数据元素的存储位置,由数据元素本身与索引表两部分组成。
- 特点:如查找、插入和删除等操作的时间效率较高,但存储空间开销较大。
(4)散列存储结构
- 构造原理:通过事先准备好的散列函数关系与处理冲突的方法来确定数据元素的存储位置。
- 特点:诸如查找、插入和删除等操作的时间效率较高,主要缺点是确定好的散列函数比较困难。
3、举例对比
(1)逻辑结构:线性结构(线性表)
(2)存储结构:顺序存储结构
(3)存储结构:链式存储结构——用一片地址任意的存储空间
4、数据结构课程的主要内容
运算的实现依赖于存储结构——存储结构不唯一——逻辑结构唯一
二、抽象数据类型
定义:在一种程序设计语言中,变量所具有的数据种类
FORTRAN语言:整型、实型、和复数型 C语言: 基本数据类型: char int float double void
构造数据类型:数组、结构体、共用体、文件
数据类型是一组性质相同的值的集合, 以及定义于这个集合上的一组运算的总称
1、抽象数据类型
- 更高层次的数据抽象
- 由用户定义,用以表示应用问题的数据模型
- 由基本的数据类型组成, 并包括一组相关的操作
抽象类型可以用以下的三元组来表示:ADT = (D,S,P)
D为数据对象 S为D上的关系集 P为D上的操作集
ADT常用定义格式:
ADT抽象数据类型名{
数据对象:<数据对象的定义>
数据关系:<数据关系的定义>
基本操作 :<基本操作的定义>
} ADT抽象数据类型名
2、抽象数据类型的表示与实现
抽象数据类型可以通过固有的数据类型(如整型、实型、字符型等)来表示和实现。
它有些类似C语言中的结构(struct)类型,但增加了相关的操作
(1)预定义常量及类型
//函数结果状态代码
#define OK 1
#define ERROR 0
#define OVERFLOW -2
// Status是函数返回值类型,其值是函数结果状态代码。
typedef int Status;
(2)数据元素被约定为ElemType 类型
用户需要根据具体情况,自行定义该数据类型。
(3)算法描述为以下的函数形式:
函数类型 函数名(函数参数表)
{
语句序列;
}
三、算法及其描述
1、算法及其性质
(1)算法的定义
- 算法是用来解决某个特定课题的指令的集合。
- 算法是由人们组织起来准备加以实施的一系列有限的基本步骤。
- 算法是一组解决问题的清晰指令,它能够对符合一定规范的输入,在有限的时间内获得所需要的输出。
算法不是问题解决的答案,而是获得答案的过程。
(2)算法的性质:
一个完整的算法应该具有下面五个基本特性:
A.输入
由算法的外部提供n≥0个有限量作为算法的输入
B.输出
由算法的内部提供n>0个有限量作为算法的输出
C.有穷性
算法必须在有限的步骤内能够结束
D.确定性
组成算法的每一条指令必须有清晰明确的含义
E.可行性
算法的每一条指令必须具有可执行性
2、算法的描述
(1)采用自然语言描述
问题:求两个正整数M与N的最大公因子
(1) M除以N,将余数送中间变量R;
(2)测试余数R是否等于零?
a) 若R等于零,求得的最大公因子为当前N的值, 算法到此结束。
b) 若R不等于零,则将N送入M,将R送N, 重复算法的(1)和(2)。
(2)采用流程图
(3)设计一种既脱离某种具体的程序设计语言,又具有各种程序设计语言的共同特点的形式化语言来描述。(伪代码)
(4)采用某种具体程序语言来描述
C、C++、Java等
int COMFACTOR( int M, int N )
{
int R;
while( 1 ){
R=M % N;
if(R==0)
return N;
M=N;
N=R;
}
}
四、算法分析
算法分析 是指对算法质量优劣的评价
目的:改进算法质量
前提:算法必须正确
除正确性外,通常从三个方面分析一个算法:
- 依据算法编写的程序在计算机中运行时间多少的度量,称之为时间复杂度。(反映算法运行的快慢)
- 依据算法编写的程序在计算机中占存储空间多少的度量,称之为空间复杂度(反映算法需要的额外空间的多少)
- 其他方面:如算法的可读性、可移植性以及易测试性的好坏。
1、算法效率的度量
算法效率:用依据该算法编制的程序在计算机上执行所消耗的时间来度量
(1)事后统计
利用计算机内的计时功能,不同算法的程序可以用一组或多组相同的统计数据区分
缺点:
- 必须先运行依据算法编制的程序
- 所得时间统计量依赖于硬件、软件等环境因素,掩盖算法本身的优劣
(2)事前分析估计
一个高级语言程序在计算机上运行所消耗的时间取决于:
- 依据的算法选用何种策略
- 问题的规模
- 程序语言
- 编译程序产生机器代码质量
- 机器执行指令速度
同一个算法用不同的语言、不同的编译程序、在不同的计算机上运行,效率均不同,——使用绝对时间单位衡量算法效率不合适,因此使用相对的时间进行计算
A、时间复杂度
一个程序在计算机中运行时间的多少与诸多因素有关,其中主要有:
1.问题的规模
(几乎所有算法的时间效率都与问题的规模有关)
2.编译程序功能的强弱以及所产生的机器代码质量的优劣。
3.机器执行一条指令的时间长短。
4.程序中那些关键语句的执行次数
B、频度统计法
以语句执行的次数的多少作为算法的时间度量的分析方法称为频度统计法
一条语句的频度是指该语句被执行的次数,而整个算法的频度是指算法中所有语句的频度之和
C、时间复杂度的渐进表示法
算法中基本语句重复执行的次数是问题规模n的某个函数f(n),算法的时间量度记作:
T(n)=O(f(n))
表示随着n的增大,算法执行的时间的增长率和f(n)的增长率相同,称渐近时间复杂度。
数学符号“O”的定义为:
若T(n)和f(n)是定义在正整数集合上的两个函数,则T(n) = O(f(n))表示存在正的常数C和n0,使得当n≥n0时都满足0≤T(n)≤Cf(n)。
算法中重复执行次数和算法的执行时间成正比的语句对算法运行时间的贡献最大
n越大算法的执行时间越长
- 排序:n为记录数
- 矩阵:n为矩阵的阶数
- 多项式:n为多项式的项数
- 集合:n为元素个数
- 树:n为树的结点个数
- 图:n为图的顶点数或边数
例1:
#define M 1000
void MATRIX( int A[ ][M], int B[ ][M], int C[ ][M], int n)
{
inti, j, k;
for(i=0;i<n;i++) //2n+1
for(j=0;j<n;j++){ //n(2n+1)
C[i][j]=0; //n²
for(k=0;k<n;k++) //n²(2n+1)
C[i][j]=C[i][j]+A[i][k]*B[k][j]; //n³
}
}
算法的频度: f(n)= 2n+1 + n(2n+1) + n²+ n²(2n+1) + n³
= 3n³+ 4n²+ 3n + 1
g(n)=n³
称算法的时间复杂度为O(n³)
例2:
for( i = 0; i < n; i++)
for( j = 0; j < n; j++)
c[i][j] = a[i][j] + b[i][j];
语句的频度: 重复执行的次数:n*n
T( n ) = O ( n 2) 即矩阵加法的运算量和问题的规模n的平方是同一个量级
分析算法时间复杂度的基本方法
- 找出语句频度最大的那条语句作为基本语句
- 计算基本语句的频度得到问题规模n的某个函数f(n)
- 取其数量级用符号“O”表示
例3:
x = 0; y = 0;
for ( int k = 0; k < n; k ++ )
x ++;
for ( int i = 0; i < n; i++ )
for ( int j = 0; j < n; j++ )
y ++; 该语句频度最大
T(n) = O(n²) f(n)=n²
时间复杂度是由嵌套最深层语句的频度决定的
例4:
void exam (float x[ ][ ], int m, int n ) {
float sum [ ];
for ( int i = 0; i < m; i++ ) {
sum[i] = 0.0;
for ( int j = 0; j < n; j++ )
sum[i] += x[i][j];
}
for ( i = 0; i < m; i++ )
printf(“%d : %d\n”,i,sum [i]);
}
T(n) = O(mn) f(n)=mn
例5:
for( i=1; i<=n; i++)
for (j=1; j<=i; j++)
for (k=1; k<=j; k++)
x=x+1;
例6:
i=1;
while(i<=n)
i=i*2;
即f(n)≤log2n,取最大值f(n)=log2n
所以该程序段的时间复杂度T(n) =O( log2n)
常见函数
O(1):表示算法的复杂度为常量,不随问题规模n的大小而改变。
D、渐进空间复杂度
空间复杂度:算法所需存储空间的度量,记作: S(n)=O(f(n))
其中n为问题的规模(或大小)
算法要占据的空间:
- 算法本身要占据的空间,输入/输出,指令,常数,变量等
- 算法要使用的辅助空间