数据结构>绪论

一、什么是数据结构

数据结构就是研究三个方面的主要问题的:数据的逻辑结构、数据的存储结构以及定义在数据结构上的一组操作。即研究按照某种逻辑关系组织起来的一批数据,并按一定的映像方式把它们存放在计算机的存储器中,最后分析在这些数据上定义的一组操作。

数据结构包括:

1.数据的逻辑结构

2.数据的存储结构

3.数据的运算

程序设计实质=好算法+好结构

二、数据的逻辑结构

定义:由某一数据对象及该对象中所有数据成员之间的关系组成。记为: Data_Structure = {D, R}

其中,D是节点集,R是节点集中所有节点之间的关系的有限集合。讨论逻辑结构(D,R)的分类,一般把讨论重点放在关系集R上。用R的性质来刻画数据结构的特点,并对数据结构进行分类。

 

2.1集合结构

结构中的元素除了同属一个集合,没有其他的关系

2.2线性结构(linear structure)

它的关系r是一种线性关系,或称为‘前后关系’,有时也称为‘大小关系’。关系r是有向的,且满足全序性和单索性等约束条件

1)   全序性是指,线性结构的全部结点两两皆可以比较前后(关系r)

2)   单索性是指,每一个结点x都存在唯一的一个直接后继结点y。如果其他结点z在y之前,则这个z也一定在x之前,不会在x,y之间

2.3树型结构(tree structure)

树型结构简称树结构,或称为层次结构。其关系r称为层次关系,或称’父子关系’、’上下级关系’等。每一个结点可以有多于一个的’直接下级’,但是它只能有唯一的’直接上级’。树型结构的最高层次的结点称为根(root)结点。只有它没有父结点

2.4图结构(graph structure)

图结构有时称为结点互联的网络结构,因特网的网页链接关系就是一个非常复杂的图结构。对于图结构的关系r没有加任何约束。

树型结构和图结构的基本区别就是“每个结点是否仅仅从属一个直接上级”。而线性结构和树型结构的基本区别是“每个结点是否仅仅有一个直接后继”。

三、数据的存储结构

计算机的主存储器的特性

1)  其存储空间提供了一种具有非负整数地址编码的,相邻单元的集合,其基本的存储单元是字节

2)  计算机的指令具有按地址随机访问存储空间内任意单元的能力,访问不同地址所需的访问时间基本相同

用数学上的映射来表示,数据的存储结构是建立一种映射,对于数据逻辑结构( K , r),其中r∈R

1)  对它的结点集合K建立一个从K到存储器M的单元的映射:K→M,对于每一个结点j∈K都对应一个唯一的连续存储区域c∈M。

2)  每一个关系元组(j1,j2)∈r(其中j1, j2∈K是结点),亦即j1,j2的逻辑后继关系应映射为存储单元的地址顺序关系(或指针的地址指向关系)。

 

四种基本存储映射方法:顺序、链接、索引、散列

3.1顺序(sequential)的方法

1)   用一块无空隙的存储区域存储数据称为顺序存储

2)   顺序存储把一组结点存储在按地址相邻的顺序存储单元里,结点间的逻辑后继关系用存储单元的自然顺序关系来表达

3)   顺序存储法为使用整数编码来访问数据结点提供了便利

4)   顺序存储结构称为紧凑存储结构,其紧凑性是指它的存储空间除了存储有用数据外,没有用于存储其他附加的信息。紧凑性可以用‘存储密度’来度量:它是一个存储结构所存储的‘有用数据’和该结构(包括附加信息)整个存储空间大小之比。有时为了‘用空间换取时间’,在存储结构中存储一些附加信息还是很必要的。譬如用于提高算法的执行速度,或者让算法实现更为简便等

 

3.2链接(linked)的方法

 利用指针,在结点的存储结构中附加指针字段称为链接法。两个结点的逻辑后继关系可以用指针的指向来表达。任意的逻辑关系r,也可以使用这种指针地址来表达。一般的做法是将数据结点分为两部分:

1)     一部分存放结点本身的数据,称为数据字段

2)     另一部分存放指针,称指针字段,链接到某个后继结点,指向它的存储单元的开始地址。多个相关结点的依次链接就会形成链索

3.3索引(indexing)的方法

1) 索引法是顺序存储法的一种推广,它也使用整数编码来访问数据结点位置

2) 索引方法是要建造一个由整数域Z映射到存储地址域D的函数Y:Z->D,把结点的整数索引值 z∈Z映射到结点的存储地址 d∈D。它称为索引函数,一般而言它并不象数组那样,是简单的线性函数

3) 索引方法也付出了存储开销,其数据结点要附加用于指针的存储空间。

4)索引方法在程序设计中是一种经常使用的方法,其主要原因是对于非顺序的存储结构来说,使用索引表是快速地由整数索引值找到其对应数据结点的唯一方法

3.4散列(hashing)的方法

散列方法是索引方法的一种延伸和扩展利用一种称为散列函数(hash functions)进行索引值的计算,然后通过索引表求出结点的指针地址散列函数是将字符串s映射到非负整数z的一类函数h: S -> Z,对任意的 s∈ S,散列函数 h(s)=z,z∈ Z

散列函数h(s)除了它取非负整数值外,关键的问题:

1)     恰当地选择散列函数

2)     如何建造散列表

3)     在构建散列表的中间解决‘碰撞’的办法

例如,要将关键字值序列(3,15,22,24),存储到编号为0到4的表长为5的哈希表中。 计算存储地址的哈希函数可取除5的取余数算法H(k)=k% 5。则构造好的哈希表如图所示。

四、抽象数据类型

数据类型:是一个值的集合和定义在该值上的一组操作的总称。


抽象数据类型(ADTs:Abstract Data Types)适合多种数据类型的类定义或算法,在特定环境下通过简单地代换,变成针对具体某种数据类型的类定义或算法。抽象数据类型使得使用它的人可以只关心它的逻辑特征,不需要了解它的实现方式。

1)抽象数据类型不同于具体的数据结构,前者所描述的是一种模板以及模板的结构和性质。而模板的类型参数T(元素的数据类型)必须用具体的数据类型所代入,才能成为具体的数据类型。

2)抽象数据类型是把数据结构作为独立于应用程序的一种抽象,目的是使人们能够独立于程序的实现细节来理解数据结构的特性 

抽象数据类型可以用以下的三元组来表示:ADT = (D,S,P)D:数据对象   S:D上的关系集   P:D上的操作集

数据结构中的基本概念和Java 语言中的概念对应

数据元素可以对应到类,其数据项就是类的成员变量,某个具体的数据元素就是某个类的一个实例;数据的顺序存储结构与链式存储结构可以通过一维数组以及对象的引用来实现;抽象数据类型也可以对应到类,抽象数据类型的数据对象与数据之间的关系可以通过类的成员变量来存储和表示,抽象数据类型的操作则使用类的方法来实现。

五、算法

5.1定义

定义:一个有穷的指令集,这些指令为解决某一特定任务规定了一个运算序列。

特性:

1)     输入 有0个或多个输入

2)     输出 有一个或多个输出(处理结果)

3)     确定性 每步定义都是确切、无歧义的

4)     有穷性 算法应在执行有穷步后结束

5)     有效性 每一条运算应足够基本

算法的性能标准:正确性、 可使用性、可读性、效率、 健壮性

5.2性能分析与度量----大O表示法

由于算法分析和它所求解的问题规模直接有关,因此通常将问题规模n作为一个参照量,求算法的时空开销和n的关系。算法的渐进分析就是要估计,当数据规模n逐步增大时,资源开销T(n)的增长趋势。

从数量级大小的比较来考虑,当n增大到一定值以后,资源开销的计算公式中影响最大的就是n的幂次最高的项,其他的常数项和低幂次项都是可以忽略的。去掉表示算法运行时间中的低阶项和首项常数,就称我们是在度量算法的渐进时间复杂度(asymptotic complexity),简称时间复杂度。

Ο符号      时间复杂度的上界,

Ω符号      时间复杂度的下界,

θ符号      时间复杂度的精确阶。

算法时间复杂度分析方法:

计算循环次数

分析最高频度的基本操作

最佳、最坏与平均情况分析

均摊分析::计算的运行时间始终变动,并且这一计算在大多数时候运行得很快,而在少数时候却要花费大量时间。在均摊分析中,我们可以算出算法在整个执行过程中,或多次执行过程中所用时间的平均值,称为该算法的均摊运行时间。均摊分析保证了算法的平均代价,这与平均情况分析是不同的,在平均分析中必须知道每种输入实例的分布,计算所有不同输入实例才能得到平均值,而在均摊分析中不需要这样。

加法规则  针对并列程序段

   T(n,m) = T1 (n) + T2 (m)   = O(max (f (n),g (m)))

   c < log2n <n<nlog2n <n2 <n3< 2n < 3n <n!

乘法规则  针对嵌套程序段
 
T (n,m) = T1 (n)* T2 (m)
         = O(f (n)*g (m))

5.3时空折中

对于同一个问题求解,一般会存在多种算法。而这些算法在时空开销上的优劣往往表现出‘时空折中’的性质‘时空折中’,是指为了改善一个算法的时间开销,往往可以通过增大空间开销为代价,而设计出一个新算法来。有时也可以为了缩小算法的空间开销,而牺牲计算机的运行时间,通过增大时间开销来换取存储空间的节省。

六、数据结构的选择和评价

探索运算步骤时,首先应该考虑顶层的运算步骤,然后再考虑底层的运算步骤。顶层的运算步骤是指定义在数据模型级上的运算步骤,或叫宏观运算。它们组成解答问题步骤的主干部分。其中涉及的数据是数据模型中的一个变量,暂时不关心它的数据结构;,底层的运算步骤包括两部分:一是数据模型的具体表示;二是定义在该数据模型上的运算的具体实现

  1. 仔细分析所要解决的问题,特别是求解问题所涉及的数据类型和数据间逻辑关系
  2. 数据结构的初步设计往往在算法设计之先
  3. 注意数据结构的可扩展性。包括考虑当输入数据的规模发生改变时,数据结构是否能够适应。同时,数据结构应该适应求解问题的演变和扩展
  4. 数据结构的设计和选择也要比较算法的时空开销的优劣

数据结构例子代码下载地址 http://download.csdn.net/detail/warin/1391320

 

原文地址:https://www.cnblogs.com/xqzt/p/5637152.html