首页 > 解决方案 > 如何在具有动态内存分配的结构中按 cgpa 的降序对数据进行排序?

问题描述

结构和DMA。我想按 cgpa 的降序检索所有插入的记录。不排序它会给出如下图所示的结果。

图片

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

struct student {
    string name;
    int age;
    float cgpa;
};
void main()
{
    student *ptr;
    int size;
    cout << "enter size \n";
    cin >> size;
    ptr = new student[size];
    for (int i = 0; i < size; i++)
    {
        cout << "enter student " << i + 1 << " name\n";
        cin >> ptr[i].name;
        cout << "enter student " << i + 1 << " age\n";
        cin >> ptr[i].age;
        cout << "enter student " << i + 1 << " cgpa\n";
        cin >> ptr[i].cgpa;
    }
    cout << "with out sorting \n";
    for (int i = 0; i < size; i++)
    {
        cout << " NAME\tAGE\tCGPA\n";
        cout << ptr[i].name << "\t" << ptr[i].age << "\t" << ptr[i].cgpa << endl;
    }
    system("pause");
}


  [1]: https://i.stack.imgur.com/whP8d.png

标签: c++visual-studio-2015

解决方案


“没有排序”有点不清楚,但我认为这意味着您不能std::sort直接调用或使用另一个显式排序例程。这使您可以选择一个容器,该容器根据您提供的比较函数(或重载)按排序顺序存储对象。查看 VS2015的Microsoft C++ 语言一致性表,它显示了支持的 C++11 的所有核心语言功能——其中包括std::set

std::set允许您存储一组排序的唯一对象。这意味着您可以接受输入并将结果存储在std::set您提供的基于比较功能中。提供将比较cgpa每个学生的比较功能,然后将自动存储您的student对象cgpa

要使其std::set可用,您只需#include<set>. 编写可用于存储学生的比较函数cgpa只需要为运算符提供一个重载,该<运算符将两个student对象作为参数,然后true在第一个参数排序在第二个之前返回,false否则。这可以很简单:

/* overload of < comparing student by cgpa */
bool operator <(const student& a, const student& b) {
    return a.cgpa < b.cgpa;
}

注意:除非您正在为没有操作系统的微控制器或嵌入式系统(称为独立环境)进行编译,否则void main()是错误的。符合标准的调用main()isint main(void)int main (int argc, char **argv)whereargc参数计数参数向量argv(技术上是指向以空字符结尾的字符串的指针数组,其中最后一个参数之后的下一个指针设置为标记)还有其他非标准扩展由一些编译器添加,例如提供指向每个环境变量的指针。NULLchar **envp

要声明您的集合,student您需要提供student将学生插入集合时要使用的类型和比较函数。由于您为小于运算符提供重载,因此您可以使用std::less<>提供一个模板参数,例如

int main(void)
{
    /* create std::set of students using std::less for compare */
    std::set<student, std::less<const student&>> students {};

而且由于您使用的是为您提供自动内存管理的容器,因此无需size事先知道(或要输入的学生人数)。您可以根据需要简单地输入任意数量的学生,然后Ctrl+d在 Linux 或Ctrl+zWindows 上按下以生成EOF表示您输入结束的手册。但是,您确实需要通过检查每个输入之后的返回(流状态)来验证每个用户输入。至少你可以使用:

        std::cout << "enter student " << i + 1 << " name\n";
        if (!(std::cin >> s.name))  /*  validate all input, ctrl + z to end input */
            break;

注意:该变量i只需要在提示输入时显示学生编号,所有容器都提供.size()成员函数,告诉您其中包含多少对象。)

完成输入后,您可以使用基于范围的 for 循环来迭代您的集合中的每个学生,以输出所需的信息。例如:

    std::cout << "\nwith out sorting \n";
    for (auto& s : students) {      /* output in order of cgpa w/o sorting */
        std::cout << " NAME\tAGE\tCGPA\n"
                    << s.name << "\t" << s.age << "\t" << s.cgpa << '\n';
    }

总而言之,你可以这样做:

#include <iostream>
#include <string>
#include <set>

struct student {            /* struct student */
    std::string name;
    int age;
    float cgpa;
};

/* overload of < comparing student by cgpa */
bool operator <(const student& a, const student& b) {
    return a.cgpa < b.cgpa;
}

int main(void)
{
    /* create std::set of students using std::less for compare */
    std::set<student, std::less<const student&>> students {};
    
    for (int i = 0; ; i++) {
        student s {};       /* temporary struct to add to set */
        std::cout << "enter student " << i + 1 << " name\n";
        if (!(std::cin >> s.name))  /*  validate all input, ctrl + z to end input */
            break;
        std::cout << "enter student " << i + 1 << " age\n";
        if (!(std::cin >> s.age))
            break;
        std::cout << "enter student " << i + 1 << " cgpa\n";
        if (!(std::cin >> s.cgpa))
            break;
        students.insert(s); /* insert student in set */
    }
    std::cout << "\nwith out sorting \n";
    for (auto& s : students) {      /* output in order of cgpa w/o sorting */
        std::cout << " NAME\tAGE\tCGPA\n"
                    << s.name << "\t" << s.age << "\t" << s.cgpa << '\n';
    }
}

注意:看看为什么“使用命名空间标准;”被认为是不好的做法?。尽早养成好习惯比以后尝试改掉坏习惯要容易得多......)

注 2:您可能会考虑使用getline(std::cin, s.name)输入学生姓名,以便您可以处理带有空格的名称Firstname Lastname,例如Mickey Mouse,由您决定)

重新添加system("pause");以根据需要保持终端窗口打开。

示例使用/输出

现在只需输入尽可能多的学生的学生数据,然后通过生成EOF如上所述的手册来终止输入,例如

$ ./bin/set_student_grades
enter student 1 name
gates
enter student 1 age
20
enter student 1 cgpa
2.12
enter student 2 name
della
enter student 2 age
21
enter student 2 cgpa
2.00
enter student 3 name
jim
enter student 3 age
30
enter student 3 cgpa
3.12
enter student 4 name

with out sorting
 NAME   AGE     CGPA
della   21      2
 NAME   AGE     CGPA
gates   20      2.12
 NAME   AGE     CGPA
jim     30      3.12

这提供了一种按顺序存储和提供学生数据的方法,cgpa而无需显式sort. 当然std::set可以,但如果避免显式排序是您的程序的意图,那么这是一个非常好的选择。如果您还有其他问题,请告诉我。


推荐阅读