数据结构 == 算法设计???
不是
数据中的新概念
-- 数据元素
组成数据的基本单位
-- 数据项
一个数据元素由若干个数据项组成
-- 数据对象
性质相同的数据元素组成的集合
struct People
{
int age;
char * name[20];
};
数据结构指的是数据对象中数据元素之间的关系
-- 数据元素之间不是独立的
存在特定的关系,这些关系即结构
-- 如:
数组中各个元素之间存在固定的线性关系
典型的逻辑结构
1、集合结构
数据元素之间没有特别的关系,仅同属相同集合。
2、线性结构
数据元素之间是一对一的关系。
3、树形结构
数据元素之间存在一对多的层次关系。
4、图形结构
数据元素之间是多对多的关系。
物理结构
-- 是逻辑结构在计算机中的存储形式
-- 顺序存储结构
将数据存储在地址连续的存储单元里。(比如:内存)
-- 链式存储结构
将数据存储在任意的存储单元里
通过保存地址的方式找到相关联的数据元素
数据结构是相互之间存在特定关系的数据元素的集合。
数据结构可以分为逻辑结构和物理结构。
数据结构静态的描述了数据元素之间的关系
高效的程序需要在数据结构的基础上设计和选择算法
高效的程序 = 恰当的数据结构 + 合适的算法
算法的本质是特定的问题求解步骤的描述。
算法的特性
-- 输入 :算法具有0个或多个输入
-- 输出 :算法具有1个或多个输出
-- 有穷性:算法在有限的步骤之后会自动结束而不会无限循环
-- 确定性:算法中的每一步都有确定的含义,不会出现二义性
-- 可行性:算法的每一步都是可行的
-- 正确性:
-- 算法对于合法数据能够得到满足要求的结果
-- 算法能够处理非法输入,得到合理的结果
-- 算法对边界数据和压力数据都能得到满足要求的结果
-- 可读性:算法要方便阅读,理解和交流
-- 健壮性:算法不应该产生莫名其妙的结果
-- 性价比:利用最少的资源得到满足要求的结果
关于有穷性,原始的定义已经不能满足现在的要求了。假如我们的算法是有穷的,但是要运行一个世纪才能得到结果,那么使用这个算法的产品就是失败的。
有穷性在现代需要重新定义:
算法的复杂度
-- 时间复杂度
算法运行之后对时间需求量的定性描述
-- 空间复杂度
算法运行之后对空间需求量的定性描述
大 O 表示法
-- 算法效率严重依赖操作(operation)数量
-- 操作数量的估算可以作为时间复杂度的估算
-- 在判断时首先关注操作数量的最高次项
O(5) = O(1)
O(2n + 1) = O(2n) = O(n)
O(n^2 + n + 1) = O(n^2)
O(3n^3 + 1) = O(3n^3) = O(n^3)
常见时间复杂度
线性阶时间复杂度 :O(n)
for(int i = 0 ; i < n ; ++i)
{
// ...
}
对数阶时间复杂度:O(logn)
int i = 1;
while( i<n )
{
// 复杂度为 O(1)的程序语句
// i *= 2;
i = i * 2;
}
平方阶时间复杂度:O(n^2)
for(int i = 0; i< n; ++i)
{
for(int j = 0 ; j<n ; ++j)
{
//复杂度为O(1)的程序语句
}
}
test1:下面代码的时间复杂度是什么??
for(int i = 0; i< n; ++i)
{
for(int j = i ; j<n ; ++j)
{
//复杂度为O(1)的程序语句
}
}
O(0.5n^2+0.5n)= O(n^2)
test2:求func()的时间复杂度
void t(int n)
{
int i = 0;
while( i < n)
{
cout << i << endl;
}
}
void func(int n)
{
int i = 0;
while( i < n )
{
t(n);
++i;
}
}
O(n^2 + n) = O(n^2 )
tset3:求test()的时间复杂度
void t(int n)
{
int i = 0;
while( i < n)
{
cout << i << endl;
}
}
void test(int n)
{
t(n);
for(int i = 0 ; i<n ;++i)
t(i);
for(int i = 0 ; i<n ; ++i)
for(int j = i ; j<n ; ++j)
t(i);
}
O(n^3 + n^2 +n)= O(n^3)