如何对文件中数组中的单个列进行冒泡排序?C++
How to bubble sort a single column in an array from a file? C++
该程序要求用户搜索具有任何2D维度数组的文件(具有指定的行/列,这在函数之外,并不真正相关),在数组中选择一列,并使用气泡排序对该列进行排序。
我的函数代码:
int sortFile(string file1, string file2)
{
ifstream inFile;
inFile.open(file1.c_str());
if (inFile)
{
int row, col;
inFile >> row >> col;
long double arr[row][col];
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
inFile >> arr[i][j];
}
}
int columnSort;
cout << "Enter the column number you'd like to sort between 1 and " << col << ": ";
cin >> columnSort;
columnSort -= 1;
for (int i = 0; i < row - 1; i++)
{
for (int j = 0; j < col - 1; j++)
{
if (arr[i][columnSort] > arr[i+1][columnSort])
{
swap(arr[i][columnSort], arr[i+1][columnSort]);
}
}
}
inFile.close();
ofstream sortFile;
sortFile.open(file2.c_str());
if (sortFile)
{
sortFile << row << " " << col << endl;
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
sortFile << arr[i][j] << " ";
}
sortFile << endl;
}
sortFile.close();
cout << "File named " << file2 << " sorted and saved successfully." << endl;
cout << endl;
}
else
{
cout << "File could not be opened for writing..." << endl;
cout << "Terminating program.";
return 1;
}
}
else
{
cout << "File could not be opened for sorting..." << endl;
cout << "Terminating program.";
return 1;
}
}
我使用以下文件作为测试:
5 6
5 8 4 2 3 6
6 5 8 7 1 2
3 9 6 3 6 4
7 7 5 2 1 3
4 2 0 3 8 4
当我指定第3列时,排序输出是这样的:
5 6
5 8 4 2 3 6
6 5 6 7 1 2
3 9 5 3 6 4
7 7 0 2 1 3
4 2 8 3 8 4
我在写的东西中没有发现任何逻辑问题(可能是因为我正在完成C++入门课程,缺乏经验),所以我不完全确定是什么原因导致它没有真正对所有东西进行排序。对于具有重复值的列,可能也存在错误?
注意:字符串变量是零问题。这个程序中还有三个函数使用相同的文件打开/关闭等等,其中唯一的问题似乎是排序算法。因此,我没有包括这一职能之外的任何内容
您的冒泡排序实现有一个小问题。我根据维基百科上的伪代码重新表述了这个。
// Sort one column with bubblesort
for (size_t n = csv.size(); n > 1U; --n)
for (size_t i = 0U; i < n-1; ++i)
if (csv[i][SortColumn] > csv[i+1][SortColumn])
std::swap(csv[i][SortColumn], csv[i+1][SortColumn]);
但另外,我想向您展示一个"更多"的C++解决方案。
基本上,你似乎想读取csv数据。这是一个标准的任务,我会给你详细的解释。最后,所有的阅读都将在一行中完成。
在源文本文件中也不需要有行和列说明符。算法将自己检测数组的维度。
尽管如此,随着CSV所有人都在谈论并链接到[我如何在C++中读取和解析CSV文件?][1],这些问题来自2009年,现在已经超过10年了。大多数答案也都是陈旧而复杂的。所以,也许是时候改变了。
在现代C++中,您可以使用在范围上迭代的算法。您经常会看到类似"someAlgorim(container.begin(),container.end(),someLambda)"的内容。我们的想法是对一些类似的元素进行迭代。
在您的情况下,我们对输入字符串中的标记进行迭代,并创建子字符串。这被称为标记化。
正是出于这个目的,我们有了std::sregex_token_iterator
。因为我们已经为这个目的定义了一些东西,所以我们应该使用它
这是一个迭代器。对于在字符串上迭代,因此为sregex。开始部分定义了我们应该在什么输入范围内操作,然后在输入字符串中有一个std::regex
来表示应该匹配/不应该匹配的内容。匹配策略的类型由最后一个参数给出。
- 1-->给我在正则表达式中定义的内容
- -1-->根据正则表达式告诉我什么是不匹配的
所以,既然我们了解了迭代器,我们就可以std::将令牌从迭代器复制到我们的目标,std::string
的std::vector
。由于我们不知道我们有多少列,我们将使用std::back_inserter
作为目标。这将添加我们从std::sregex_token_iterator
获得的所有令牌,并将其附加到我们的std::vector<std::string>>
。我们有多少列并不重要。
很好。这样的声明可能看起来像
std::copy( // We want to copy something
std::sregex_token_iterator // The iterator begin, the sregex_token_iterator. Give back first token
(
line.begin(), // Evaluate the input string from the beginning
line.end(), // to the end
re, // Add match a comma
-1 // But give me back not the comma but everything else
),
std::sregex_token_iterator(), // iterator end for sregex_token_iterator, last token + 1
std::back_inserter(cp.columns) // Append everything to the target container
);
现在我们可以了解这种复制操作是如何工作的。
下一步。我们想从文件中读取。该文件还包含某种相同的数据。相同的数据是行。
至于上面,我们可以迭代类似的数据。如果是文件输入或其他什么。为此,C++具有CCD_ 8。这是一个模板,作为模板参数,它获取应该读取的数据类型,作为构造函数参数,它获得对输入流的引用。不管输入流是std::cin
、std::ifstream
还是std::istringstream
。所有类型的流的行为都是相同的。
由于我们没有SO文件,我使用(在下面的示例中)std::istringstream
来存储输入的csv文件。但是,您当然可以通过定义std::ifstream testCsv(filename)
来打开一个文件。没问题。
使用std::istream_iterator
,我们对输入进行迭代并读取类似的数据。在我们的例子中,一个问题是我们希望迭代特殊数据,而不是某些内置数据类型。
为了解决这个问题,我们定义了一个Proxy类,它为我们做内部工作(我们不想知道如何封装在代理中)。在代理中,我们覆盖类型转换运算符,以将结果转换为std::istream_iterator
的预期类型。
最后一个重要步骤。std::vector
有一个范围构造函数。它还有许多其他构造函数,我们可以在定义std::vector
类型的变量时使用。但就我们的目的而言,这个构造函数最适合。
因此,我们定义了一个变量csv,并使用它的范围构造函数,给它一个范围的开始和一个区域的结束。在我们的具体示例中,我们使用std::istream_iterator
的开始和结束迭代器。
如果我们结合以上所有内容,读取完整的CSV文件是一个一行,它是一个变量的定义,并调用其构造函数。
然后我们使用一个超简单的冒泡排序,如上所示,并显示结果。
请查看结果代码:
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <regex>
#include <algorithm>
#include <utility>
std::istringstream testCsv{ R"(5 8 4 2 3 6
6 5 8 7 1 2
3 9 6 3 6 4
7 7 5 2 1 3
4 2 0 3 8 4)" };
// Define Alias for easier Reading
using Columns = std::vector<std::string>;
using CSV = std::vector<Columns>;
// Proxy for the input Iterator
struct ColumnProxy {
// Overload extractor. Read a complete line
friend std::istream& operator>>(std::istream& is, ColumnProxy& cp) {
// Read a line
std::string line; cp.columns.clear();
std::getline(is, line);
// The delimiter
const std::regex re(" ");
// Split values and copy into resulting vector
std::copy(std::sregex_token_iterator(line.begin(), line.end(), re, -1),
std::sregex_token_iterator(),
std::back_inserter(cp.columns));
return is;
}
// Type cast operator overload. Cast the type 'Columns' to std::vector<std::string>
operator std::vector<std::string>() const { return columns; }
protected:
// Temporary to hold the read vector
Columns columns{};
};
constexpr size_t SortColumn = 2;
int main()
{
// Define variable CSV with its range constructor. Read complete CSV in this statement, So, one liner
CSV csv(std::istream_iterator<ColumnProxy>(testCsv), {});
// Sort one column with bubblesort
for (size_t n = csv.size(); n > 1U; --n)
for (size_t i = 0U; i < n-1; ++i)
if (csv[i][SortColumn] > csv[i+1][SortColumn])
std::swap(csv[i][SortColumn], csv[i+1][SortColumn]);
// Print result. Go through all lines and then copy line elements to std::cout
std::for_each(csv.begin(), csv.end(), [](Columns& c) {
std::copy(c.begin(), c.end(), std::ostream_iterator<std::string>(std::cout, " ")); std::cout << "n"; });
}
打开文件的附加提示。您正在使用:
ifstream inFile;
inFile.open(file1.c_str());
if (inFile)
您可以也应该使用:
if (std::ifstream inFile(file1.c_str()); inFile) {
它将使inFile保持在内部范围内。析构函数将在if
结束时自动关闭该文件。
- 如何在C++中对数组进行冒泡排序
- 我想在 c++ 中对单向链表进行冒泡排序,但我一直面临左值错误,无法解决它
- 在C++中使用冒泡排序时出现意外值
- 冒泡排序中所需的交换次数,而无需实际对其进行排序
- 如何对文件中数组中的单个列进行冒泡排序?C++
- 需要关于如何将我的随机数数组连接到冒泡排序的帮助
- 冒泡排序无法对C++中的对象的动态数组进行排序
- 冒泡排序.C++
- 链表的冒泡排序
- 有没有选择排序优于冒泡排序的输入
- C++:如何使用冒泡排序来重新排列我的数据
- 冒泡排序随机数
- 矢量下标超出范围-冒泡排序
- 使用冒泡排序比较类对象
- 在c++中使用冒泡排序/交换对字符串进行排序
- 矢量下标超出范围错误,C++,冒泡排序
- 冒泡排序、选择排序和插入排序
- 使用冒泡排序c++对结构数组的成员进行优先级排序
- 冒泡排序链表C++
- 行搜索和冒泡排序的问题