翻译:程序员数据结构基础:选择正确的数据结构
本文转载自GameDev.net,仅供学习交流。因为刚刚开始学习翻译,难免有些疏漏,如果有哪些地方翻译的不正确,请不吝告知,万分感谢。
原文链接:http://www.gamedev.net/page/resources/_/technical/general-programming/data-structures-for-pre-college-programmers-choosing-the-right-structure-r2991
网络上的许多初学者还是学生。通常初学者通过在网上看教程,从书上复制代码和尝试一些感兴趣的东西来学习。
这篇文章是初级开发者所需要了解的数据结构基础系列文章中的一篇。前一篇文章分析了非线性数据结构。(Non-Linear Structures.)
这篇文章是帮助初学者理解如何选择一个合适的数据结构或者容器类型。
数据结构
在该系列的前几篇文章中说明了最常用的一些数据结构,这里只是一个概括。
线性的结构包括:数组,动态数组和链表。他们之所以是线性的,是因为他们总是呆在你放置他们的地方。数组的随机访问 是非常快的,而且在数组末尾添加和删除数据具有适当良好的性能。如果你频繁地在中间添加或删除数据,链表将是一个非常好的选择。
线性端点数据结构包括:堆和队列等。他们的工作方式与现实世界中的同名操作非常相似。堆,比如一堆木板或者一个数据堆,你可以把东西放在(push)堆的最上面,可以直接用最早面的一块木板或者数据,或者你可以直接拿掉(pop)最上面的一个木板或都数据。队列,像一人排成一个队伍或一个队列数据,以从队尾加入,从队首移除的方式来工作。
非线性数据结构包括:数据字典,有序集和无序集。这些结构是内部非线性的,也就是说你把相关数据插入的顺序和取出数据的顺序是基本无关的。数据字典的工作方式与真正的字典非常相似,它拥有一个关键值(key:用来索引的)和值(value:数据值)。一个有序集(ordered set)跟排序过的只包含关键值(key)不包含值(value)的数据字典一样。至于无序集则是像一个数据的抓斗袋(类似抽奖的暗箱),但无序集这个名字是有点误导性的,实际是他们也是有序的,只是他们排序的方式对我们的使用来说是没有什么用的。这些非线性的数据结构非常适合快速的查找数据。
一个好的数据结构的影响
大多数时候,程序员只是需要遍历整个数据集合。通常,当我们需要从头访问每个数据项时,我们不关心数据内部是怎么排序的。这种常见的情况中,数据结构的选择不是很大的问题。
当有疑问的时候最普遍的选择是动态数组,它可以变成任意的大小,中规中矩,在后期有需要时也可以很容易的转换成其它的数据结构。
但有时候他也有一些问题。
在游戏中,一个很常见的问题就是寻路。你需要找出一个从a到b的路径。最常见的寻路算法是a星算法。在a星算法中你需要一个数据结构来存储部分路径。这个结构应该是排序过的,这样可以把我们最最想要的路径摆放在容器的最前面方便我们使用。如果该路被检测后发现不是一个完整的路径,该算法则会使他成为一个更大的路径的一部分并加入的相当的容器中。
使用动态数组作为a星算法的容器将会是一个糟糕的选择,原因如下:
- 从动态数组的开头移除一个数组是我们所能执行最低效的一个操作。
- 当加入了一个新的路径,我们对动态数组进行重新排序是非常低效的。
如果记得之前所说的,还有是这种类型的访问的最优化的数据结构。我们可以移除最前面的数据,把数据从最后面插入,并自动重排索引出最佳的路径。优先队列是a星算法容器类型的一个好的选择。它通常都内置在语言内部,并通过完善的测试。
根据使用的模式来写选择
使用什么样的数据结构,通常依据你所使用的设计模式。
动态数组 -- 默认的选择
当有疑问的时候,使用动态数组。在c++叫做vector,在java中叫做ArrayList,在c#中叫做List。
动态数组通常可以符合使用要求。它大多数操作都有好的性能 ,剩余的操作性能也不差。如果你发现你需要其它的数据结构,动态数组也是最容易进行修改的。
堆 -- 只有一端
如果你只在单独的一端添加或删除。使用堆,在c++中是stack,在java和c#中都叫Statck。
有许多算法依赖堆来实现。我的第一个反应就是双堆计算器(two-stack calculator)。数学问题像汉诺塔也可以通过堆来解决。当然,在游戏编程中,你可能用不到他们。
游戏工具经验解析数据。解析器在很大程度上依赖堆数据结构来保证配对项匹配正确。
如果你正在使用各种各样的ai类型。你可以发现堆数据结构对于自动机家族中的自动下推器是难以估计的实用。
队列 -- 先进先出
如果你需要从两端进行增删数据,那你你可以使用队列或者双端队列。在c++中叫做queue(队列)或者deque(双端队列).在java中你可以使用Queue或者Deque接口,都是基于LinkList实现的。在c#中只有一个Queue类型,没有内置双端队列(deque)。
如果你需要保证某些重要的东西第一时间被处理,但除非所有的事情都有序的发生,并且按优先级顺序完成。这时你可以使用优先级队列来处理,在c++中称为priority_queue.在java中称为PriorityQueue.C#中你需要自己来实现这个优先级队列。
非线性结构 -- 快速索引
如果你需要创建一个稳定的数据结构,并频繁的进行随机查找,那么你需要使用非线性数据结构。
非线性数据结构有的保存一对数据,有的保存独立的数据。有的是对用户友好的排序,有的是对计算机友好的排序。如果要列出他们之间的所有组合,又将是一篇文章。实际上,那些在之前的文章中已经详细的描述过了。 对于这些非线性结构哪些满足特定的需求,可以查看之前的关于非线性数据结构的文章。
链表 -- 频繁有序的修改
如果你需要频繁的在容器中间进行操作数据(增删),而且你只需要顺序的遍历列表。你可以使用链表,在c++中称为list, 在java和c#中称为LinkedList。
当数据需要频繁的增删,并且在增删后必须保持有序状态时,链表是一个非常好的容器选择。
结论
选择正确的数据结构可以让算法的性能是非常大的改善。
理解主要的数据结构,包含他们的优缺点可以帮助你选择你所需要的数据结构。
我建议你们深入的研究学习这些主要的数据结构。深入学习这些数据结构的计算机科学学位课程通常会持续数星期内。
希望你已经了解了主要的数据结构,可以在没有进行数周深入的学习这些数据结构时可以选择一个好的数据结构。
这系列的文章已经结束了,感谢阅读。
本文转载自GameDev.net,仅供学习交流。因为刚刚开始学习翻译,难免有些疏漏,如果有哪些地方翻译的不正确,请不吝告知,万分感谢。
原文链接:http://www.gamedev.net/page/resources/_/technical/general-programming/data-structures-for-pre-college-programmers-choosing-the-right-structure-r2991