C++ 基于使用冒泡排序的第一列对二维数组的行进行排序
C++ Sort rows of a 2D array, based on the first column using bubblesort
免责声明:这些都是假地址,仅供学习。
我希望我的列表根据第一列 [i][0] 进行排序,并使行的其余部分 ([i][j]) 跟随新的排序位置列.现在我的代码似乎只对第一列进行排序,而不是让整行跟随它到第一列已经给出的新位置。我尝试了很多方法,但一直未能找到解决方案。
请帮帮我!
/*
konst.txt includes following:
Stengren Lena Bokstavsgatan 10 27890 Stadköping
Osterblad Johan Grönskog 12A 10908 Ljushöjda
Broholme Reny Havstundav 8 36799 Hökänget
Roholm Karol Stugsten 7 45892 Rågskog
Lindagren Erika Hjufjord 139 87834 Skogholma
*/
string adresser[50][6];
string input_file = "D:\konst.txt";
ifstream input_stream;
int lastpos = 0;
string temp;
input_stream.open(input_file);
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 6; j++) {
input_stream >> adresser[i][j]; //Saves the columns and rows in the 2d array
cout << adresser[i][j] << ' '; //Writes out the whole list
}
cout << endl;
}
for (int i = 0; i < 50; i++) { //Finds the last position for columns
if (adresser[i][0] == "") {
lastpos = i;
break;
}
}
cout << "\n\n\n\n";
for (int i = lastpos - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (adresser[j][0] > adresser[j + 1][0]) { //Sorts the array for ONLY the first columns.
temp = adresser[j][0];
adresser[j][0] = adresser[j + 1][0];
adresser[j][0] = temp;
}
}
}
提示二维数组包含的内容:
/*
Stengren Lena Bokstavsgatan 10 27890 Stadköping
Osterblad Johan Grönskog 12A 10908 Ljushöjda
Broholme Reny Havstundav 8 36799 Hökänget
Roholm Karol Stugsten 7 45892 Rågskog
Lindagren Erika Hjufjord 139 87834 Skogholma
*/
代码的作用:
/*
Broholme Lena Bokstavsgatan 10 27890 Stadköping
Lindagren Johan Grönskog 12A 10908 Ljushöjda
Osterblad Reny Havstundav 8 36799 Hökänget
Roholm Karol Stugsten 7 45892 Rågskog
Stengren Erika Hjufjord 139 87834 Skogholma
*/
我想要它做什么:
/*
Broholme Reny Havstundav 8 36799 Hökänget
Lindagren Erika Hjufjord 139 87834 Skogholma
Osterblad Johan Grönskog 12A 10908 Ljushöjda
Roholm Karol Stugsten 7 45892 Rågskog
Stengren Lena Bokstavsgatan 10 27890 Stadköping
*/
数组不是执行您想要执行的操作的良好数据类型。
从现实生活中获取“文字”并在您的代码中使用它们是很好的。
您正在做的是对联系人进行排序,因此首先制作代表联系人的内容,例如一个结构。从那里构建你的代码,(一次一个函数,函数也很适合命名事物)然后将变得更具可读性和更容易理解。例如像这样:
#include <fstream>
#include <functional>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <regex>
struct contact_info_t
{
std::string first_name;
std::string last_name;
std::string address;
std::string postal_code;
std::string city;
};
// removed the "special" characters for now, seems code has some trouble with that
std::istringstream file_content
{
"Stengren Lena Bokstavsgatan 10 27890 Stadkoping\n"
"Osterblad Johan Gronskog 12A 10908 Ljushojda\n"
"Broholme Reny Havstundav 8 36799 Hokanget\n"
"Roholm Karol Stugsten 7 45892 Ragskog\n"
"Lindagren Erika Hjufjord 139 87834 Skogholma\n"
};
// load uses a regex to split up string, I think that's what causes the issues with special characters.
// but the bottom line is read your file and build a vector of structs from it. Not an array
auto load(std::istream& file)
{
static const std::regex rx{ "(\w+)\s+(\w+)\s+(\w+\s\w+)\s+(\w+)\s+(.*)" };
std::smatch match;
std::vector<contact_info_t> contacts;
std::string line;
while (std::getline(file,line))
{
if (std::regex_search(line,match,rx))
{
contact_info_t info;
info.last_name = match[1];
info.first_name = match[2];
info.address = match[3];
info.postal_code = match[4];
info.city = match[5];
contacts.push_back(info);
}
}
return contacts;
}
// Since you can sort by multiple predicates (functions that return a bool)
// I made a generic sort function. It sorts pointers to the structs
// so that no data is move where it is not necessary
auto sort(const std::vector<contact_info_t>& contacts, std::function<bool(const contact_info_t* lhs, const contact_info_t* rhs)> predicate)
{
std::vector<const contact_info_t*> sorted_contacts;
for (const auto& contact : contacts) sorted_contacts.push_back(&contact);
std::sort(sorted_contacts.begin(), sorted_contacts.end(), predicate);
return sorted_contacts;
}
// show the sorted contacts, one struct at a time.
// that way it is impossible for columns to get mixed up
void show_sorted_contacts(const std::vector<const contact_info_t*>& sorted_contacts)
{
for (const auto& contact : sorted_contacts)
{
std::cout << contact->last_name << " ";
std::cout << contact->first_name << " ";
std::cout << contact->address << " ";
std::cout << contact->city << " ";
std::cout << contact->postal_code << "\n";
}
}
int main()
{
auto contacts = load(file_content);
auto contacts_sorted_by_last_name = sort(contacts, [](const contact_info_t* lhs, const contact_info_t* rhs)
{
return (lhs->last_name < rhs->last_name);
});
show_sorted_contacts(contacts_sorted_by_last_name);
}
如果您问 10 个 C++ 开发人员,您可能会得到 11 个不同的答案,这些答案的复杂程度各不相同,并且使用了更多或更少的语言功能。这是我的看法,距离 OP 的代码仅几步之遥。
如果你想把所有的信息放在一起,那么这就是 class
es 或 struct
s 的目的,这确实是 C++ 与众不同的重要原因来自 C。您滚动自己的类型(在本例中为 Record 结构),它将所有 name/address 信息组合到一个项目中。可以复制只有简单成员变量的结构,无需任何额外代码。
还有几件事要做。 OP 使用 cout
和 ifstream
,它们都可以处理 string
和数字。他们需要一些帮助来处理我们的新 Record 类型,这就是两个流运算符重载为我们所做的。最后,如果我们要排序,我们需要能够比较两个记录:在本例中按姓氏字母顺序排列,因此我们重载了“>”运算符。
现在,我们有一个一维记录数组,而不是一个二维字符串数组。
#include <fstream>
#include <iostream>
#include <string>
//Create a structure to hold all the items for a name/address
struct Record
{
std::string familyName;
std::string firstName;
std::string streetName;
std::string streetNumber;
long postCode{ 0 };
std::string townName;
};
//Overloads for printing out a record ...
std::ostream& operator<<(std::ostream& os, const Record& r)
{
os << r.familyName << " " << r.firstName << " " << r.streetName << " "
<< r.streetNumber << " " << r.postCode << " " << r.townName;
return os;
}
//... and reading in a record
std::istream& operator>>(std::istream& is, Record& r)
{
is >> r.familyName >> r.firstName >> r.streetName >> r.streetNumber >> r.postCode >> r.townName;
return is;
}
//How to compare two records
bool operator>(const Record& lhs, const Record& rhs)
{
return lhs.familyName > rhs.familyName;
}
int main()
{
using namespace std;
//Create any fixed-length array of Records
Record records[20];
//Load the name/address info
//and keep a count
ifstream ifs;
ifs.open("konst.txt", ifstream::in);
auto nRecords = 0;
cout << "Input:\n";
while(ifs.good() && nRecords<20)
{
Record& r = records[nRecords];
ifs >> r;
cout << r << "\n";
nRecords++;
}
//Perform the bubble sort
for (int i = nRecords - 1; i > 0; i--)
{
for (int j = 0; j < i; j++)
{
if( records[j] > records[j+1])
{
//Swap records
Record tmp = records[j];
records[j] = records[j + 1];
records[j + 1] = tmp;
}
}
}
//Print out result
cout << "\nSorted:\n";
for (int i = 0; i < nRecords; i++)
{
cout << records[i] << "\n";
}
ifs.close();
}
结果如下(我的默认语言环境不解码 ä 或 ö):
Input:
Stengren Lena Bokstavsgatan 10 27890 Stadk├╢ping
Osterblad Johan Gr├╢nskog 12A 10908 Ljush├╢jda
Broholme Reny Havstundav 8 36799 Hökänget
Roholm Karol Stugsten 7 45892 Rågskog
Lindagren Erika Hjufjord 139 87834 Skogholma
Sorted:
Broholme Reny Havstundav 8 36799 Hökänget
Lindagren Erika Hjufjord 139 87834 Skogholma
Osterblad Johan Gr├╢nskog 12A 10908 Ljush├╢jda
Roholm Karol Stugsten 7 45892 Rågskog
Stengren Lena Bokstavsgatan 10 27890 Stadk├╢ping
免责声明:这些都是假地址,仅供学习。
我希望我的列表根据第一列 [i][0] 进行排序,并使行的其余部分 ([i][j]) 跟随新的排序位置列.现在我的代码似乎只对第一列进行排序,而不是让整行跟随它到第一列已经给出的新位置。我尝试了很多方法,但一直未能找到解决方案。
请帮帮我!
/*
konst.txt includes following:
Stengren Lena Bokstavsgatan 10 27890 Stadköping
Osterblad Johan Grönskog 12A 10908 Ljushöjda
Broholme Reny Havstundav 8 36799 Hökänget
Roholm Karol Stugsten 7 45892 Rågskog
Lindagren Erika Hjufjord 139 87834 Skogholma
*/
string adresser[50][6];
string input_file = "D:\konst.txt";
ifstream input_stream;
int lastpos = 0;
string temp;
input_stream.open(input_file);
for (int i = 0; i < 20; i++) {
for (int j = 0; j < 6; j++) {
input_stream >> adresser[i][j]; //Saves the columns and rows in the 2d array
cout << adresser[i][j] << ' '; //Writes out the whole list
}
cout << endl;
}
for (int i = 0; i < 50; i++) { //Finds the last position for columns
if (adresser[i][0] == "") {
lastpos = i;
break;
}
}
cout << "\n\n\n\n";
for (int i = lastpos - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (adresser[j][0] > adresser[j + 1][0]) { //Sorts the array for ONLY the first columns.
temp = adresser[j][0];
adresser[j][0] = adresser[j + 1][0];
adresser[j][0] = temp;
}
}
}
提示二维数组包含的内容:
/*
Stengren Lena Bokstavsgatan 10 27890 Stadköping
Osterblad Johan Grönskog 12A 10908 Ljushöjda
Broholme Reny Havstundav 8 36799 Hökänget
Roholm Karol Stugsten 7 45892 Rågskog
Lindagren Erika Hjufjord 139 87834 Skogholma
*/
代码的作用:
/*
Broholme Lena Bokstavsgatan 10 27890 Stadköping
Lindagren Johan Grönskog 12A 10908 Ljushöjda
Osterblad Reny Havstundav 8 36799 Hökänget
Roholm Karol Stugsten 7 45892 Rågskog
Stengren Erika Hjufjord 139 87834 Skogholma
*/
我想要它做什么:
/*
Broholme Reny Havstundav 8 36799 Hökänget
Lindagren Erika Hjufjord 139 87834 Skogholma
Osterblad Johan Grönskog 12A 10908 Ljushöjda
Roholm Karol Stugsten 7 45892 Rågskog
Stengren Lena Bokstavsgatan 10 27890 Stadköping
*/
数组不是执行您想要执行的操作的良好数据类型。 从现实生活中获取“文字”并在您的代码中使用它们是很好的。 您正在做的是对联系人进行排序,因此首先制作代表联系人的内容,例如一个结构。从那里构建你的代码,(一次一个函数,函数也很适合命名事物)然后将变得更具可读性和更容易理解。例如像这样:
#include <fstream>
#include <functional>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <regex>
struct contact_info_t
{
std::string first_name;
std::string last_name;
std::string address;
std::string postal_code;
std::string city;
};
// removed the "special" characters for now, seems code has some trouble with that
std::istringstream file_content
{
"Stengren Lena Bokstavsgatan 10 27890 Stadkoping\n"
"Osterblad Johan Gronskog 12A 10908 Ljushojda\n"
"Broholme Reny Havstundav 8 36799 Hokanget\n"
"Roholm Karol Stugsten 7 45892 Ragskog\n"
"Lindagren Erika Hjufjord 139 87834 Skogholma\n"
};
// load uses a regex to split up string, I think that's what causes the issues with special characters.
// but the bottom line is read your file and build a vector of structs from it. Not an array
auto load(std::istream& file)
{
static const std::regex rx{ "(\w+)\s+(\w+)\s+(\w+\s\w+)\s+(\w+)\s+(.*)" };
std::smatch match;
std::vector<contact_info_t> contacts;
std::string line;
while (std::getline(file,line))
{
if (std::regex_search(line,match,rx))
{
contact_info_t info;
info.last_name = match[1];
info.first_name = match[2];
info.address = match[3];
info.postal_code = match[4];
info.city = match[5];
contacts.push_back(info);
}
}
return contacts;
}
// Since you can sort by multiple predicates (functions that return a bool)
// I made a generic sort function. It sorts pointers to the structs
// so that no data is move where it is not necessary
auto sort(const std::vector<contact_info_t>& contacts, std::function<bool(const contact_info_t* lhs, const contact_info_t* rhs)> predicate)
{
std::vector<const contact_info_t*> sorted_contacts;
for (const auto& contact : contacts) sorted_contacts.push_back(&contact);
std::sort(sorted_contacts.begin(), sorted_contacts.end(), predicate);
return sorted_contacts;
}
// show the sorted contacts, one struct at a time.
// that way it is impossible for columns to get mixed up
void show_sorted_contacts(const std::vector<const contact_info_t*>& sorted_contacts)
{
for (const auto& contact : sorted_contacts)
{
std::cout << contact->last_name << " ";
std::cout << contact->first_name << " ";
std::cout << contact->address << " ";
std::cout << contact->city << " ";
std::cout << contact->postal_code << "\n";
}
}
int main()
{
auto contacts = load(file_content);
auto contacts_sorted_by_last_name = sort(contacts, [](const contact_info_t* lhs, const contact_info_t* rhs)
{
return (lhs->last_name < rhs->last_name);
});
show_sorted_contacts(contacts_sorted_by_last_name);
}
如果您问 10 个 C++ 开发人员,您可能会得到 11 个不同的答案,这些答案的复杂程度各不相同,并且使用了更多或更少的语言功能。这是我的看法,距离 OP 的代码仅几步之遥。
如果你想把所有的信息放在一起,那么这就是 class
es 或 struct
s 的目的,这确实是 C++ 与众不同的重要原因来自 C。您滚动自己的类型(在本例中为 Record 结构),它将所有 name/address 信息组合到一个项目中。可以复制只有简单成员变量的结构,无需任何额外代码。
还有几件事要做。 OP 使用 cout
和 ifstream
,它们都可以处理 string
和数字。他们需要一些帮助来处理我们的新 Record 类型,这就是两个流运算符重载为我们所做的。最后,如果我们要排序,我们需要能够比较两个记录:在本例中按姓氏字母顺序排列,因此我们重载了“>”运算符。
现在,我们有一个一维记录数组,而不是一个二维字符串数组。
#include <fstream>
#include <iostream>
#include <string>
//Create a structure to hold all the items for a name/address
struct Record
{
std::string familyName;
std::string firstName;
std::string streetName;
std::string streetNumber;
long postCode{ 0 };
std::string townName;
};
//Overloads for printing out a record ...
std::ostream& operator<<(std::ostream& os, const Record& r)
{
os << r.familyName << " " << r.firstName << " " << r.streetName << " "
<< r.streetNumber << " " << r.postCode << " " << r.townName;
return os;
}
//... and reading in a record
std::istream& operator>>(std::istream& is, Record& r)
{
is >> r.familyName >> r.firstName >> r.streetName >> r.streetNumber >> r.postCode >> r.townName;
return is;
}
//How to compare two records
bool operator>(const Record& lhs, const Record& rhs)
{
return lhs.familyName > rhs.familyName;
}
int main()
{
using namespace std;
//Create any fixed-length array of Records
Record records[20];
//Load the name/address info
//and keep a count
ifstream ifs;
ifs.open("konst.txt", ifstream::in);
auto nRecords = 0;
cout << "Input:\n";
while(ifs.good() && nRecords<20)
{
Record& r = records[nRecords];
ifs >> r;
cout << r << "\n";
nRecords++;
}
//Perform the bubble sort
for (int i = nRecords - 1; i > 0; i--)
{
for (int j = 0; j < i; j++)
{
if( records[j] > records[j+1])
{
//Swap records
Record tmp = records[j];
records[j] = records[j + 1];
records[j + 1] = tmp;
}
}
}
//Print out result
cout << "\nSorted:\n";
for (int i = 0; i < nRecords; i++)
{
cout << records[i] << "\n";
}
ifs.close();
}
结果如下(我的默认语言环境不解码 ä 或 ö):
Input:
Stengren Lena Bokstavsgatan 10 27890 Stadk├╢ping
Osterblad Johan Gr├╢nskog 12A 10908 Ljush├╢jda
Broholme Reny Havstundav 8 36799 Hökänget
Roholm Karol Stugsten 7 45892 Rågskog
Lindagren Erika Hjufjord 139 87834 Skogholma
Sorted:
Broholme Reny Havstundav 8 36799 Hökänget
Lindagren Erika Hjufjord 139 87834 Skogholma
Osterblad Johan Gr├╢nskog 12A 10908 Ljush├╢jda
Roholm Karol Stugsten 7 45892 Rågskog
Stengren Lena Bokstavsgatan 10 27890 Stadk├╢ping