C++ 使用冒泡排序根据第一列对二维数组的行进行排序

Posted

技术标签:

【中文标题】C++ 使用冒泡排序根据第一列对二维数组的行进行排序【英文标题】:C++ Sort rows of a 2D array, based on the first column using bubblesort 【发布时间】:2021-12-30 19:43:28 【问题描述】:

免责声明:这些都是假地址,仅供学习使用。

我希望我的列表根据 [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
*/

【问题讨论】:

在 C++ 中有更好的方法来实现这一点。使用索引来迭代固定长度的数组并不是一个好的开始。但是,如果您正在学习冒泡排序的工作原理,您最好创建一个 struct 来保存每个名称/地址记录,然后创建一个数组。 【参考方案1】:

数组不是一个很好的数据类型来做你想做的事情。 最好从现实生活中提取“单词”并在您的代码中使用它们。 您正在做的是对联系人进行排序,因此请先制作代表联系人的内容,例如一个结构。从那里构建您的代码,(一次一个函数,函数也非常适合命名事物)然后将变得更具可读性和更易于理解。比如这样:

#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);

【讨论】:

对不起,它看起来很完美而且做工很好,但我仍然是一个初学者,我目前只尝试通过仅使用 c++ 的基础知识来学习冒泡排序如何与 2d 数组一起工作,谢谢不过你的慷慨。 没问题,但也是一种看待事物的方式。我认为结构/字符串/向量(标准库的东西)的使用和编写可重复的代码是初学者在开始编写自己的算法之前就应该学习的内容。所以就以这个为例吧:) 我以后一定会记住这一点的:D 很好 :) 如果您以后有任何问题,我很乐意为您提供帮助【参考方案2】:

如果您询问 10 位 C++ 开发人员,您可能会得到 11 个不同的答案,这些答案具有不同的复杂性,并且使用了更多或更少的语言特性。这是我的看法,距离 OP 的代码仅几步之遥。

如果您想将所有信息放在一起,那么这就是 classes 或 structs 的用途,并且确实是 C++ 与 C 不同的重要部分。您滚动您的自己的类型(在本例中为 Record 结构),它将所有名称/地址信息组合到一个项目中。无需任何额外代码即可复制只有简单成员变量的结构体。

还有几件事要做。 OP 使用coutifstream,它们都可以处理strings 和数字。他们需要一些帮助来处理我们的新 Record 类型,这就是两个流运算符重载为我们所做的。最后,如果我们要进行排序,我们需要能够比较两个记录:在本例中按姓氏字母顺序,因此我们重载了 '>' 运算符。

现在,我们有一个 1D Records 数组,而不是 2D 字符串数组。

#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

【讨论】:

以上是关于C++ 使用冒泡排序根据第一列对二维数组的行进行排序的主要内容,如果未能解决你的问题,请参考以下文章

基于一列对二维数组进行排序

如何按列对二维数组(锯齿状)进行排序[重复]

根据第一列对 CSV 文件进行排序

基于列对二维向量数组进行排序

C++ 按列对二维向量进行排序

Vector容器 二维数组sort()排序