数据结构之线性结构(二,联合数组等)


关键词数据结构 联合数组 栈 队列                                           

数据结构之线性结构(二,联合数组等)

作者:冲出宇宙

时间:2006.10.24

修改:2006.11.3

3 联合数组(Associative array)

  联合数组的别名有:Map,Hash,Dictionay, finite map, lookup table, index/index file。它是一个抽象数据结构,包含了一个key集合和一个value集合,每个key都对应一个value。它和数学中的函数十分相似,因为把key当做输入的话,value就是其输出。正因为这样,key和value之间的关系有的时候被认为是映射关系。比如,如果key="good"而它对应的value=3的话,我们说数组把good映射到了3上面。联合数组是基本数组的扩充形式,基本数组是把整数(索引)映射到值上面,而联合数组是把任何类型的数映射到值上面。
  一般的说,它支持4种操作:
    1,Add: 加入一个新的key,value对;
    2,Reassign: 把一个旧的key绑定到一个新的value上面;
    3,Remove: 删除一个key,value对;
    4,Lookup: 查找一个key对应的value值。
    
  联合数组通常用在查找十分频繁的地方,所以,其查找性能是现实它的时候需要优先考虑的。目前主要有3种实现办法:
    1,Hash table: 散列表是最常见的实现方式,其优点是查找快,缺点是占用空间多,未对key进行排序,设计一个好的一般hash算法比较困难。
    2,Self-balancing binary search tree: 平衡查找树也是一个很常用的办法,其优点是查找和插入都是o(logn)的复杂度,同时对多个key对应一个value的情况支持很好。
    3,Skip lists: 跳跃表主要的优点是插入和删除都是十分的快速,但是,其缺点是查找速度最差是o(n),平均是o(logn)。
    
  
最简单的实现联合数组的办法是联合表(Associative lists),就是把key和value对用list链接在一起。目前来说,比较好的实现方法是Patricia Trees和Judy arrays,一般推荐使用这2种结构来实现联合表。
  Multimap是联合数组的变形,它定义为每个key可以对应于多个value。

3.1 散列表(Hash table)

  散列表也叫hash map,它是一种联合了keys和values的数据结构。它提供的最有效的基本操作是查找。这种操作是基于hash函数的。下图是一个把名字映射到电话号码上的散列表示意图:
     
  散列表常被用来构建联合数组、集合和缓冲。无论表里面有多少元素,散列表提供常数的平均查找复杂度,这点和数组是一样的(虽然它比数组慢许多倍)。但是,最坏的情况下,查找一个元素可能花费o(n)的时间。
  散列表对碰撞的处理有很多办法,但是,最常用的只有2种:链表和地址散列。在使用链表处理散列表碰撞的时候,hash值一样的key-value被串到同一个链表上。查找的时候,先根据hash值找到链表的头节点,然后顺序查找下去。图示的是链表方式的碰撞处理。
     
  地址散列试图在出现冲突之后在数组中找到一个空闲位置放数据。有3种比较著名的找空闲位置的办法:
    1)线性探测。以一个固定的间隔步探测下一个空闲位置,这个间隔常常为1;
    2)多项式探测。间隔步的计算方式是多项式。
    3)2次hash。间隔步的计算方式是输入为记录的hash函数。
    图示是一个地址散列解决冲突的例子:


  显然,散列表的性能和Hash函数的构造是紧密联系的,如何构造Hash函数是一个很大的问题,作者不久将单独写一篇文章谈论Hash函数。

3.2 跳跃表(Skip list)

   跳跃表是一个已经排序了的多层次链表,它由多个基本链表组成。第一层的链表包含了全部的元素,在第n层里面出现的元素在第n+1层出现的概率是p,这样就随机的构造出了多个层次的链表,最后那层的链表只有1个元素。       

  下面是一个例子:
  1: 1 --> 2 --> 3 --> 4 --> 5 --> 6 --> 7 --> 8 -->  9 --> 10
  2: 1 -------->  3 --> 4 -------------->    7 -------->   9
  3: 1--------------->   4 -------------------------->        9
  4: 1
  除了这种分层次的表示方法以外,一般跳跃表都表示成下面的样子:
  |
  |-------------------->|--------------------------------->|
  |------------>| ----->|------------------------->|------>|
  1 --> 2 --> 3 --> 4 --> 5 --> 6 --> 7 --> 8 --> 9 --> 10
  这里,每个节点包含多个指针。
  根据跳跃表的定义,第i层链表拥有N*p^i个节点,跳跃表包含的所有节点数为N/(1-p)个,每个节点在1/(1-p)个链表里面出现。
  查找数据M的时候,首先查找最高层的链表,找到最后一个小于等于待查数据的节点node,然后从下一层节点里面的包含了和node包含的数据一样的节点开始查找。重复上述动作,直到找到为止。对于上面的例子,如果我们要查找8的话,首先查找第4层,止步的数据为1,继续查找第3层,中止的数据为4,查找第2层,从4开始,止步的数据为7,查找第1层,从7开始,止步的数据为8。查询结束。
  插入数据和删除数据的操作很容易根据定义得到,只是他们可能都需要对多个链表进行操作。
  性能方面,查找一个数据的耗费显然为o(logN)。
  根据已有的比较结果,skip list性能不如B树,同时,作者宣称的skip list比AVL树在性能上好的说法引起了很多争议。但是,skip list应用在并行环境下的时候,具有不错的效果。
 

4 栈(Stack)

  堆栈是一种暂时性的数据结构(抽象数据结构)。它在现代计算机中到处可见,俨然就是现代计算机的支撑者。堆栈是一种后进先出(也就是先进后出)的数据结构,其实现往往使用数组。
  堆栈支持2种基本操作:进栈(Push)和出栈(Pop)。进栈的时候,把数据放到栈的顶端;出栈的时候,把数据从栈的顶端移走。一般来说,实现堆栈的结构还会支持下面2种操作:查看顶(Peek)和计算栈长(getLength)。
 

5 队列(Queue)

  在计算机科学中,队列是一种包含了许多待处理的数据的结构。最有名的队列是先进先出(FIFO)队列,在这种队列中,先进入的数据会先被处理。先进先出队列支持2种基本操作:出列(Dequeue)和入队(Enqueue)。出列是把队列的头数据进行处理,而入队则是把新待处理数据加入到队列的末尾。当然,某些队列的实现还会支持查看头数据(Peek)和计算队列长度(getLength)这2种操作。
  根据队列的定义,最常用来实现它的是链表。所以,队列一般都具有链表的时间和空间性质。

5.1 优先队列(Priority queue)

   优先队列和基本的队列唯一不同的地方在于:每个队列的元素都有一个优先度。同时,它支持3种操作:enqueue(包括优先度)、dequeue(把最高优先度的那个数据请出队列)和peek(查看最高优先度的那个数据)。
  优先队列的实现是一个值得探讨的问题。最简单的说,我们可以维持一个队列数组,每个队列的优先度都一样,这样做的结果是,enqueue的速度很快,dequeue和peek的速度就十分慢了(因为我们要找到最大优先度的那个队列)。显然,使用平衡树就能够加快dequeue和peek的速度,它的3种操作的复杂度都是o(logn)。当优先度的取值范围比较小的时候,使用van Emde Boas树是更好的选择。各种Heap结构也可以用来构建优先队列。

6 双向队列(Deque)

  双向队列是可以在前面或者后面加入或者删除数据的队列结构。它可以从2头出列和入队。

7 间隙缓冲(Gap buffer)

  最早使用在emacs上面,它是一种用来存储大数组集合的结构,它提供了快速的插入和删除操作,前提是操作在当前位置附近发生。正因为这样,它在文本编辑器中使用很多。举例来说,现在一个缓冲保存了一大段文字,这段文字被划分为2部分:A和B。现在,A保存在缓冲的前面,而B保存在缓冲的后面,它们之间有一块空地方。假设鼠标指针在A和B之间,现在鼠标指针往后面移动,到达了一个新位置,这个新位置把B划分为C和D两部分,那么,gap buffer规则将会把C拷贝到A的后面,组成一个新的A。这样,现在缓冲的前面放的是新的A,后面放的是D,而它们之间是一块gap buffer区域(空白)。


  虽然gap buffer对于快速插入小量数据十分有效,但当插入一块大数据的时候,gap buffer不得不拷贝大量的数据到新的缓冲去,这是很费时的操作。作为一种变形,可以把多个buffer串接起来(linked list),利用分治方式加快操作。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构原本,大一统,外文书原版 Data structures Contents Articles Introduction 1 Data structure 1 Linked data structure 3 Succinct data structure 6 Implicit data structure 8 Compressed data structure 9 Search data structure 10 Persistent data structure 11 Concurrent data structure 18 Abstract data types 21 Abstract data type 21 List 29 Stack 32 Queue 61 Deque 63 Priority queue 66 Map 70 Bidirectional map 73 Multimap 74 Set 75 Tree 80 Arrays 85 Array data structure 85 Row-major order 91 Dope vector 93 Iliffe vector 94 Dynamic array 95 Hashed array tree 98 Gap buffer 99 Circular buffer 101 Sparse array 111 Bit array 112 Bitboard 117 Parallel array 121 Lookup table 123 Lists 129 Linked list 129 XOR linked list 145 Unrolled linked list 147 VList 149 Skip list 151 Self-organizing list 157 Binary trees 162 Binary tree 162 Binary search tree 170 Self-balancing binary search tree 180 Tree rotation 182 Weight-balanced tree 185 Threaded binary tree 186 AVL tree 191 Red-black tree 195 AA tree 210 Scapegoat tree 215 Splay tree 219 T-tree 234 Rope 237 Top Trees 242 Tango Trees 246 Van Emde Boas tree 268 Cartesian tree 272 Treap 277 B-trees 281 B-tree 281 B+ tree 292 Dancing tree 297 2-3 tree 298 2-3-4 tree 299 Queaps 301 Fusion tree 305 Bx-tree 309 Heaps 312 Heap 312 Binary heap 315 Binomial heap 321 Fibonacci heap 326 2-3 heap 331 Pairing heap 331 Beap 334 Leftist tree 335 Skew heap 338 Soft heap 341 d-ary heap 343 Tries 346 Trie 346 Radix tree 353 Suffix tree 358 Suffix array 363 Compressed suffix array 367 FM-index 368 Generalised suffix tree 371 B-trie 372 Judy array 372 Directed acyclic word graph 374 Multiway trees 376 Ternary search tree 376 And–or tree 379 (a,b)-tree 380 Link/cut tree 381 SPQR tree 381 Spaghetti stack 384 Disjoint-set data structure 385 Space-partitioning trees 389 Space partitioning 389 Binary space partitioning 390 Segment tree 395 Interval tree 399 Range tree 404 Bin 406 k-d tree 408 Implicit k-d tree 416 min/max kd-tree 419 Adaptive k-d tree 420 Quadtree 421 Octree 427 Linear octrees 429 Z-order 429 UB-tree 434 R-tree 435 R+ tree 441 R* tree 442 Hilbert R-tree 445 X-tree 452 Metric tree 452 vP-tree 453 BK-tree 454 Hashes 455 Hash table 455 Hash function 468 Open addressing 476 Lazy deletion 479 Linear probing 479 Quadratic probing 480 Double hashing 484 Cuckoo hashing 486 Coalesced hashing 491 Perfect hash function 494 Universal hashing 496 Linear hashing 501 Extendible hashing 502 2-choice hashing 508 Pearson hashing 508 Fowler–Noll–Vo hash function 509 Bitstate hashing 511 Bloom filter 512 Locality preserving hashing 523 Morton number 524 Zobrist hashing 529 Rolling hash 530 Hash list 531 Hash tree 532 Prefix hash tree 534 Hash trie 535 Hash array mapped trie 535 Distributed hash table 536 Consistent hashing 542 Stable hashing 544 Koorde 544 Graphs 547 Graph 547 Adjacency list 549 Adjacency matrix 551 And-inverter graph 554 Binary decision diagram 556 Binary moment diagram 560 Zero-suppressed decision diagram 562 Propositional directed acyclic graph 563 Graph-structured stack 564 Scene graph 565 Appendix 570 Big O notation 570 Amortized analysis 581 Locality of reference 582 Standard Template Library 585 References Article Sources and Contributors 596 Image Sources, Licenses and Contributors 605 Article Licenses License 610

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值