首页 > 解决方案 > 如何在 C++ 中对数组进行洗牌?

问题描述

我有一个数组:

names[4]={john,david,jack,harry};

我想随机洗牌,比如:

names[4]={jack,david,john,harry};

我尝试使用它,但它只是打乱了数组中第一个单词的字母:

random_shuffle(names->begin(), names->end());

这是完整的代码,它从 .txt 文件中读取名称并放入一个数组中:

#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;


int main() {

    ifstream readName("names.txt");
    string names[197];
    int i = 0;
    for (string line; getline(readName, line); ){
        readName >> names[i];
        i++;
    }
    readName.close();


    random_shuffle(names->begin(), names->end());
    
    for (int i = 0; i < 197; i++) {
        cout << names[i] << endl;
    }
    return 0;
}

我从不同的人那里尝试了一些其他的东西,但我无法做到。有什么帮助,谢谢!

标签: c++arraysrandomshuffle

解决方案


这是您的代码,我认为更改量最小。有人可能会争辩说,我不需要对你的第一个 for 循环进行太多更改,但我认为如果你有先见之明知道你正在阅读多少个名字,你不妨使用这些知识。

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>  // std::begin(), std::end(); required for C-arrays
#include <random>    // std::mt19937; needed to feed std::shuffle()
#include <string>
// using namespace std;  // BAD PRACTICE

int main() {
  constexpr int size = 4;  // Give your magic number a name; only need to change
                           // a single location
  std::ifstream readName("names.txt");
  if (!readName) {  // Always check that you successfully opened the file.
    std::cerr << "Error opening file.\n";
    return 1;
  }

  std::string names[size];
  // int i = 0;
  for (int i = 0; i < size; ++i) {  // Retool the loop entirely
    std::getline(readName, names[i]);
  }
  readName.close();

  // This is a fragile solution. It's only working because the array is in
  // scope
  std::shuffle(std::begin(names), std::end(names),
               std::mt19937{std::random_device{}()});

  for (int i = 0; i < size; i++) {
    std::cout << names[i]
              << '\n';  // Don't use std::endl unless you actually need it
  }
  return 0;
}

不过,这不是理想的代码。对输入文件大小的任何更改都需要更改代码并重新编译。最大的单一变化是摆脱std::random_shuffle和使用std::shuffle()std::random_shuffle已在 C++14 中弃用并在 C++17 中删除。不好用。std::shuffle()确实增加了提供 PRNG 的要求,但还不错。如果你有一个 PRNG 需要在一个更大的程序中随机化许多不同的东西,它会导致更好的代码。这是因为最好有一个 PRNG 并让它在你的程序的整个过程中都存在,而不是不断地构建新的。

而 C-array 只是让事情变得有点笨拙。输入std::vector

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <random>  // std::mt19937; needed to feed std::shuffle()
#include <string>
#include <vector>

int main() {
  std::ifstream readName("names.txt");
  if (!readName) {  // Always check that you successfully opened the file.
    std::cerr << "Error opening file.\n";
    return 1;
  }

  std::vector<std::string> names;
  std::string name;
  while (std::getline(readName, name)) {  // Retool the loop entirely
    names.push_back(name);
  }
  readName.close();

  std::shuffle(std::begin(names), std::end(names),
               std::mt19937{std::random_device{}()});

  for (const auto& i : names) {
    std::cout << i << '\n';
  }

  return 0;
}

向量可以根据需要增长,因此您会看到读取名称的循环变得多么简单。它也更加灵活,因为您不必提前知道预期有多少条目。它会“正常工作”。调用std::shuffle()I 时保留了std::begin(names)语法,因为许多人认为这是最佳实践,如果你愿意,你也可以使用names.begin(),因为向量类提供了自己的迭代器。


推荐阅读