数据结构-王道-绪论
绪论
- 数据:客观事物的符号表示.在计算机科学中指的是所有能输入到计算机中冰杯计算机程序处理的符号的总称. 数据又分为数值型数据,非数值型数据
- 数据元素:是数据的基本单位,在程序中通常会作为一个整体来进行处理和考虑.
- 数据项:一个数据元素可由多个数据项(Data Item)组成。
- 最小单位 :数据项是数据的不可分割的最小单位,数据项是对客观事物某一方面特性的数据描述。
例如:按照学生的成绩进行排名。1:在计算机中找到学生们的数据,每一个学生的数据都是一个数据元素(基本单位),其中含有关于学生各方面属性的数据项(最小单位),然后我们按照每个学生(数据元素)的成绩(数据项)对学生(数据元素)这个整体进行排名。
- 数据对象(Data Object):是性质相同的数据元素(基本单位,整体考虑)的集合,是数据的一个子集。如字符集合\(C=\{'A','B','C',...\}\)。
- 数据结构:指的是相互之间存在一定的关系的数据元素的集合。元素之间的相互联系称为逻辑结构。
四种逻辑关系
- 集合:结构中的数据元素除了“同属于一个集合”外,没有其他的任何关系。
- 线性结构:结构中的数据元素见存在一对一的关系。
- 树形结构:结构中的数据元素之间存在一对多的关系。
- 图状结构或网状结构:结构中的数据存在多对多的关系。
储存方式
数据结构在计算机内存中的储存包括数据元素的储存和数据关系的储存。
元素之间的关系在计算机中有两种表示方法:顺序表示和非顺序表示\(\rightarrow\) 顺序储存结构和链式储存结构。
- 顺序储存结构:用数据元素在储存器中的相对位置来表示数据元素之间的逻辑结构关系。
- 链式储存结构:在每一个数据元素中增加一个存放另一个元素地址的指针(pointer),应该指针来表示顺居元素剪得逻辑结构。
数据结构的三个组成部分
- 逻辑结构:数据元素之间逻辑关系的描述\(D_S=(D,S)\)。
- 存储结构:数据元素在计算机中的储存及其逻辑关系的表现称为数据的储存结构或者物理结构。
- 数据操作:对数据进行的运算。
抽象数据类型
抽象数据类型(Abstract Data Type)简称(ADT):是指一个数学模型以及定义在该模型上的一组操作。
- ADT定义是一组逻辑特性的描述。
- ADT形式化定义是三元组:\(ADT=(D,S,P)\)
- D是数据对象,S是D上的关系集,P是对D的基本操作集。
算法
- 算法(algorithm):是对特定问题求解方法(步骤)的一种描述,是指令的有限序列,其中每一条指令表示一个或者多个操作。
特性
- 输入:有0个(也就是没输入)或者多个输入。
- 输出:有一个(没输出的话就没意义了)或多个输出。
- 确定性:每步的定义都是确切的,无歧义的。
- 有穷性:算法应该在执行有穷步之后结束。
- 可执行性:每一条运算都行该通过有限次完成。
时间/空间 复杂度
算法执行时间需要通过一句根据该算法编制的程序在执行上运行所消耗的时间来度量。
计算的方法通常有两种
- 事后统计:计算机内部进行执行的时间和实际占用空间的统计。
- 事前分析:求出该算法的一个时间/空间界限函数。
- 运行时间 \(=\) 算法每条语句执行时间的总和。(每条语句执行的时间=该语句执行的次数\(*\)语句执行一次所需的时间)。
- 语句执行一次所需的时间取决于机器的指令性能和速度和编译所产生的代码质量,很难确定。
- 通常设每条语句执行一次所需的时间为单位时间,则一个算法的运行时间就是该算法中所有语句的频度之和。
- 算法中基本操作重复执行的次数是问题规模n的某个函数,七时间度量记作\(T(n)=O(f(n))\),称作算法的渐进时间复杂度。
- 一般情况下用最深层循环内的语句中的原操作执行频度(重复执行次数)来表示。
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
c[i][j]=0;
for(int k=1;k<=n;k++)
{
c[i][j] += a[i][k]+b[k][j]
}
}
}
可以看出上述代码是一个三重循环,则时间复杂度的计算按照执行次数最多的语句来计算 \(~O(n^3)\)
{
++x;
s=0;
}
将x自增看做基本操作,则语句频度为1,时间复杂度为\(O(1)\)。
如果将s=0也看为基本操作,则语句的频度为2,其时间复杂度仍未\(O(1)\),即常量阶。
for(int i=1;i<=n;i++)
{
x++;
s+=x;
}
语句频度为:\(2n\),时间复杂度为:\(O(n)\),线性阶。
for(int i=0;i<=n;i++)
{
for(j=1;j<=n;j++)
{
x++;
s+=x;
}
}
语句频度为:\(2n^2\),时间复杂度为:\(O(n^2)\),即平方阶。
for(int i=2;i<=n;i++)
{
for(int j=2;j<=i-1;j++)
{
x++;
a[i][j]=x;
}
}
语句频度为:\(1+2+3+...+(n-2)=\frac{(1+n-2)*(n-2)}{2}\)
时间复杂度为:\(O(n^2)\)。
六种常用计算算法时间的多项式
\(O(1)<O(log_n)<O(n)<O(nlogn<O(n^2)<O(n^3)\)
指数的时间关系为:
\(O(2^n)<O(n!)<O(n^n)\)
当n取得非常大的时候,指数时间算法和多项式时间算法在所需的时间上非常的悬殊。
有的情况下,算法中基本操作重复执行的次数还随问题的输入数据集不同而不同。
素数的判断算法。
void prime(int n)
{
int i=2;
while((n%i)!=0&&i*1.0<sqrt(n))
i++;
if(i*1.0>sqrt(n))
printf("%d 是一个素数\n",n);
else
printf("%d 不是一个素数\n",n);
}
嵌套的最深层语句是i++;其频度由条件
(n%i)!=0&&i*1.0<sqrt(n)
所确定,显然i*1.0<sqrt(n),时间复杂度为\(O(n^\frac{1}{2})\)
case 1:基本语句和n无关。时间复杂度 \(O(1)\)
case 2:分裂原则\(\frac{n}{2}\) 。时间复杂度\(\log_2n\)
case 3:单一循环,依赖n。时间复杂度\(O(n)\)
case 4:双循环,分裂原则。时间复杂度\(O(n\log_2n)\)
case 5:双循环。时间复杂度\(O(n^2)\)
空间复杂度
-
指令常数变量所占用的储存空间。
-
输入数据所占用的储存空间。
-
辅助(储存)空间。
算法的空间复杂度指的是辅助空间。