大多数数据结构能否使用向量实现?

时间:2013-09-21 16:54:16

标签: c++ data-structures vector

我使用C ++向量来实现堆栈,队列,堆,优先级队列和有向加权图。在书籍和参考书中,我已经看到了这些数据结构的大类,所有这些都可以使用向量简单地实现。 (使用指针可能更灵活)

我们还可以使用向量实现更高级的数据结构吗? 如果是的话,为什么C ++书籍仍然使用指针解释长类的概念?

是否要记住较低级别的想法,如果它更生动,或者让学生配备这样的指针使用?

3 个答案:

答案 0 :(得分:1)

确实,许多数据结构可以在矢量(数组,为了这个答案)的基础上实现,基本上它们都可以,因为每个计算任务都可以实现为在图灵机上运行一个更基本的数据访问能力(或者,在现实世界中,你可以说你用指针实现的任何程序最终都运行在一个具有简单数组类虚拟内存空间的CPU上,所以你可以称之为一个庞大的数组) 。然而,它并不总是聪明。两个主要原因:

  1. 性能/时间复杂度 - 向量根本无法提供O(1)中的所有基本操作。有一个快速初始化的解决方案,但尝试将值随机插入一个大型向量中,看看你的表现有多糟糕 - 那是因为你必须一遍又一遍地将所有元素移动一个地方。列表可以在单个操作中执行此操作。当然,其他结构也有其自身的性能缺点,但这就是使用这些基本构建模块设计复杂数据结构的美妙之处。

  2. 结构复杂性 - 您可以将向量的列表视为有序容器,并可能将其扩展为可在其上实现的多维矩阵,因为它们仍保留一些基本排序,但是有更复杂的结构。以...为例树,一个简单的完整二叉树,可以很容易地用向量实现,因为父子关系可以很容易地转换为索引算术,但是如果树没有满并且每个节点有不同数量的子节点怎么办?现在,您可能会说它仍然可以完成(任何图形都可以通过邻接矩阵或邻接列表来实现,例如),但是当您可以使用指针链接实现更简单的实现时,几乎没有任何意义。试着用阵列做一个AVL滚动。 :颤动:

  3. 请注意,第二个参数可能很好地归结为性能(“嘿,这是一个尴尬的方法,但我仍然设法使用矢量!”),但它不仅仅是 - 它会使你的代码复杂化,使你的混乱变得混乱数据结构设计,可能使它更容易出错。

    现在,这里出现了“但是” - 尽管使用语言为您提供的所有可能工具有很多意义,但是使用基于矢量的结构进行性能关键任务已被广泛接受。看看几乎所有的科学CPU基准测试,其中大多数最终都依赖于矢量(未被发现,但如果有人感兴趣,我可以进一步详细说明。可以说即使是众所周知的* 图形 * 500也能做到这一点) 。

    原因并不是它是最好的编程实践,而是它更适合CPU内部结构并从硬件中获得更多“果汁”。这是由于空间局部性 - CPU非常喜欢它,因为它允许内存单元并行访问(在数组中你总是知道下一个元素在哪里,在列表中你必须等到获取当前元素),以及发出流/跨步预取,减少未来请求的延迟。 我不能说这总是一个很好的做法,当你通过图表访问时,即使你使用数组实现,访问仍然是非常不规则的,但它仍然是一种非常常见的做法。

    总结一下,从字面上理解问题 - 其中大多数都可以(对于“大多数”的给定定义,好吗?),但如果意图是“为什么教指针”,我相信你可以看到为了理解你的极限以及你可以和应该使用的东西 - 你需要知道的不仅仅是数组甚至是指针。一个优秀的程序员应该对所有事情都有所了解 - 操作系统设计,CPU设计等。除非你真正理解你正在运行的结构,否则你不能做任何体面的事情,不幸的是(或者不包括)包含很多指针

答案 1 :(得分:0)

您可以使用std::vector作为后备存储来实现一种allocator。如果这样做,基本计算机科学的所有标准数据结构都可以在向量之上实现。但是,它几乎不会让你使用指针:向量实际上只是一些内存块,带有一些有用的附加操作,最显着的是扩展能力。

更重要的是:如果您不理解指针,您将无法理解如何使用vector进行高级数据结构。 vector是一个有用的抽象,但它遵循C ++规则“你没有得到你不付出的东西”,所以它也是一个非常“瘦”的抽象,你根据您必须编写的代码数量支付抽象成本。

(Jonathan Wakely在评论中指出,当你在vector之上实现它们时,你不会得到C ++标准库需要分配器数据结构的确切保证。原则上,载体只是一种处理内存块的方法。)

答案 2 :(得分:-1)

如果您正在学习C ++,您需要熟悉指针以及如何使用它们,即使有更多更高级别的概念可以帮助您完成这项工作。 是的,可以使用向量或列表实现大多数数据结构,如果您刚刚开始学习编程,那么您可能知道如何自己编写这些数据结构。

话虽如此,生产代码应始终使用标准库,除非有充分的理由不这样做。