基本概念
数据结构可理解为,数据经过一定的加工,有效的存储在计算机中并实现相应的运算。计算机中的存储称之为“结点”。
数据之间的关系成为“逻辑关系”。逻辑结构常常采用二元组S=(D,R)来表示,其中D是元素的有限结合,R是定义在D上的关系集合。
存储在计算机中的数据一定要能够还原出原始数据的逻辑关系,因此需要构建出数据值和存储地址之间的某种映射关系,这种关系称为“物理关系”。相同逻辑关系的数据可能采用不同的物理结构存储,其目的一方面是方便保存数据之间的逻辑关系;另一方面是更加有效的进行相应的运算。数据存储的逻辑结构、物理结构及运算的分类如下:
数据的逻辑结构:线性结构、非线性结构。
数据的物理结构:顺序存储、链式存储、索引存储、散列存储。
数据的运算:插入、删除、查找、修改、排序。
1)线性结构
除了第一个元素,每个元素都拥有唯一一个前驱元素;除了最后一个元素,每个元素都有唯一一个后继元素,这样的数据结构称为线性结构。
2)非线性结构
一个元素可能有多个前驱元素和多个后继元素,两种典型的非线性结构分别是树和图。其中,树形结构是一对多的关系;图形结构的元素之间存在多对多的关系。
3)顺序存储
顺序存储要求逻辑上相邻的元素物理上也必须相邻,这里的“物理上”指的是内存地址,元素间的逻辑关系由存储节点的邻接关系决定。
4)链式存储
链式存储要求在存储结点信息的同时,建立附加的索引表,索引表中的每项称为索引项,索引项的一般形式为(关键字,地址),关键字能唯一地识别一个元素的所有数据项。
5)散列存储
散列存储地主要思想是基于所要存储的数据值决定所要存放地内存地址,这种存储方式便于查找,但对内存要求非常高。
算法
算法是由有穷规则构成的、为解决某一问题的运算序列。算法包括输入、输出,输入一般是算法开始时给出的初始条件,而基于这些条件得到的结果称为输出。
算法分析
算法除了正确之外,还需要考虑复杂度,包括时间复杂度和空间复杂度,往往时间复杂度更为重要。一般而言,算法的时间复杂度和和空间复杂度常常是n的函数,记作O(f(n)),其中f(n)是n的函数。当n足够大是,有下面的关系:
下面举一些典型例子
1)求n个节点的完全二叉树深度
int deeptree(int n){
int i=1;
while(i<=n)
i=i*2;
return i;
}
分析第二条while语句,假设第二条语句执行f(n)次,那么语句结束的条件为:
可以得到 ,由此可得该算法的时间复杂度为
2)选择排序
void selectsort(int[]a,int n){
int i,j,k,t;
for(i=0;i<n-1;i++){
j=i;
for(k=i+1;k<n;k++){
if(a[k]>a[j]) j=k;
}
t=a[i];
a[i]=a[j];
a[j]=t;
}
}
分析两层for循环,可以知道总共需要执行1+2+3+...+n=n(2+1)/2次,当n很大时,只保留项,得到时间复杂度为
。
3)求阶乘(函数递归)
int fac(n){
if n==1 return 1;
else return n*fac(n-1);
}
虽然算法本身没有与n相关的循环,但是递归调用的是与n线性相关的,因此,该算法的时间复杂度为。