第一章 数据结构论叙
1.1什么是数据结构?
数据:所有能够输入到计算机中且能够被处理的
数据结构:数据对象+结构。。。就这对数据之间的关系构成结构
1.1.1数据之间的关系(脑子版本)
逻辑结构类型:集合(莫得关系),线性结构(一对一),树形结构(一对多),图形结构(多对多)
前驱元素,后继元素,终端元素
1.1.2储存结构类型(计算机版本)
顺序储存结构:
逻辑上相邻的元素,物理上存放也是相邻的。数组什么的。
链式存储结构
每个节点的元素不一定是连续的,逻辑上相邻的元素,在物理上存储不是相邻的,用指针来表示逻辑关系。链表是这种。
索引存储结构
类似字典的那种结构
哈希散列结构
哈希表底层使用的也是数组机制,数组中也存放对象,而这些对象往数组中存放时的位置比较特殊,当需要把这些对象给数组中存放时,那么会根据这些对象的特有数据结合相应的算法,计算出这个对象在数组中的位置,然后把这个对象存放在数组中。而这样的数组就称为哈希数组,即就是哈希表。
就是一个数据该存在那里,是算出来的。
1.1.3数据运算
数据运算就是对数据的操作(则行家,删除,查找,修改等等)
层次:运算描述(人脑)+运算实现(计算机层次)
1.2认识一个新的数据结构
1.2.1ADT
(一种抽象逻辑表示,理解为模型)
定义一个复数
ADT complex{
数据对象:D={real, image | real∈实数, image∈实数}
数据关系:R={<real,image>}
基本操作:
InitComplex(&C)
操作结果:构造一个复数。
GetReal(C, &real)
初始条件:复数C存在。
操作结果:用real返回复数C的实部。
GetImage(C, &image)
初始条件:复数C存在。
操作结果:用image返回复数C的虚部。
OutputComplex(C)
初始条件:复数C存在。
操作结果:输出复数C的值。
Add(C1,C2,&C)
初始条件:复数C1,C2存在。
操作结果:用复数C返回复数C1,C2的和。
Sub(C1,C2,&C)
初始条件:复数C1,C2存在。
操作结果:用复数C返回复数C1,C2的差。
Mul(C1,C2,&C)
初始条件:复数C1,C2存在。
操作结果:用复数C返回复数C1,C2的乘积。
Div(C1,C2,&C)
初始条件:复数C1,C2存在。
操作结果:用复数C返回复数C1除以C2的值。
}ADT Complex
1.3算法
解决一系列问题的骚操作加算法
-
算法的特性
有限性,确定性,可行性,输入和输入
-
算法和程序的关系
程序:使用某种计算机语言对一个算法的具体实现。
算法:重于对解决问题的方法描述,即要干啥。可用自然语言,类语言,高级语言。
-
算法设计的要求:
正确性,可读性,健壮性,高效率低储存量。
1.5算法分析(重点内容)
-
主要包含两个方面:正确性和成本
正确性是基本的,成本就是评价算法优劣的,当然执行时间和运行所用储存空间就是判断方式。
1.5.1算法执行时间分析方式
1.5.1.1事后分析统计法:
跑一遍再说。
1.5.1.2事前估算分析方法:
观察:问题的规模是决定计算成本的主要因素(处理10组数据和10000组数据emm)
如果数据规模为n,那么运行时间会和n有关系,我们可以把它写成关于n的函数
算法时间比较本质是算法中语句执行次数的比较(语句频度),语句频度是问题规模n的函数,我们用T(n)
表示算法的执行时间,通过比较不同算法的T(n)
大小来得出算法执行时间的好坏。
渐进分析
渐进分析是指:在问题规模足够大后,计算成本如何增长?
渐进分析:大O记号——T(n) = O(f(n))
T(n) = O(f(n))表示存在一个正的常数C,使得当n≥n 0 时都满足:
|T(n)|≤C|f(n)|
– f(n)是T(n)的 上界
– 这种上界可能很多,通常取最接近的上界,即紧凑上
界
大O记号的求解:直接取最高次项,去掉系数。例:
T
(
n
)
=
2
n
2
+
2
n
+
1
=
O
(
n
2
)
T(n) = 2n^2 +2n+1 = O(n^2 )
T(n)=2n2+2n+1=O(n2)
这里描述起来相对繁琐,以以下例子来表示:
- 顺序结构的时间复杂度为O(1)
int sum = 0, n = 100;
sum = (1 + n) * n / 2;
sum = (1 + n) * n / 2;
sum = (1 + n) * n / 2;
sum = (1 + n) * n / 2;
printf(“%d”, sum);
//明显这段代码执行次数为长输,语句频度是恒定的,是常数阶
//一般来讲,莫得循环
- 线性阶 O(n)
int i;
for (i=1; i<= n; i++)
x=x+1;
//一重循环
- 平方阶 O(n2 )
for (i=1; i<= n; i++)
for (j=1;j<= n; j++)
x=x+1; //这句叫做基本操作
//二重循环->推广到多重
- O(log n)
int count = 1;
while (count < n)
{
count = count * 2;
}
我们设基本操作执行x次,则在以下情况会退出循环
2
x
=
n
2^x = n
2x=n
算出来发现 x = log2n,因此这段程序的时间复杂度是O(log n)
- 数据结构中常见的时间复杂度的比较关系
Ps: n log2n叫二维型
最坏时间复杂度
定义:讨论算法在最坏情况下的时间复杂度,即分析最坏情况下估计出算法执行时间的上界。通常除非指定,我们提到的运行时间都是最坏情况的运行时间。与之相对的是平均时间复杂度,是算法的期望运行时间。(概率统计)
1.5.2算法的空间复杂度
定义:用于度量一个算法在运行过程中临时占用的空间大小。
一般是以问题规模n为变量的函数,采用数量级形式描述,记为:
S
(
n
)
=
O
(
f
(
n
)
)
S(n)=O(f(n))
S(n)=O(f(n))
例子
- 若算法执行所需要的辅助空间为常数 时间复杂度为O(1)
- 举个栗子为 O(n)
for( i = 0; i < n; i++)
b[i] = a[n-i-1];
for( i = 0; i < n;i++)
a[i] = b [i];