【问题标题】:What's the Big-O of a stack, queue, set, and deque?堆栈、队列、集合和双端队列的 Big-O 是什么?
【发布时间】:2014-10-14 07:22:51
【问题描述】:

堆栈、队列、集合和双端队列在插入、搜索、索引、空间和删除复杂性方面的 Big-O 效率是多少?

【问题讨论】:

  • 感谢@MikeDinescu 的讽刺,我已经在 Google 上搜索了将近一个小时,但没有找到太多答案。我的研究并不局限于一个来源,请不要以为我没有尝试自己找到答案。
  • 您具体发现了什么,您的具体问题是什么?
  • 我在该问题上发现的所有内容都与各种实现有关,但我发现的所有内容都没有讨论 Big-O。事实上,我信息量最大的来源是维基百科,它对这些数据类型提供了很好的入门知识,但也没有解释它们的效率。
  • 好了。我已将我的问题改写为一个“中肯”的句子。我已经排除了我尝试和搜索的内容,因为显然这会让你被那些更倾向于傲慢而不是帮助别人理解他们觉得难以理解的概念的人激怒。

标签: stack set queue big-o deque


【解决方案1】:

我很惊讶您在网上找不到此信息。

您在问题中列出的数据结构之间存在区别。

我将从队列和堆栈数据结构开始。堆栈和队列都提供对数据的专门访问,因为没有随机访问,只有顺序访问。因此,您不能谈论随机访问性能。在这种情况下,任何体面的堆栈或队列实现都将为插入和删除操作(以它们各自的形式)提供 O(1) 访问。

集合是一种非常不同的结构,其性能在很大程度上取决于底层实现。例如,您可以使用底层哈希表来实现一个集合,以实现近乎恒定的时间插入、删除和查找操作,或者您可以使用 O(log n) 的平衡搜索树来实现它。

【讨论】:

  • 我认为在这种情况下,出队是“双端队列”;即两个方向的链接之一
【解决方案2】:

Big-O 表示法通常保留给算法和函数,而不是数据类型。
此外,时间复杂度很大程度上取决于实现。要求“堆栈”数据类型的 Big-O 时间复杂度就像要求“排序”的 Big-O 时间复杂度。这一切都取决于实施。 (更具体地说,某些特定于案例的优化和要求可能会大大改变时间复杂度。)

如果您希望使用 C++ STL 作为参考实现,您可以找到有关您列出的每个数据类型的复杂性的详细信息 from here。只需搜索数据类型和操作即可。

【讨论】:

    【解决方案3】:

    这里的问题是这些数据结构通常是根据其他数据结构来实现的。例如,set 可以实现为哈希表或使用红黑树算法。

    堆栈不提供随机访问,但通常实现为内存块(例如数组),其中单个元素指向堆栈顶部,该元素针对pushpop 操作进行更新。

    queue 可以实现为具有非常不同的插入、删除和索引特性的数组或链表。 deque 更有可能实现为链表,但 C++ 标准库中的 Microsoft 实现使用混合方法(请参阅 What the heque is going on with the memory overhead of std::deque?)。

    【讨论】:

      【解决方案4】:

      这实际上取决于每个数据结构的实现。我将介绍一些,以便您了解如何确定这一点。

      假设 Stack 类是使用 Node 实现的(也可以使用 LinkedListArrayListarrray 等实现)。

      Node top, bottom;
      public Stack(Node n){
          top = bottom = n;
      }
      

      堆栈有 3 个主要方法:peekpushpop

      public int peek(){
          return top.value; //only return value
      }
      

      没有涉及太多处理。它只是返回一个原始值。这对于时间和空间来说都是 O(1)

      public void push(Node n){
          n.next = top;
          top = n;
      }
      

      仍然没有真正的处理。这对于时间和空间来说都是 O(1)。让我们跳过pop() 并尝试一些更有趣的事情。让我们尝试一个名为contains(int v) 的方法。它将搜索堆栈以查看它是否包含一个Node,其中包含一个等于v 的值。

      public bool contains(int v){
          Node current = top;
          while(current != null){
              if(current.value == v){
                  return true;
              }
              current = current.next;
          }
          return false;
      }
      

      基本上,我们将遍历节点引用,直到找到值或到达终点。在某些情况下,您会及早发现价值,而在某些情况下,您会在以后发现价值。但是,我们关心最坏的情况!最坏的情况是我们必须检查每个Node。假设有 n 个节点,那么我们有 O(n)

      您可以将这些分析技能应用到其他数据结构中,这样您就可以自己解决其余的问题。这还不错。祝你好运。 :)

      【讨论】:

        【解决方案5】:

        我一直在使用这个:http://bigocheatsheet.com/,但几乎没有关于为什么使用这些大 O 值的信息。你必须自己去挖掘和研究。

        【讨论】:

          猜你喜欢
          • 2019-04-13
          • 2013-12-13
          • 2017-04-12
          • 2020-04-19
          • 2013-09-18
          • 1970-01-01
          • 2016-01-19
          • 2020-06-18
          • 1970-01-01
          相关资源
          最近更新 更多