【问题标题】:How to shuffle list of pointers in C++?如何在 C++ 中打乱指针列表?
【发布时间】:2012-10-13 11:25:06
【问题描述】:

如何在 C++ 中打乱 stl 指针列表? 我在类 Player 上有 stl 指针向量,我像

一样随机播放
std::random_shuffle(players.begin(), players.end());

是否已经有不需要随机访问的随机列表算法,或者我需要将列表转换为向量 => 随机播放 => 回到列表?有没有更优雅的解决方案?

【问题讨论】:

  • 有什么理由需要使用列表吗?
  • 请考虑,列表几乎总是远低于向量,即使在历来被视为优越的领域也是如此。
  • @BenjaminLindley 我需要大量的插入操作和列表是更好的选择,而且我已经继承了该代码并且有严格的截止日期,所以我现在不想赌博
  • 您可能会问自己为什么首先使用std::liststd::list 闪耀的情况是:1)您需要迭代器始终保持有效(例如,存储它们,但指向 std::deque 元素或向量中索引的指针是要考虑的替代方案),2)您想要恒定时间拼接.如果您既不需要 1 也不需要 2,请使用其他内容(这意味着 dequevector[multi]set)。

标签: c++ boost stl


【解决方案1】:

随机洗牌算法将特定元素与随机选择的元素交换。重复遍历列表来获取元素是非常低效的(也就是O(n^2)操作)。

这就是为什么最好(更快)将您的列表复制到一个数组中,进行随机洗牌并可能恢复列表。那将是 3*n 遍历,仍然是 O(n)

【讨论】:

  • 非常适合复杂性开始起作用的非常长的列表。但是对于短列表(如播放列表),常数因素可能会发挥更大的作用。将复杂性理论保存到我们不希望无限扩展的正确位置(不是这样)。
  • @LokiAstari 对于一个简短的列表,常数因素也无关紧要 - 无论你怎么做,它都很快。因此,恕我直言,您最好为速度很重要的大型播放列表做好准备,而不是针对无关紧要的短列表进行优化并在大型播放列表中失败。
  • 我会先说常见情况的代码,然后仅在必要时进行优化。不是针对异常的代码,然后针对常见情况进行优化(过早的优化是万恶之源Knuth)。关键是当列表很短时,const 因素更重要。但这不是重点。不要盲目地应用你在大学里学到的东西。您需要知道应用它们的正确时间。这不是那种情况(直到您可以证明播放列表足够长才重要)。即使播放列表有 100,000 个,我也怀疑进行随机随机播放的时间对人眼来说是显而易见的。
  • 你错了。只需对其进行基准测试,您就会看到。将 100,000 个元素复制到向量的随机洗牌会很快。为每次交换遍历列表的随机 shuffle 实现会慢很多。但你不必相信我的话,试试吧。
  • 我并不是说它会更快。我是说您使用错误的技术来解决问题(即使您找到了正确的解决方案)。我是说复杂性理论与情况无关。此外,除非您在 1980 硬件上运行,否则我不认为它很明显(我试过)。
【解决方案2】:

std::random_shuffle 需要一个随机迭代器。 Vector 支持这一点,而 List 则不支持。 std::deque 怎么样,它是一种 Vector 和一种 List。

【讨论】:

    【解决方案3】:

    你的问题很有趣。所以,我试着写了一些东西,最后想出了这个。

        //---------- sample List initialization ------
        list<string> lst;
        lst.push_back("A");
        lst.push_back("B");
             ....
        lst.push_back("Y");
        lst.push_back("Z");
    
        #define LIST_SIZE 26
        //--------------------------------------------
    
        //------------- Shuffle Algorithm ------------
        unordered_multimap<int,string> mymap;
        int HashKeys[LIST_SIZE];
        srand((int)time(NULL) * (int)clock());
    
        for(int i = 0; i<LIST_SIZE; i++) // loop 'n' times
        {
            HashKeys[i] = rand(); // O(c) operation
        }
    
        for(int i = 0;lst.size() > 0; i++) // loop 'n' times
        {
             // O(n) operation ( varies from O(c) to O(n) according to the situations )
            mymap.insert(std::make_pair<int,string>(HashKeys[rand() % LIST_SIZE],lst.front()));
            lst.pop_front(); // O(c) operation
        }
    
        unordered_multimap<int,string>::iterator it;
        for(int i = 0; i < LIST_SIZE ;i++) // loop 'n' times
        {
            while(mymap.count(HashKeys[i]) > 0) // unpredictable
            {
                it = mymap.find(HashKeys[i]); // O(c) for single O(n) for multi
                        // ...USAGE...
                cout << it->second << endl;
                        lst.push_back(it->second);
                        //............
                mymap.erase(it); // O(c) operation
            }
        }
        //-------------------------------------------------
    

    如果哈希图中的同一键有多个值,则时间复杂度为 O(n^2)。 否则时间复杂度为 O(n)。 所以一切都取决于函数(rand() % LIST_SIZE)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-10
      • 2012-07-03
      相关资源
      最近更新 更多