您的位置:首页 > 理论基础 > 数据结构算法

数据结构总结(摘抄)(二)

2009-07-31 15:48 267 查看
(三)专用数据结构
专用数据结构有栈,队,和优先级队列。这些结构不是为了用户可访问的数据库而建立的,通常用他们在程序中辅助实现一些算法。如图,带权图
栈,队,和优先级队列是抽象数据类型(ADT),它们又由一些更加基础的结构如数组、链表或堆(如在优先级队列中)组成。这些ADT只提供给用户简单的借口,一般仅允许插入和访问或者删除一个数据项。
这些数据项是:
对于栈:最后被插入的数据项
对于队:最先被插入的数据项
对于优先级队列:具有最高优先级的数据项
这些ADT可以被当做帮助理解的概念。他们的功能可以通过直接使用基础结构(如数组)来实现,但是他们提供的精简的接口可以简化许多问题。

栈只对最后被插入数据项访问的时候,它是一个后进先出的结构。
栈往往通过数组或链表实现,通过数组实现很有效率,因为最后被插入的数据总是在数组的最后,这个位置是数据最容易删除。栈的溢出有可能出现,但当数组的大小被合理的规划后,溢出并不常见,因为栈很少会拥有大量的数据。
如果栈拥有许多数据,并且数量或插入一个元素很方便。除非整个内存满了,栈的溢出不可能出现。链表比数组稍慢一些,因为对于插入一个新连接必须分配内存,从表中某连接点上删除元素后回收分配内存是必需的。
队列
队用在只对最先被插入的数据项访问的时候,他是一个先进先出的结构。
同栈相比,队同样可以通过数组和链表实现。这两种方法都很有效率。数组需要附加的程序来处理队在数组尾部回绕的情况。链表必须是双端的,这样才能从一端从另一端删除。
用数组还是链表来实现队的选择是通过数据量是否可以被很好地预测来决定的,如果知道有多少数据量的话,就用数组,否则的话就用链表。
优先级队列
优先级队列可以用有序数组或堆来实现,向有序数组中插入式很慢的,但是删除很快。使用堆来实现优先级队列,插入和删除的时间复杂度都是O(logN)级
当插入速度不重要时,可以使用数组或双端链表。当数据量可以被预测时,使用数组,当数据量未知时,使用链表,如果速度很重要的话,选择堆更好一些。
数据结构
插入
删除
注释
栈(数组或链表)
O(1)
O(1)
删除最先插入的
队(数组或链表)
O(1)
O(1)
删除最后插入的
优先级队列(有序数组)
O(N)
O(1)
删除优先级最高的
优先级队列(堆)
O(logN)
O(logN)
排序:
当选择数据结构时,可以先尝试一种较慢但简单的排序,例如插入排序。如果采用了这些方法,现代计算机的快速处理速度也有可能在恰当的时间内将较大的数据量排序。(比较粗略的估计是,较慢的排序对于少于1000的数据量为宜。)
插入排序对几乎已排好的文件很有效,如果没有太多的元素处于乱序的位置上,操作的时间复杂度大约在O(N2)(先写出‘2’,然后选中按‘ctrl+shift+=’)级,这通常发生在往一个已排好序的文件中插入一些新的数据元素的情况。
如果插入排序显得太慢,下一步可以尝试希尔排序,它很容易实现,并且使用起来不会因为条件不允许而性能差距太大;估计在5000以下很有用,
只有当希尔排序显得太慢,你才应该使用更复杂但更快速的方法:归并排序、堆排序或快速排序。归并排序需要辅助存储空间,堆排序需要一个堆的数据结构,前两者都比较快速排序在某些程度上慢,所以当需要最短的排序时间时经常选择快速排序。
归并算法的中心是归并两个已经有序的数组。归并两个有序数组A和B,就生成了第三个数组C。所以归并排序的思想是把一个数组分成两半,排序每一半,然后在归并在一起,于是就用的递归算法。
堆排序:
快速排序:首先须明白什么是划分算法,划分算法就是由两个指针(rightPtr和leftPtr)开始工作,两个指针分别指向数组的两头。取数组中的一个值pivot,进行比较
程序如下:
While(theArray[++leftPtr]<pivot);
While(theArray[--rightPtr]>pivot);
Swap(leftPtr,rightPtr);

希尔排序:它对于多达几千个数据项的,中等大小规模的数据排序表现良好。希尔排序就相当于增量排序,h=3*h+1;首先用最大的h排序,然后用h=(n-1)/3一步一步的缩小增量。
然而,快速排序在处理非随机性数据时性能不大可靠,因为那时它的速度有可能蜕化至O(N2)级
对于那些有可能是非随机性的数据来说,堆排更加可靠。当快速排序没有被正确的实现时,它会产生微小的偏差。在代码中细小的错误会使它对按某些顺序排列的数据无能为力,而诊断到这种情况却又相当难。
排序
平均情况
最坏情况
比较
附加存储
冒泡排序
O(N2)
O(N2)
及格
不需要
选择排序
O(N2)
O(N2)
良好
不需要
插入排序
O(N2)
O(N2)
优秀
不需要
希尔排序
O(N3/2)
O(N3/2)
——
不需要
快速排序
O(N*logN)
O(N2)
优良
不需要
归并排序
O(N*logN)
O(N*logN)
良好
需要
堆排
O(N*logN)
O(N*logN)
良好
不需要
图:
图在数据结构的神殿中与众不同。他们并不存储通用数据,也并不会在其他算法中称为程序员的工具,正相反,它们直接模拟现实世界的情况,图的结构直接反应了问题的结构。
当需要用图时,没有其他的数据结构可以取代之,所以对于何时选择图并没有太多可说的,主要的选择还是如何表示图:使用邻接矩阵或邻接表。这个选择依赖于图的疏密程度,稠密的图用邻接矩阵,稀疏的图用邻接表。
邻接矩阵表示的图的深度优先搜索和广度优先搜索的时间复杂度为O(V2)级,V是顶点的个数,邻接表表示的图的这两种操作的时间复杂度为O(V+E)级,E是边的条数。最小生成树和最短路径在使用邻接矩阵表示时为O(V2)级,邻接表为((E+V)logV)级。请先估计图中的V和E,并通过计算来判断那种表示方法更加合适。

(四)外部存储
在先前的讨论中,我们假设了数据被存放在内存中。然而如果数据量大到内存容不下时,只能被存到外部存储空间,它们经常被称为磁盘文件。在2-3-4树,和哈希表中讨论了外部存储。
存在磁盘文件中具有固定大小单元的数据被称为块。每一个块都存储一定数据的记录。(磁盘文件中的记录拥有与主存中对象相同的数据类型)与对象一样,每条记录都有一个关键字值,通过它可以访问到这条记录。
同样,我们假设了读写操作总是在一个单一的块中进行,这些读写操作比对主存中的数据进行任何操作都要耗时得多,因此,为了提高操作速度必须将磁盘的存取次数减到最小。
顺序存储:
通过特定的关键字进行搜索的最简单的方法是随机存储记录后顺序读取。新的记录可以被简单地插入在文件的最后,已删除的记录可以标记为已删除,或将记录顺次移动来填补空缺。
就平均来说,查找和删除会涉及读取半数的块,所以顺序存储并不是很快,时间复杂度为O(N).。
但是对于小量数据来说它依然是令人满意的。

索引文件
当使用索引文件时,速度会明显的提高,在这种方法中关键字的索引和相应块的号数被存放在内存中,当通过一个特殊的关键字访问一条记录时,程序会向索引询问,索引提供这个关键字的块号数,然后只需要读取这个块,仅耗费O(1)级的时间
可以使用不同种类的关键字来做多种索引(名字做一个,社会安全号码做一个,等等),只要索引数量能在内存的存储的范围之内,这种方法表现得很好。
通常,索引文件存储在磁盘上,只有在需要时才复制进内存中,
索引文件的缺点是必须先创建索引,这有可能对磁盘上的文件进行顺序读取,所以创建索引时很慢的,同时,当记录被加入到文件中时,索引还需要更新。
B-树
B-树是多叉树,通常用于外部存储,书中的节点对应于磁盘中的块。同其他树一样,通过算法来遍历树,在每一层读取一个块。B-树可以在O(logN)级时间内进行查找、插入、删除。这是相当快的,并且它对很大的文件也很有效。但是,他的编程很繁琐。
哈希方法:
如果可以占用一个文件通常大小两倍以上的外部存储空间的话,外部哈希会使一个很好的选择,它同索引文件一样有着相同的存取时间,O(1),但它可以对更大的文件进行操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: