【问题标题】:Access c++ queue elements like an array像数组一样访问 c++ 队列元素
【发布时间】:2011-08-18 03:54:38
【问题描述】:

可以像数组一样访问队列元素吗?如果不是,那有什么类似于队列的容器可以呢?

【问题讨论】:

  • 定义“像一个数组”。您的意思是“使用下标运算符”、“在 O(1) 时间内”还是什么?
  • 像数组一样访问元素意味着使用下标运算符。
  • 你指的是STL的队列吗?即std::queue?

标签: c++ stl queue


【解决方案1】:

这是std::deque 的理想任务。它针对添加/删除到末尾进行了优化,但也提供了对中间元素的随机访问。引用链接的文章:

双端队列非常像 vector:和vector一样,是一个序列 支持随机访问 元素,恒定时间插入和 删除末尾的元素 序列,以及中间元素的线性时间插入和移除。

... deque 还支持在序列的开头以恒定时间插入和删除元素

因此,由于它可以有效地从两端添加/删除,因此 deque 可以通过其 push_back 和 pop_front 方法有效地用作队列:

std::deque<int> aDeque;

// enqueue
aDeque.push_back(1);
aDeque.push_back(2);

// dequeue
int top = aDeque.front();
aDeque.pop_front();

像数组一样访问元素意味着使用下标运算符

deque也支持通过下标操作符随机访问:

std::cout << aDeque[0];

【讨论】:

    【解决方案2】:

    可以像数组一样访问队列元素吗?

    当然!只要底层容器(默认为双端队列)确实如此,尽管您可能希望将代码称为坏名...

    template<class T, class C=std::deque<T> >
    struct pubqueue : std::queue<T, C> {
      using std::queue<T, C>::c;
    
      static C& get_c(std::queue<T, C> &s) {
        return s.*&pubqueue::c;
      }
      static C const& get_c(std::queue<T, C> const &s) {
        return s.*&pubqueue::c;
      }
    };
    
    template<class T, class C>
    C& get_c(std::queue<T, C> &a) {
      return pubqueue<T, C>::get_c(a);
    }
    template<class T, class C>
    C& get_c(std::queue<T, C> const &a) {
      return pubqueue<T, C>::get_c(a);
    }
    
    int main() {
      std::queue<int> q;
      q.push(42);
      std::cout << get_c(q)[0] << '\n';
    
      pubqueue<int> p;
      p.push(3);
      std::cout << p.c[0] << '\n';
    
      return 0;
    }
    

    请注意允许您将 std::queue 变量更改为 pubqueue 变量并直接访问容器成员的技巧。这让您可以保留 std::queue 的 push/pop(而不是 push_back/pop_front 等)接口。

    【讨论】:

      【解决方案3】:

      既然您已经澄清您想要下标运算符访问,那么答案是否定的。队列不是需要随机元素访问的数据结构。如果您需要随机元素访问,请使用向量或实际数组。

      【讨论】:

        【解决方案4】:

        答案,这取决于队列的实现。标准模板库提供的队列不会让您通过下标运算符随机访问元素,因为随机访问的实现会破坏队列的点。

        回想一下,队列是一种提供先进先出行为的数据结构。这意味着你需要真正关注头部元素,仅此而已。一旦你需要访问头部旁边的元素,你就不再有队列了。

        现在这并不意味着您不能在数组/向量类之上实现自己的队列,但是它不会很有效,因为数组和向量都不适合动态添加和删除元素。

        【讨论】:

        • std::queue 使用 std::deque 作为其底层容器 FWIW。)
        • 我不会用任何东西实现队列是一个类似数组的类。
        • @Dennis:为什么?使用数组而不是列表有什么好处?
        • @Alan:注意他说的是类数组,它可能包括一个双端队列,它具有高效的前后操作。在任何情况下,链表都可能是最糟糕的容器,除了拼接和反转之外,在所有方面(与其他容器相比)都很慢,并且只有在主要操作是拼接或反转时,这些优点才会明显。
        • @GMan:双端队列不一定是“类数组”。您可以使用不断增长的数组来实现一个,但这是一种实现选择。类数组,意味着数组的特性(恒定时间访问、连续内存分配)等。双端队列也不能保证。通过动态数组实现的双端队列具有插入的摊销成本,而使用列表的实现在前后插入的固定成本为 O(1)。如果您使用数组来实现队列,则会增加更多复杂性,从而增加出错的可能性。
        【解决方案5】:

        使用向量代替队列。队列不使用 [] 运算符。

        【讨论】:

        • Well vector 的界面只允许你在后面推/弹。由于所有东西都需要在阵列中向下移动,因此在向前推进或弹出时会降低性能。 Vector 会更好地针对具有随机访问的堆栈进行优化。
        【解决方案6】:

        STL 以下容器可以使用 operator[] 访问: 矢量、出列、映射、位集。

        使用的默认容器是矢量容器。在您的情况下,出队是最有价值的选择(因为您希望进行队列操作以及随机访问)。

        查看显示 STL 容器上可用操作的参考表: http://www.cplusplus.com/reference/stl/

        确定您需要使用哪种类型的容器的图表(在页面底部): http://www.linuxsoftware.co.nz/cppcontainers.html

        【讨论】:

          【解决方案7】:

          std::queue 没有随机元素访问,它是一个序列容器适配器,默认使用std::dequeue。但是,值得注意的是,如果您使用的是微软的编译器cl,您可以使用._Get_container() 方法来访问底层容器,从而访问其各个元素,如下所示:

          std::deque<int> dq;
          
          std::queue<int, decltype(dq)> q;
          q.push(23);
          q.push(90);
          q.push(38794);
          q.push(7);
          q.push(0);
          q.push(2);
          q.push(13);
          q.push(24323);
          q.push(0);
          q.push(1234);
          
          for (int i = 0; i < q.size(); i++)
          {
              std::cout << q._Get_container()[i] << '\n';
          }
          

          第一次。

          【讨论】:

            【解决方案8】:

            你可以像队列一样使用向量,例如:

            std::vector<int> v;
            int i=0;
            
            v.push_back(1);
            v.push_back(2);
            v.push_back(3);
            v.push_back(4);
            
            // "dequeue"
            i=v[0]; // get 1
            v.erase[ v.begin() ); // remove 1 / "dequeue" 1
            
            i=v[0]; // get 2
            v.erase[ v.begin() ); // remove 2 / "dequeue" 2
            
            i=v[0]; // get 3
            v.erase[ v.begin() ); // remove 3 / "dequeue" 3
            
            i=v[0]; // get 4
            v.erase[ v.begin() ); // remove 4 / "dequeue" 4
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-01-02
              • 1970-01-01
              • 2019-11-16
              • 1970-01-01
              • 1970-01-01
              • 2016-10-01
              相关资源
              最近更新 更多