【问题标题】:A difference behavior between a deque and a list双端队列和列表之间的差异行为
【发布时间】:2020-07-13 06:21:01
【问题描述】:

我可以使用列表和(散列)映射成功实现 LRU 缓存。我想知道为什么当我使用双端队列而不是列表时会出现错误行为。让我简要解释一下我的方法。

  1. 使用地图中的键查找值。该映射返回一个包含其值的列表或双端队列的迭代器。
  2. 应该更新迭代器 2.1。从地图和列表或双端队列中删除现有节点。 2.2.将一个新节点推入列表的前面,并且该映射还将新节点的键和迭代器作为值保存。

所以我的问题是:当我使用双端队列而不是列表时,为什么会得到错误的结果?我猜双端队列内部有一个块列表,它会产生问题。但是,我不确定根本原因。

这是一个可重现的代码。预期的结果是“9 29 9”,使用列表时我可以看到正确的答案。但是使用双端队列时返回错误的结果“9 29 29”。

#include <bits/stdc++.h>

using namespace std;
using vi = vector<int>;
using vvi = vector<vi>;

using pii = pair<int, int>;
#if 1
using List = deque<pii>;
#else
using List = list<pii>;
#endif
using ListIter = List::iterator;
using Map = unordered_map<int, ListIter>;

class LRUCache {
  size_t capacity;
  List lru_list;
  Map map;

public:
  LRUCache(size_t capacity) : capacity(capacity) {}

  void put(int key, int value) {
    Map::iterator miter = map.find(key);
    promote(key, value, miter != map.end() ? miter->second
      : (lru_list.size() == capacity) ? --lru_list.end() : lru_list.end());
  }
  int get(int key) {
    Map::iterator miter = map.find(key);
    if (miter == map.end()) return -1;
    pii v = *(miter->second);
    promote(v.first, v.second, miter->second);
    return v.second;
  }

  void promote(int key, int value, ListIter iter) {
    if (iter != lru_list.end()) lru_list.erase(iter);
    lru_list.push_front({key, value});
    map[key] = lru_list.begin();
  }
};

void run(LRUCache& cache, vvi& vv) {
  for (auto& e : vv) {
    if (e.size() > 1) cache.put(e[0], e[1]);
    else cout << cache.get(e[0]) << endl;
  }
}

void test1() {
  LRUCache cache(10);
  vvi vv {
    {10,27}, {8,10}, {6,29}, {1,9},
    {1}, {6}, {1}
  };
  run(cache, vv);
}

int main() {
  test1();

  return 0;
}

【问题讨论】:

  • 请将您的问题限制在 1 个主要问题上,而不是两个单独的问题
  • 感谢您的反馈。我已经更新了我的问题。
  • 您还需要minimal reproducible example 而不是外部链接
  • 感谢您的友好评论。我添加了一个紧凑的可重现场景,而不是提供带有详细描述的链接。

标签: c++ list iterator deque c++-standard-library


【解决方案1】:

我没有尝试过你的代码,但我猜你的问题是迭代器失效。在promote 中,您可以使用push_fronterase 来自底层容器的元素。如果容器是list,则没有迭代器无效。如果容器是deque,那么一些迭代器将失效。

CppReference 有一节介绍迭代器失效。

【讨论】:

    猜你喜欢
    • 2012-03-27
    • 2010-10-11
    • 1970-01-01
    • 2016-01-19
    • 2015-07-04
    • 2018-07-02
    • 1970-01-01
    • 2015-02-02
    • 1970-01-01
    相关资源
    最近更新 更多