【问题标题】:Unsure of what's wrong with my sorting algorithm不确定我的排序算法有什么问题
【发布时间】:2019-11-23 14:41:36
【问题描述】:

我一直在尝试使用 c-strings 对输入的数据进行排序。到目前为止一切顺利,除了案例 3​​ 和 4,也就是排序和显示排序后的数据,输出不是预期的。 显示的排序数据的输出只是给了我

0 0 0 0 0 0 0 0 0 . . . 这是我第一次使用 c-strings,但我仍然不太熟悉结构的概念。如果有人有替代方法或知道我的案例 3/4 代码有什么问题,请告诉我。谢谢

这是我的代码:

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

struct sPlayer {
    char lname[20];
    char fname[20];
    int birthmonth;
    int birthday;
    int birthyear;
};
int main()
{

    int choice;
    sPlayer players[10];
    sPlayer sortedData[10];

    while (true) {
        cout << "Choose an option: " << endl;
        cout << "1 - Input data, 2 - display original data, 3 - 
            sort data by last name,\n4 - display sorted data,
            5 - search by
                    last name,\n6 - display goodbye message and exit the program " << 
            endl;

        cin >> choice;
        switch (choice) {
        case 1:

            cout << "Enter data for 10 soccer players " << endl;
            cout << "Enter in order: Last name, first name,(as integers) birth month, birthday, birth year, ";
            cout << "separated by a space. Press [ENTER] to enter next player data. " << endl;

            for(int i = 0; i < 10; i++)
            {
                cin >> players[i].lname;
                cin >> players[i].fname;
                cin >> players[i].birthmonth;
                cin >> players[i].birthday;
                cin >> players[i].birthyear;
            }
            break;

        case 2:
            cout << "Unsorted data: " << endl;
            for (int i = 0; i < 10; i++) {
                cout << players[i].lname << " "
                     << players[i].fname << " " << players[i].birthmonth;
                cout << " " << players[i].birthday << " " << players[i].birthyear << endl;
            }
            cout << endl;
            break;

        case 3:
            sortedData[10] = players[10];
            for (int i = 0; i < 9; i++) {
                for (int j = i + 1; j < 10; j++) {

                    if (strcmp(sortedData[i].lname, sortedData[j].lname) > 0) {
                        char tempLastName[20];
                        char tempFirstName[20];
                        int tempBirthmonth;
                        int tempBirthday;
                        int tempBirthyear;

                        strcpy(tempLastName, sortedData[i].lname);

                        strcpy(sortedData[i].lname, sortedData[j].lname);

                        strcpy(sortedData[j].lname, tempLastName);

                        strcpy(tempFirstName, sortedData[i].fname);

                        strcpy(sortedData[i].fname, sortedData[j].fname);

                        strcpy(sortedData[j].fname, tempFirstName);

                        tempBirthmonth = sortedData[i].birthmonth;

                        sortedData[i].birthmonth = sortedData[j].birthmonth;

                        sortedData[j].birthmonth = tempBirthmonth;

                        tempBirthday = sortedData[i].birthday;

                        sortedData[i].birthday = sortedData[j].birthday;

                        sortedData[j].birthday = tempBirthday;

                        tempBirthyear = sortedData[i].birthyear;

                        sortedData[i].birthyear = sortedData[j].birthyear;

                        sortedData[j].birthyear = tempBirthyear;
                    }
                }
            }
            break;

        case 4:
            cout << "Sorted data: " << endl;

            for (int i = 0; i < 10; i++) {
                cout << sortedData[i].lname << " 
                                               " << sortedData[i].fname << "
                                               " << sortedData[i].birthmonth << "
                                               " 
                     << sortedData[i].birthday << " " << sortedData[i].birthyear << endl;
            }
            cout << endl;
            break;

        case 5:
            char searchString[20];
            while (true) {
                cout << "Enter one or more 
                        starting letters of the last name(enter '//' to quit this option)
                    : " << endl;
                    cin
                    >> searchString;

                if (strcmp(searchString, "//")
                    == 0)
                    break;
                else {
                    int length = strlen(searchString);

                    strcat(searchString, "xx");
                    bool notFound = true;

                    for (int i = 0; i < 10; i++) {
                        if (strncmp(players[i].lname, searchString, length) == 0) {
                            cout << players[i].lname << " " << players[i].fname << " " << players[i].birthmonth << " " << players[i].birthday << " " << players[i].birthyear << endl;

                            notFound = false;
                        }
                    }
                    if (notFound) {
                        cout << "Not 
                                found." << endl;
                    }
                }
            }
            break;

        case 6:
            cout << "Good Bye " << endl;
            break;

        default:
            cout << "Invalid Option , Try again" << endl;
        }
        if (choice == 6)
            break;
    }

    return 0;
}

【问题讨论】:

  • 不相关,但如果使用输入流(std::cin),您应该始终在输入后检查流状态(您可以将多个读取操作分组,但您只能如果在最后一次读取后流仍然正常,则假定数据有效)。请注意,用户可能总是输入了无效数据(例如,在要求整数值时包含字母的字符串)。
  • 简单得多:sPlayer tmp = sortedData[i]; sortedData[i] = sortedData[j]; sortedData[j] = tmp;,甚至可以缩短为std::swap(sortedData[j], sortedData[j]);...
  • sortedData[10] = players[10]; 是未定义的行为,因为您正在访问两个数组的末尾。
  • @1201ProgramAlarm 只比我快几秒钟...[x] 仅在一种情况下表示数组的大小:当您声明它时。在以后的任何时候,它都会在某个索引处访问数组。您现在尝试复制第 10 个元素(不存在),而元素 [0; 9]保持不变。又跑题了——为什么只有 10 名玩家?据我所知,足球队由 11 支球队组成......
  • 复制数组:试试std::copy(players, players + sizeof(players)/sizeof(*players), sortedData); - 和std::array 在许多方面都比经典的原始数组方便得多。

标签: c++ arrays string sorting struct


【解决方案1】:

通常最好将大问题拆分成小问题。我推荐使用子函数。

而且,您应该使用 C++ STL 和算法。这很有帮助。你会看见。不要使用像char lname[20]sPlayer players[10]; 这样的普通数组。请使用 STL 容器。它们可以增长并且可以调整大小。它还可以大大减少您的复制工作。

使用面向对象的方法。数据和方法应该在一个类中。 sPlayer 知道如何打印和阅读。因此,将这些方法添加到您的结构中。

您应该使用算法。喜欢std::copy。这让生活更轻松。

错误已经在你帖子下的 cmets 中提到了。

请查看修改后的示例(一种可能性):

#include <iostream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

struct sPlayer {
    // Data
    std::string lname;
    std::string fname;
    unsigned int birthmonth;
    unsigned int birthday;
    unsigned int birthyear;

    // Extractor operator
    friend std::istream& operator >> (std::istream& is, sPlayer& sp) {
        return is >> sp.lname >> sp.fname >> sp.birthmonth >> sp.birthday >> sp.birthyear;
    }

    // Inserter operator
    friend std::ostream& operator << (std::ostream& os, const sPlayer& sp) {
        return os << sp.fname << ' ' << sp.lname << ' ' << sp.birthmonth << '/' << sp.birthday << '/' << sp.birthyear;
    }
};

constexpr int CmdInputData = 1;
constexpr int CmdDisplayOriginalData = 2;
constexpr int CmdSortByLastName = 3;
constexpr int CmdDisplaySortedData = 4;
constexpr int CmdSearchLastName = 5;
constexpr int CmdExit = 6;

// Read users choice. Check for valid data
int getMenuSelection()
{
    std::cout << "\n\nChoose an option:\n   1 - Input Data\n   2 - Display original data\n" <<
        "   3 - Sort data by last name\n   4 - Display sorted data\n   5 - Search by last name\n" <<
        "   6 - Exit the program\n\n --> ";

    // Here we will store the selection
    int selection{ 0 };
    // As long as there is no good selection, we will read a number
    bool noGoodSelection = true;
    while (noGoodSelection) {
        // Read selection
        std::cin >> selection;
        // Check if valid
        noGoodSelection = ((selection < CmdInputData) || (selection > CmdExit));
        // If not, show message and read again
        if (noGoodSelection) {
            std::cout << "Invalid Option , Try again" << '\n';
            std::cin.clear(); std::cin.ignore();
        }
    }
    return selection;
}


void enterSPlayerData(std::vector<sPlayer>& sp)
{
    // Ask, how many players we would like to register
    std::cout << "\n\nEnter soccer player data\n\nHow many player do you want to register: ";
    size_t numberOfPlayersToRegister{ 0 };
    std::cin >> numberOfPlayersToRegister;

    // Make space in vector for all the players
    sp.clear();
    sp.resize(numberOfPlayersToRegister);

    // Read all players
    for (size_t i = 0; i < numberOfPlayersToRegister; ++i) {
        std::cout << '\n' << (i+1) <<"  Enter --> Last Name --> First Name --> Birt Month --> Birth Day --> Birth Year\n";
        std::cin >> sp[i];
    }
}


int main()
{
    // This is our player vector
    std::vector<sPlayer> players{};

    // Andf here a copy with the sorted data
    std::vector<sPlayer> playersSorted{};

    // If we want zo search a name in the vector
    std::string searchString{};
    bool playerFound{ false };

    // Menu selection
    int selection{ CmdExit };
    do {
        selection = getMenuSelection();
        switch (selection)
        {
        case CmdInputData:
            // Read player vector
            enterSPlayerData(players);
            break;

        case CmdDisplayOriginalData:
            // Show all players
            std::cout << "\n\nPlayer List\n\n";
            std::copy(players.begin(), players.end(), std::ostream_iterator<sPlayer>(std::cout, "\n"));
            break;

        case CmdSortByLastName:
            // Copy player list and sort the copy
            playersSorted.clear();
            std::copy(players.begin(), players.end(), std::back_inserter(playersSorted));
            std::sort(playersSorted.begin(), playersSorted.end(), 
                [](const sPlayer & sp1, const sPlayer & sp2) { return sp1.lname < sp2.lname; });
            break;

        case CmdDisplaySortedData:
            // Show the sorted data
            std::cout << "\n\nPlayer List Sorted\n\n";
            std::copy(playersSorted.begin(), playersSorted.end(), std::ostream_iterator<sPlayer>(std::cout, "\n"));
            break;

        case CmdSearchLastName:
            // Sear for a part of a name
            std::cout << "\n\nSearch Player name\n\nEnter some starting characters of Name:  ";
            std::cin >> searchString;
            playerFound = false;
            std::for_each(players.begin(), players.end(),
                [&searchString, &playerFound](const sPlayer & sp) {
                    if (sp.lname.find(searchString) != std::string::npos) {
                        std::cout << "Found Player\n" << sp << '\n';
                        playerFound = true;
                    }
                }
            );
            if (!playerFound) std::cout << "\nNo player found\n\n";
            break;
        default:
            selection = CmdExit;
            break;
        }
    } while (selection != CmdExit);
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 2020-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-29
    相关资源
    最近更新 更多