Каков наилучший способ сортировки динамического c массива c -строк в классе в c ++? - PullRequest
0 голосов
/ 17 февраля 2020

В моем текущем классе программирования мне было поручено создать программу, которая принимает вводимый пользователем курс (состоящий из имени курса, оценки курса, переменных единиц курса) и сохранять их в динамически генерируемом массиве с максимальным размером 10.

Из-за моего незнакомого отношения с объектно-ориентированным программированием и классами, я нахожу что-то, кроме создания классов, очень сложным. Я выяснил способ создания записей, а также как редактировать их после того, как они были созданы с использованием функций друзей (я думаю, это имя?), Хранящихся в заголовочном файле моих программ.

Однако теперь, когда мне нужно было выполнить сортировку данных (по имени переменной каждой записи), а также затем искать их, я нахожу это очень трудным для продолжения. Я понимаю, как создавать функции, которые могут выполнять обе эти вещи (как я делал это для моего предыдущего класса), но делать это с участвующими классами оказывается сложной задачей.

Мой заголовочный файл:

#ifndef COURSE_H
#define COURSE_H

#include <iostream>
#include <conio.h>
#include <stdio.h>
#include <cstdlib>
#include <vector>


class Course
{
private:
    char name[10] = ""; //name of course
    char grade; //grade in course
    int units; //units in course

public:
    Course()
    {
        name;
        grade;
        units;
    }

    void read() //Initializes course and collects information from user
    {
        std::cout << "\nEnter course name: ";
        std::cin.getline(name, 10, '\n');
        std::cout << "\nEnter number of units: ";
        std::cin >> units;
        std::cout << "\nEnter grade received: ";
        std::cin >> grade;
        std::cin.ignore();
    }

    void display() const //Displays course to user
    {
        std::cout << name << ' ' << units << ' ' << grade << std::endl;
    }

    ~Course() //Destructor frees allocated dynamic memory
    {
        std::cout << "\nDeleting any dynamically created object";
    }
};

#endif // COURSE_H

Мой основной исходный файл:

#include <iostream>
#include <conio.h>
#include <stdio.h>
#include <cstdlib>
#include <vector>
#include "courses.h"

int menu();
void add(Course* co_ptr[], int& size);
void edit(Course* co_ptr[], int size);
void swap_ptrs(Course*& pt1, Course*& pt2);

int main()
{
    Course* courses[10] = {};
    int selection;

    int size = 0;
    do
    {
        selection = menu();

        if (selection == 1)
        {
            if (size < 10)
                add(courses, size);
            else
                std::cout << "\nUnable to add more classes.";
        }
        else if (selection == 2)
        {
            edit(courses, size);
        }
        else if (selection == 3)
        {

        }
        else if (selection == 4)
        {

        }
        else if (selection == 5)
        {

        }
        else if (selection == 6)
        {

        }
        else if (selection == 7)
        {
            break;
        }
        else
        {
            std::cout << "\nInvalid selection.";
        }
    } while (selection != 7);

    std::cout << "\nPress any key to exit.";
    (void)_getch();
    return 0;
}

Исходный файл моих функций:

#include <iostream>
#include <conio.h>
#include <stdio.h>
#include <cstdlib>
#include <vector>
#include "courses.h"

int menu()
{
    int selection;

    std::cout << "\nSelect one of the following actions: " << std::endl
        << "1. Add new course" << std::endl
        << "2. Edit an existing course" << std::endl
        << "3. Display a course" << std::endl
        << "4. List all courses" << std::endl
        << "5. Display GPA" << std::endl
        << "6. Delete all courses" << std::endl
        << "7. Quit";
    std::cout << "\nEnter selection number: ";
    std::cin >> selection;
    std::cin.ignore();

    return selection;
}

void add(Course* co_ptr[], int& size)
{
    co_ptr[size] = new Course;
    co_ptr[size]->read();
    size++;
}

void edit(Course* co_ptr[], int size)
{
    int selection;
    for (int i = 0; i < size; i++)
    {
        std::cout << std::endl << i << ". ";
        co_ptr[i]->display();
    }

    std::cout << "Enter your selection: ";
    std::cin >> selection;
    std::cin.ignore();

    co_ptr[selection]->read();
}

Моя последняя попытка создания функции сортировки (я пытался создать ее в заголовке поскольку всякий раз, когда я переносил свой старый сортировочный код как обычную функцию, он не мог получить доступ к необходимым данным из-за того, что эти переменные были «приватными»)

void Course::sort_name(Course* co_ptr[], int size) //has to be apart of the class (Course::) to have access to the name data
{
    bool swap;

    do
    {
        swap = false;
        for (int i = 0; i < size - 1; i++)
        {
            if (strcmp(co_ptr[i]->name, co_ptr[i + 1]->name) > 0) //We're now comparing and swapping pointers
            {
                swap_ptrs(co_ptr[i], co_ptr[i + 1]);
                swap = true;
            }
        }
    } while (swap);
}

Наконец, моя функция swap_ptrs, которая также была в Исходный файл функции:

void swap_ptrs(Course*& pt1, Course*& pt2) //Passes the pointers by reference
{
    Course* tmp = pt1;
    pt1 = pt2;
    pt2 = tmp;
}

Извините за такой длинный пост, но этот проект был настоящей борьбой, и я чувствую, что не продвигаюсь вперед.

Ответы [ 3 ]

2 голосов
/ 17 февраля 2020

Не используйте массив символов. Вместо этого используйте строку

char name[10]; //bad form

Вместо этого используйте

std::string name;

, приходящий к исходному запросу, если вы создаете vector of Course, например

std::vector<Course> mycourselist;

, тогда все, что вам нужно сделать это

std::sort(mycourselist.begin(),mycourselist.end(), mysortfunc);

, поэтому вам нужно написать свою собственную функцию сравнения, чтобы делать то, что вы хотите.

, чтобы вы могли сделать

   bool mysortfunc(Course c1, Course c2)
   {
    return c1.name<c2.name;
   } 

Узнайте больше о это здесь

1 голос
/ 17 февраля 2020

Для сортировки можно использовать std :: sort () .

Конечно, есть еще что-то необходимое - меньший предикат, обеспечивающий предполагаемый порядок - Course* отсортировано по name элементам.

Такой предикат может быть:

auto lessCourse
    = [](const Course *pCourse1, const Course *pCourse2)
    {
      return strcmp(pCourse1->getName(), pCourse2->getName()) < 0;
    };

, который является лямбда-выражением (и может быть предоставлен в качестве третьего аргумента std::sort() напрямую).

(Функция с такой же сигнатурой тоже подойдет.)

Небольшая демонстрация для иллюстрации:

#include <iostream>
#include <cstring>
#include <algorithm>

class Course {
  private:
    char name[10] = ""; //name of course
    char grade; //grade in course
    int units; //units in course

  public:
    explicit Course(const char *name = "", char grade = ' ', int units = 0):
      grade(grade), units(units)
    {
      strncpy(this->name, name, 9);
      this->name[9] = '\0';
    }

    ~Course() = default;
    Course(const Course&) = delete;
    Course& operator=(const Course&) = delete;

    const char* getName() const { return name; }
};

void add(
  Course *pCourses[], unsigned &n,
  const char *name = "", char grade = ' ', int units = 0)
{
  pCourses[n++] = new Course(name, grade, units);
}

int main()
{
  Course *pCourses[10];
  unsigned nCourses = 0;
  // make sample
  add(pCourses, nCourses, "Peter");
  add(pCourses, nCourses, "Carla");
  add(pCourses, nCourses, "Anna");
  add(pCourses, nCourses, "Dieter");
  add(pCourses, nCourses, "Berta");
  // sort sample
  // make a less predicate to compare Course instances by name
  auto lessCourse
    = [](const Course *pCourse1, const Course *pCourse2)
    {
      return strcmp(pCourse1->getName(), pCourse2->getName()) < 0;
    };
  // use std::sort() with that less predicate
  std::sort(pCourses, pCourses + nCourses, lessCourse);
  // output
  for (unsigned i = 0; i < nCourses; ++i) {
    const Course *pCourse = pCourses[i];
    std::cout
      << pCourse->getName() << ", "
      << pCourse->getName() << ", oh "
      << pCourse->getName() << ".\n";
  }
}

Вывод:

Anna, Anna, oh Anna.
Berta, Berta, oh Berta.
Carla, Carla, oh Carla.
Dieter, Dieter, oh Dieter.
Peter, Peter, oh Peter.

Live Demo на coliru

Общая информация:

Что касается необычного формата вывода, я использовал:

Trio - Анна - Лассмихрейн Лассмихраус

1 голос
/ 17 февраля 2020

Вы можете использовать контейнер типа std :: list или std :: vector для хранения ваших объектов курса вместо массива и использовать std :: sort с выбранным вами методом сравнения. Это, вероятно, будет самым простым. Если вам нужно использовать массивы в качестве контейнера, вы также можете использовать сортировку следующим образом:

std::sort(array, array + array_size,[](Course* a, Course* b) {
        return strcmp(a->name, b->name) < 0;   
    });

Но это больше похоже на C, чем на C ++ ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...