Как структурировать функцию, которая может сортировать массив указателей, используя члены-указатели - PullRequest
1 голос
/ 05 апреля 2020

Новый студент CS нуждается в руководстве / помощи. Я пытаюсь отсортировать массив pRecordBook по классу, выбранному на стороне пользователя. Но почему-то при выполнении моего сравнения просто аннулируется или не берется.

clang 11.0.3 Xcode

#include <iostream>
#include <fstream>
#include <string>

const int MAX_RECORDS = 200;

class Record{ // Record Class with members
private:
    std::string id;
    std::string name;
    int quantity;
    double price;

public:
    Record();
    const std::string getID();
    const std::string getName();
    const double getPrice();
    const int getQuantity();
    void setID(std::string num);
    void setName(std::string input);
    void setQuantity(int quantity);
    void setPrice(double price);
    void setRecord(std::string id, std::string name, int quantity, double price);

    std::string displayRecord();
};

void readFile(Record recordBook[], Record *pRecordBook[], std::string file, int &count);
void displayArray(Record recordBook[], const int count);
void displayArray(Record *pRecordBook[], const int count);
void sortArray(Record *pRecordBook[], const int count, int selection);
std::string searchRecord(Record *pRecordBook[], const int count, std::string &input);
std::string searchRecord(Record *pRecordBook[], const int count, std::string &input);
void printReport(Record recordBook[], const int count);
void displayOptions(int &choice);

int main(int argc, const char * argv[]) {
    int selection = 0;
    int subSelection = 0;
    std::string inputID = "";
    std::string inputName = "";
    int count = 0;
    Record recordBook[MAX_RECORDS];
    Record *pRecordBook[MAX_RECORDS];
    std::string fileName = "testFile.txt";


    readFile(recordBook, pRecordBook, fileName, count);

    displayOptions(selection);

    while(selection != 0){
        switch(selection){
            case 1:
                std::cout << "\nPrinting Unsorted Inventory";
                displayArray(recordBook, count);
                break;
            case 2:
                std::cout << "\nSort By\n1. ID\n2. Name\n3. Quantity\n4. Price\nSelection: ";
                std::cin >> subSelection;
                while(subSelection < 1 || subSelection > 4){
                    std::cout << "\nPlease a selection from 1-4\nTry Again: ";
                    std::cin >> subSelection;
                }
                sortArray(pRecordBook, count, subSelection);
                displayArray(pRecordBook, count);
                break;
            case 3:
                std::cout << "\nSearch for item by:\n1. ID\n2. Name\nSelection: ";
                std::cin >> subSelection;
                if(subSelection > 2 || subSelection < 1){
                    std::cout << "\nPlease a selection of 1 or 2\nTry Again: ";
                    std::cin >> subSelection;
                }else{
                    if(subSelection == 1){
                        std::cout << "\nEnter ID to search for: ";
                        std::cin >> inputID;
                        searchRecord(pRecordBook, count, inputID);
                    }else{
                        std::cout << "\nEnter the Name to search for: ";
                        std::cin >> inputName;
                        searchRecord(pRecordBook, count, inputName);
                    }
                }
                break;
            case 4:
                printReport(recordBook, count);
                break;
            default:
                std::cout << "\nInvalid Option, Try Again\n";
                break;
        }
        displayOptions(selection);

    }
    if(selection == 0){
        std::cout << "\nTerminated Program. Goodbye\n";
    }

    return 0;
}

// Get Functions
const std::string Record::getID(){ return id;}
const std::string Record::getName(){ return name;}
const double Record::getPrice(){ return price;}
const int Record::getQuantity(){ return quantity;}

// Set Functions
void Record::setID(std::string num){
    this->id = num;
}
void Record::setName(std::string input){
    std::string name;
    for(char letter: input){
        name += toupper(letter);
    }
    this->name = name;
}
void Record::setQuantity(int quantity){
    this->quantity = quantity;
}
void Record::setPrice(double price){
    this->price = price;
}

// Contsructor for the initialization of "recordBook Array"
Record::Record(){
    id = "";
    name = "";
    quantity = NULL;
    price = NULL;
}

// Function to set the Entire class at once - Called in readFile function
void Record::setRecord(std::string id, std::string name, int quantity, double price){
    setID(id);
    setName(name);
    setQuantity(quantity);
    setPrice(price);
}

// Reads file, checks if correct file, checks if its empty, grabs values and stores them in class Record on the recordBook array
void readFile(Record recordBook[], Record *pRecordBook[], std::string fileName, int &count){
    std::ifstream inFile;
    std::ofstream outFile;

    inFile.open(fileName, std::ios::in);
    outFile.open("errorFile.txt", std::ios::out | std::ios::app);

    while(!inFile){
        std::cout << "\nError: Could Not Open File\nTry Again: ";
        std::cin >> fileName;
        inFile.open(fileName, std::ios::in);
    }
    while(inFile.peek() == EOF){// Checking if file is empty
        std::cout << "\nError: File is Empty\nTry Again: ";
        std::cin >> fileName;
        inFile.open(fileName, std::ios::in);
    }

    std::string id;
    std::string name;
    int quantity;
    double price;

    while(inFile >> id >> name >> quantity >> price && !(inFile.eof())){
        if(price == 0 || quantity == 0){
            outFile << id << " " << name << " " << quantity << " " << price << "\n";
        }else{
            recordBook[count].setRecord(id, name, quantity, price);
            pRecordBook[count] = &recordBook[count];
            count++;
            }
        if(count == MAX_RECORDS){
            std::cout << "\nProgram Storage Full. Stopping on line " << MAX_RECORDS << "\nUsing values grabbed. . . ";
            break;
        }
    };
    outFile.close();
    inFile.close();
}

std::string Record::displayRecord(){ // Function to display individual Record
    return this->id + " " + this->name + " " + std::to_string(this->quantity) + " " + std::to_string(this->price);
}

void displayArray(Record recordBook[], const int count){ // Function to display all Records in RecordArray
    for(int i = 0; i < count; i++){
        std::cout << "\nItem: " << (i+1) << " " << recordBook[i].displayRecord();
    }
    std::cout << "\n";
}

void displayArray(Record *pRecordBook[], const int count){ // Function display all Record in PointerArray
    for(int i = 0; i < count; i++){
        std::cout << "\n" << pRecordBook[i]->displayRecord();
    }
    std::cout << "\n";
}

Я работал задом наперед и даже подключил свой обычный массив, выбрал одно условие, жестко закодировал его в операторе if, - Boom Works

Затем я включил оператор switch , потому что думал, что break; в switch заставлял меня выгонять из своих вложенных циклов, убивая при этом функцию. - Нет работает

Когда я подключаю массив указателей, сравнение не удается. Есть ли актерский состав, которого я пропускаю или?

Спасибо за ваше время!

// Function to sort array depending on user selection
void sortArray(Record *pRecordBook[], const int count, int selection){

    bool toSwap;
    bool condition;
    Record *pTemp;

    for(int i = 0; i < count; i++){
        toSwap = false;
        for(int j = i + 1; j < count-i-1; j++){

            // Seems like our problem is the sorting is not being saved
            // Possibly grabbing the data incorrectly or might be the sorting itself that is wrong

                 switch(selection){
                    case 1:
                        condition = pRecordBook[j]->getID() < pRecordBook[i]->getID();
                        break;
                    case 2:
                        condition = pRecordBook[j]->getName() < pRecordBook[i]->getName();
                        break;
                    case 3:
                        condition = pRecordBook[j]->getQuantity() < pRecordBook[i]->getQuantity();
                        break;
                    case 4:
                        condition = pRecordBook[j]->getPrice() < pRecordBook[i]->getPrice();
                        break;
                    default:
                        std::cout << "\nError concurred - sorting bv default: Name";
                        condition = pRecordBook[j]->getName() < pRecordBook[i]->getName();
                        break;
                }

            if(condition){
                pTemp = pRecordBook[i];
                pRecordBook[i] = pRecordBook[j];
                pRecordBook[j] = pTemp;
                toSwap = true;
            }
        }
        if(toSwap == false)
            break;
    }
}

std::string searchRecord(Record *pRecordBook[], const int count, std::string id){ // Function searches for ID
    for(int i = 0; i < count; i++){
        if(id == pRecordBook[i]->getID())
            return "\nRecord Found at Index " + std::to_string(i) + ": " + pRecordBook[i]->displayRecord();
        }
    return "\nRecord Not Found!";

};


std::string searchRecord(Record *pRecordBook[], const int count, std::string &input){ // Function searches for Name
    for (int i = 0; i < count; i++) {
        if(input == pRecordBook[i]->getName()){
            return "\nRecord Found at Index " + std::to_string(i) + ": " + pRecordBook[i]->displayRecord();
        }
    }
    return "\nRecord Not Found!";
};


void printReport(Record recordBook[], const int count){ // Prints Inventory Report
    double totalValue = 0.0;

    for(int i = 0; i < count; i++)
        totalValue += recordBook[i].getPrice();

    std::cout << "Report:\nTotal Number of items: " << std::to_string(count) << "\nTotal worth of Inventory: $";
    std::cout << std::setprecision(2) << std::fixed << totalValue;
};

void displayOptions(int &choice){ // Displays Main Menu

    std::cout
    << "\n1: Print Inventory Unsorted"
    << "\n2: Sort in ascending order by any field"
    << "\n3: Search for an item by ID or name"
    << "\n4: Print Report with total count and worth of inventory"
    << "\nChoose an Option: ";
    std::cin >> choice;
}

1 Ответ

1 голос
/ 05 апреля 2020

Логотип сортировки c имеет недостатки!

Во-первых, проверка toSwap преждевременно завершит сортировку (в большинстве случаев). Например, как только i l oop запустится и не найдет значения, которое меньше текущего значения индекса i, поиск будет остановлен. Таким образом, в списке из 3 элементов с количеством (в несортированном списке) 1, 3 и 2, тогда toSwap будет false в конце первого l oop, но 3 и 2 все еще нужно поменять местами.

Итак, первое исправление: удалите

   if (toSwap == false)
       break;

и, таким образом, вы можете удалить переменную toSwap полностью !

Во-вторых, «тестовое» состояние вашего внутреннего (j) l oop действительно странно! Вы должны запускаться до конца списка каждый раз.

Итак, второе исправление: изменить

    for(int j = i + 1; j < count-i-1; j++){

на

    for(int j = i + 1; j < count; j++){

I проверили ваш код, с этими изменениями , на следующем входном файле, и, насколько я могу судить, он работает:

123 Cheese   5 12.30
212 Mutton   1 44.67
202 Chicken  3 12.78
363 Orange   5 6.22
327 Lemon   10 8.13
124 Butter   4  6.45

(я понятия не имею, что ваши фактические значения данных будут, конечно, поэтому я их придумала!)

РЕДАКТИРОВАТЬ: Возможно, новый вопрос, но есть также проблема с вашими опциями «Поиск элемента ...», так как компилятор не может правильно различить guish вызовы двух searchRecord функций. Два вызова:

searchRecord(pRecordBook, count, inputID);
searchRecord(pRecordBook, count, inputName);

имеют точно одного и того же профиля.

...