算法导论之数据结构

来源:互联网 发布:淘宝宝贝描述 编辑:程序博客网 时间:2024/05/29 10:48

数据结构

集合,是数学也是计算机科学的基础,在表示和操纵有穷、动态集合上,动态集合中每个元素由对象来表示,并有指向对象的指针。对动态集合的操作分为两类:查询和修改,操作以指针为导航,涉及元素对象内的关键字和卫星数据。

数据结构和动态集合的关系,可以这么理解,把集合中的元素根据相互间关系用某种结构组织起来,方便查询和修改。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合,是计算机存储和数据组织的方式,是逻辑上的。

1.1基础数据结构

指针,在编程世界中,扮演着一个很重要的角色。指针,是一个变量,指向存储地址,指向存储的值。通过指针来表示动态集合的数据结构,包括栈、队列、链表及树。

栈的后进先出和队列的先进先出并未太多可着笔之处,日常应用时,较多关注所分配空间的管理,避免溢出。数组是用下标来表示线性,而链表则是用对象中的指针。链表有单、双、环形等特性,主要是根据指针的指向来定义。

在不提供指针和对象数据类型的语言中,可以通过二维数组来表示链表,队列和栈也是一样。一般一维用来存储位置,下标,另一维刻画前后指针和关键字值(也可包括卫星数据)。

对于树,二叉树和k节点树,都可分别用指针和数组来表示。

1.2散列表

散列表是集合域之间,通过散列函数构造映射的一种数据结构。可以把普通数组理解为一个全域映射的散列表,存储空间允许下,可直接寻址。但一般情况下,全域映射所分配的存储空间是浪费,于是构造散列表,将关键字域映射到散列表的槽中。散列映射,最大的问题是碰撞,就是两个关键字通过散列函数获得了相同的散列值,从而归到同一个槽位。

解决碰撞,除了构造优秀散列函数,还可通过链接法来解决。所谓链接法,就是把散列到同一槽位的所有元素按照链表串联起来,即每一个槽位存储不是单个对象,而是一个链表。对于待链接的散列表,其

对于构造散列函数,提出好的散列函数特点:应近似地满足简单一致散列的原则,即n个关键字中每个关键字等可能地散列到m个槽位的任何一个中,且与其他关键字已被散列的槽位无关。一般很难满足这个原则,因为一般关键字的分布未知,且不可能完全相互独立。

构造散列函数一般有关键字映射为自然数、除法散列法(质数)、乘法散列法(字长位数)、全域散列等。全域散列是提供有限的一组散列函数,将给定的关键字域n个元素映射到m个槽中,这个函数组就是全域的,而全域散列就是可以随机从这组函数中选择散列函数,独立于存储的关键字。假设k和l是关键字域中的元素,且不相同,使h(k)=h(l)出现的散列函数,即k和l发生碰撞的概率小于1/m。文中提出利用质数和模来构造全域散列函数类。

解决映射碰撞,除了链接法还有开放寻址法。所谓开放寻址法,就是不设定映射域大小,而是根据关键字动态增长,把所有元素都放在散列表中。当要插入一个元素时,连续地探查散列表中的各项,直到找到一个空槽来存放,当然如果槽位已满,则扩展。开放寻址法,插入、删除、查找元素都要处理空槽,即槽位中没有包含动态集合中元素的可能。开放寻址法通过线性探查、二次探查、双重探查来检查散列表,寻找操作所需的项。线性探查就是定位到散列表中某个具体项,然后循环一圈;二次探查是在此基础上增加偏移量;这两者性能取决于初始探查位置和偏移量的选择,会导致群集现象出现。群集现象是指随着时间的推移,连续被占用的槽不断增加,平均查找时间也随着不断增加。双重探查则对初始探查位置和偏移量都设立函数(自变量都为关键字),使之可变,具有随机产生探查序列的性质。

文中对散列的描述,从散列表定义,到构造散列函数的方法,接着引入解决碰撞冲突的链表法和开放寻址法,并对相关操作进行性能分析。对于如何构造好的散列函数,以及如何解决冲突是散列表的关键。在解决冲突上,对于固定、静态的关键字集合,可以采用完全散列。完全散列是将第一次散列映射出现冲突的关键字,再进行二次散列,确保不出现碰撞。显然,很关键就是两次散列函数的选择。

对于散列,发现CSDN博客有一篇博文介绍的比较全面,还有代码验证性能,很有参考价值。

http://blog.csdn.net/jn1158359135/article/details/7205688

1.3二叉树

二叉树在数据组织上来说,有一种技术的艺术美,在树形视图结构中运算。导论中,二叉树介绍了二叉查找树、红黑树以及B树。

1)二叉查找树

二叉查找树,二叉树结构,可用链表结构表示,每个节点存储一个对象。结点中除了数据域(含key和卫星数据),还包括左域left、右域right、父域parent,分别指向结点在树中的左子、右子及父结点。

二叉查找树按照数据域中关键字的顺序来存储,满足以下性质:

设x为二叉查找树种的一个结点,如y为x的左子树中的一个节点,则key[y]<=key[x],如y是为x的右子树中的一个节点,则key[y]>=key[x]。即结点左树小于结点,右树大于结点。

二叉查找树的查询就围绕这个性质进行,查找指定值、最小、最大、前趋、后续,在一个高度为h的二叉查找树种进行查询,运行时间为O(h)。

二叉查找树的插入和删除,都是在二叉树中结点发生变化,需要保持二叉查找树右大于左的性质。插入和删除的动态集合操作运行时间也为O(h)。

导论中介绍了随机构造二叉查找树,并通过随机变量概率分析证明其期望高度为O(lgn),其中n为结点数。理解随机构造二叉查找树,主要是要理解输入的关键字队列中任何一个关键字都等可能成为根节点,而不同的根节点,在保持二叉查找树性质下,将构造出不同的高度的树,且这个数的期望高度是O(lgn)。随机构造,也就是从关键字中等可能选择一个节点开始构造。

2)红黑树

红黑树也是一棵二叉查找树,只是在每个节点上增加一个存储域表示节点的颜色。构造红黑树的目的是克服二叉查找树在树高度较高时性能不佳而变形,通过对任何一条从根到叶子的路径上各个结点着色方式的限制,确保没有一条路径比其他路径长出两倍,使其接近平衡。

红黑树每个节点包括五个域:数据域key、左域left、右域right、父域parent、颜色域color,这个颜色域就是比二叉查找树多处的域,那么可称之为红黑树需满足怎样的性质呢?

一颗二叉查找树满足:每个节点或红或黑;根节点和叶子节点为黑色;如结点为红色,则其左右儿子都是黑色;对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。这些性质保持了二叉树的平衡性质,使在构造二叉查找树时,避免出现树高度最坏情况。

红黑树是在二叉查找树基础上扩展的数据结构,在进行动态集合操作时,在保持二叉查找树的基础上,还要保持自己的红黑性质。而要保持红黑树性质,最重要的算法就是旋转。

旋转是保持树高度平衡的重要算法,以左旋来说,主要是将父节点调整到左节点,而将右节点调整为父节点,相应将右节点的左子树调整到原父节点的右子树,这样一来降低树的高度。

红黑树的插入是在二叉查找树插入基础上,对新增节点着红色。着红色后可能会改变红黑树性质中结点为红色左右结点要是黑色的性质,即一个红结点不能有红色子女,于是需要调整着色并旋转保持树高度平衡。红黑树的删除,如果是删除红色结点则不影响红黑树性质,但删除黑色节点,则要调整着色并旋转。

具体算法也很有意思,锻炼程序每个步骤的逻辑,可以具体代码实现下。

红黑树是二叉查找树数据结构的扩展,这种扩展就是在基础和标准的数据结构中增加一些信息,用于既定场合。如红黑树增加了结点的颜色域;为了动态顺序统计,导论中还给出红黑树增加size域,统计左右子树的个数,这样就可以直接定位到具体结点的位置;为了支持区间数据维护,在红黑树基础上,扩展区间域,每个结点的值是一个区间。

在一些实际应用中,对基础数据结构的改进基本都能满足,因为基础数据结构已经是经过实践累积出来的具有模型意义,具有很强的适应性。当然必要还是可以创新数据结构来满足。这个章节主要是描述,因为原来都有代码实现过具体算法,所以算法及分析没有进一步描述和理解。
0 0
原创粉丝点击