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 的代码仅几步之遥。

如果你想把所有的信息放在一起,那么这就是 classes 或 structs 的目的,这确实是 C++ 与众不同的重要原因来自 C。您滚动自己的类型(在本例中为 Record 结构),它将所有 name/address 信息组合到一个项目中。可以复制只有简单成员变量的结构,无需任何额外代码。

还有几件事要做。 OP 使用 coutifstream,它们都可以处理 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