绪论
前言
文章目录
数据是珍贵的东西,比系统本身更持久。
基本数据组织和数据处理的方法:
- 各种数据的逻辑结构描述。
- 各种数据的存储结构表示。
- 各种数据结构的运算定义。
- 设计实现运算的算法。
- 分析算法的效率。
学习目标
- 掌握数据结构的基本概念,基本原理和基本方法。
- 掌握数据的逻辑结构,存储结构及基本运算的实现过程。
- 掌握算法基本的时间复杂度与空间复杂度的分析方法,能够设计出求解问题高效算法。
学习方法
- 理解各种数据结构的逻辑特性和存储结构设计。
- 掌握各种数据结构算法设计的基本方法。
- 利用各种数据结构来求解实际问题。
- 演绎和归纳相结合。
A、什么是数据结构
1.数据:
所有能够输入到计算机中,且能被计算机处理的符号的集合。
2.数据项:
用于描述数据元素,是数据的最小单位。
3.数据对象:
具有相同性质的若干个数据元素的集合,如整数数据对象是所有整数的集合。
4.数据结构:
是指带结构的数据元素的结合。
数据结构=数据对象+结构
数据结构中讨论的元素关系主要是指相邻关系或邻接关系。
数据结构的构成
逻辑结构+存储结构+数据运算
-
逻辑结构:
数据元素之间的逻辑关系。
学生表的逻辑结构表示二元数组,二元组是一种通用的逻辑结构表示方法。
-
存储结构:
数据元素及其关系在计算机存储器中的存储方式。 -
数据运算:
施加在该数据上的操作。
1.数据的逻辑结构表示
每个关系用若干个序偶来表示:
序偶<x,y>(x,y ∈ \in ∈ D) ⇒ \Rightarrow ⇒x为第一元素,y为第二元素。
x为y的前驱元素,y为x的后继元素。
若某元素没有前驱元素,则该元素为开始元素,若某元素没有后继元素,则该元素为终端元素。
序偶<x,y>表示x,y是有向的,序偶(x,y)表示x,y是无项的。
2.数据的存储结构表示
设计存储结构的这种映射应满足两个要求:
- 存储所有元素
- 存储数据间的关系
1.学生表存储结构1——结构体数组
由此可看出:两个逻辑上相邻的元素,其存储空间也相邻。
这种存储空间结构(顺序存储结构)的特点:
- 所有元素占用一整块内存空间。
- 逻辑上相邻的元素,物理上也相邻。
2.学生表存储结构2——链表
这种存储结构(链式存储结构)的特点:
- 一个逻辑元素用一个结点储存,每个结点单独分配,所有结点的地址不一定是连续的。
- 用指针来表示逻辑关系。
3.数据运算
数据运算分两个层次:
运算描述和运算实现。
结论:
- 同一逻辑结构可以对应多种存储结构。
- 同样的运算,在不同的存储结构中,其实现过程是不同的。
一、逻辑结构类型
1.集合
元素之间的关系:无
特点:数据之间属于同一集合。
2.线性结构
元素之间的关系:一对一
特点:开始元素与终端元素唯一,另外,其余元素有且仅有一个前驱元素和一个后继元素。
3.树形结构
元素之间的关系:一对多
特点:开始元素唯一,终端元素不唯一。另外,每个元素有一个或多个后继元素(除终端元素),么个元素有且仅有一个前驱元素(除开始元素)。
4.图形结构
元素之间的关系:多对多
特点:所有元素都有可能有多个前驱元素和多个后继元素。
二、存储结构类型
- 顺序存储结构
- 链式存储结构
- 索引存储结构
- 哈希存储结构
数据类型和抽象数据类型
1.数据类型:
是一个值的集合和定义在此集合上的一组操作的总称。
2.抽象数据类型(ADT):
指从求解问题的数学模型中抽象出来的数据结构和运算,不考虑计算机的运算。
抽象数据类型=逻辑结构+抽象运算
B、什么是算法
通常把基于存储结构的运算实现的步骤或过程称为算法。
1.算法的五个重要特性
- 有穷性:在有穷步之后结束,算法能够停机。
- 确定性:无二义性。
- 可行性:可通过基本运算有限次执行来实现,即每一个动作都能被机械地执行。
- 输入:0个或多个输入。
- 输出:1个或多个输出。
2.算法与程序的区别
程序指的是某种计算机语言对一个算法的具体实现,及具体怎么做。而算法侧重于对解决问题的方法的描述,即要做什么。算法用计算机语言描述就得到程序。
3.算法描述
参数传递:
例如,设计一个算法
代码实现:
#include<iostream>
#include<cmath>
using namespace std;
void solution(float a, float b, float c, float& x1, float& x2);
int main()
{
float a, b, c,m,x1,x2;
cout << "请输入a,b,c的值:" << endl;
cout << "a=";
cin >> a;
cout << "b=";
cin >> b;
cout << "c=";
cin >> c;
cout << "求得的方程的根为:";
solution(a, b, c, x1, x2);
return 0;
}
void solution(float a, float b, float c, float& x1, float& x2)
{
float d;
d = b * b - 4 * a * c;
if (d > 0)
{
x1 = (-b + sqrt(d)) / (2 * a);
x2 = (-b - sqrt(d)) / (2 * a);
cout << x1 << " " << x2 << endl;
}
else if (d == 0)
{
x1 = (-b) / (2 * a);
cout << x1 << endl;
}
else
cout << "该方程无实根!";
}
4.算法分析
算法分析的目的:
分析算法的时空效率以便改进算法性能。
一、算法时间复杂度分析
一个算法是由控制结构(顺序,分支和循环)和原操作构成的。
顺序结构:按照所述顺序处理。
分支结构:根据判断条件改变执行流程
循环结构:当条件成立时,反复执行给定的处理操作。
原操作:指固有数据类型的操作,如+,-,*,/,++,–等。
算法的执行时间取决于两者的综合效果。
例如:
算法分析方式
1.事后分析统计方法:
编写算法对应程序,统计其执行时间。
2.事前估算分析方法:
撇开上述因素,认为算法执行时间是问题规模n的函数。
分析算法执行时间
- 求出算法所有原操作的执行次数(也称为频度),它是问题规模n的函数,用T(n)表示。
- 算法执行时间大致=原操作所需时间*T(n)。所以T(n)与算法的执行时间成正比。为此用T(n)表示算法的执行时间。
- 比较不同算法的T(n)大小得出算法执行时间的好坏。
T(n)表示求解问题大小的正整数,如n个记录排序。
例如:求两个n阶方阵的相加C=A+B的算法如下,分析其时间复杂度。
伪代码:
#define NAX=28
voidmatrixadd(int n,int A[MAX][MAX],int B[MAX][MAX],int C[MAX][MAX])
{
int i,j;
for(i=0;i<n;i++) //1
for(j=0;j<n;j++) //2
C[i][j]=A[i][j]+B[i][j]; //3
}
除变量定义语句外,该算法包括3个可执行语句1,2和3。
1.频度为n+1,循环体执行n次。
2.频度为n*(n+1)。
3.频度为n*n。
因此,所有语句频度之和为:
算法执行时间用时间复杂度来表示:
算法中执行时间T(n)是问题规模n的某个函数f(n),记作:
T(n)=O(f(n))
"O"表示随问题规模n的增大算法执行时间的增长率和f(n)的增长率相同。
"O"的形式定义为:
T(n)=O(f(n))表示存在一个正的常数c,使得当n>=n0时都满足:
|T(n)|<=|c(f(n)|
f(n)是T(n)的上界,
通常有:
也即只求出T(n)的最高阶,忽略其低阶项和常系数,这样既可以简化T(n)的计算,又能比较客观地反映当n很大时算法的时间性能。
一般地:
- 一个没有循环的算法的执行时间与问题规模n无关,记作0(1),也称作常数阶。
- 一个只有一重循环的算法的执行时间与问题规模n的增长呈线性增大关系,记作0(n),也称线性阶。
各种不同算法时间复杂度的比较关系如下:
算法时间性能比较:
假如求同一问题有两个算法:A和B,如果算法A的平均时间复杂度为0(n),而算法B的平均复杂度为0(n*n)。
一般情况下,认为算法A的时间性能比算法B好。
简化的算法时间复杂度的分析
算法中的基本操作一般是最深层循环内的原操作。
算法执行时间大致=基本操作所需的时间*其运算次数
在算法分析时,计算T(n)时仅仅考虑基本操作的运算次数。
最好、最坏和平均时间复杂度分析
定义:设一个算法的输入规模为n,Dn是所有输入的集合,任意输入I ∈ \in ∈Dn,P(I)是I出现的概率,有 ∑ \displaystyle\sum ∑P(I)=1,T(I)是算法输入I下的执行时间,则算法的平均时间复杂度为:
例如:10个1~10的整数序列递增排序。(n=10):
所有可能的初始序列有m个,m=10! ⇒ \Rightarrow ⇒P(I)=1/m。
解:
算法的主要时间花费在元素比较上:
- i的取值范围为1~n,共n种情况。
- 在等概率的情况(每种情况的概率为1/n).
- 求前i个元素的最大值时,max=a[0],将其与a[1…i-1]元素进行比较。比较次数=(i-1)-1+1=i-1次。
- i=1时,比较次数为0 ⇒ \Rightarrow ⇒算法的最好复杂度B(n)=0(1)。
- i=n时,比较次数为n-1 ⇒ \Rightarrow ⇒算法的最坏复杂度W(n)=0(n)。
二、算法空间复杂度的分析
空间复杂度:
用于度量一个算法运行过程中临时占用的内存空间的大小。
一般也作为问题规模n的函数,采用数量级形式描述,记作:
S(n)=0(g(n))
若一个算法的空间复杂度为0(1),则称此算法为原地工作或就地工作算法。
空间复杂度考虑临时占用的存储空间