• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Funkcja zwracająca najlepszą grupę studentów na podstawie mediany ich średnich

Object Storage Arubacloud
0 głosów
215 wizyt
pytanie zadane 22 grudnia 2021 w C i C++ przez MKolaj15 Bywalec (2,270 p.)

Witam, mam napisaną strukturę Student przechowującą informacje o studentach oraz strukturę Group, która posiada pola nazwa i studenci w postaci vector'a obiektów typu student. Mam także napisane funkcję wyliczającą średnią ocen studenta oraz funkcję dodającą studenta do grupy. Moim następnym zadaniem jest napisanie funkcji best_groups_name(), która będzie zwracała nazwę najlepszej grupy, czyli takiej, której mediana średnich ocen wszystkich studentów jest najwyższa. Przy próbie uruchomienia mojego kodu, wyświetla mi następującą informację:

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_M_construct null not valid
Aborted (core dumped)

Mój kod:

#include <iostream>
#include <string>
#include <vector>

struct Student
{
        std::string imie;
        std::string nazwisko;
        std::vector<int> oceny;
         
        Student(std::string im, std::string naz, std::vector<int> o)
        {
                imie = im;
                nazwisko = naz;
                oceny = o;
        }

};

auto average_of(Student a) -> float
{
        int x = 0;
        for(size_t i = 0; i < a.oceny.size(); i++)
        {
                 x = x + a.oceny[i];
        }

        return float(x)/float(a.oceny.size());
}

struct Group
{
        std::string nazwa;
        std::vector<Student> studenci;

        Group(std::string naz, std::vector<Student> s)
        {
                nazwa = naz;
                studenci = s;
        }


};

void add_to_group(Group& g, Student const& st)
{
        g.studenci.push_back(st);
}

auto best_groups_name(std::vector<Group> gr) -> Group
{
        auto tmp = average_of(gr[0].studenci[0]);
        auto best = gr[0];
        for(size_t i = 0; i < gr.size(); i++)
        {
                if(gr[i].studenci.size() % 2 == 0)        // jeśli ilość studentów jest parzysta porównaj sumę średnich dwóch studentów w środku do tmp
                {
                        if(average_of(gr[i].studenci[gr[i].studenci.size()/2-1]) + average_of(gr[i].studenci[gr[i].studenci.size()/2+1]) > tmp)
                        {
                                tmp = average_of(gr[i].studenci[gr[i].studenci.size()/2-1]) + average_of(gr[i].studenci[gr[i].studenci.size()/2+1]); 
                                best = gr[i];
                        }
                }
                else                 // jeśli ilość studentów w grupie nie jest parzysta porównaj średnią ocen środkowego studenta z tmp
                {
                        if(average_of(gr[i].studenci[gr[i].studenci.size()/2]) > tmp)
                        {
                               tmp = average_of(gr[i].studenci[gr[i].studenci.size()/2]);
                                best = gr[i];
                        }
                }

        }

        return best;
}

auto main() -> int
{
        auto Stasiek = Student("Stasiek", "Kowalski", {3,4,5,5});
        auto Grzesiek = Student("Grzesiek", "Nowak", {6,6,4,5});
        auto c = Group("c", {});

        add_to_group(c, Stasiek);
        add_to_group(c, Grzesiek);

        auto Mikolaj = Student("Mikolaj", "Kowalski", {2,1,5,5});
        auto Kuba = Student("Kuba", "Nowak", {6,6,4,5,4,4});
        auto Piotr = Student("Piotr", "Nowak", {2,2,1,5,4,4});
        auto b = Group("b", {});

        add_to_group(b, Mikolaj);
        add_to_group(b, Kuba);
        add_to_group(b, Piotr);

        auto vec = std::vector<Group>{c,b};
        auto najgrupa = best_groups_name(vec);
        std::cout<<najgrupa.nazwa<<std::endl;

return 0;
}

Czy ktoś byłby w stanie pomóc w poprawie tego kod? Z góry dzięki!

 

Edit: Przypomniało mi się, że aby obliczyć medianę należy jeszcze posortować wartości rosnąco laugh, ale szczerze i tak nie wiem jak to zaimplementować do kodu.

komentarz 22 grudnia 2021 przez j23 Mędrzec (194,920 p.)
auto best_groups_name(std::vector<Group> gr) -> Group
{
        auto tmp = average_of(gr[0].studenci[0]);
        auto best = gr[0];
...

Średnio to bezpieczne, bo zakłada, że gr zawiera przynajmniej jedną grupę z przynajmniej jednym studentem. Tak lepiej:

Group best_groups_name(const std::vector<Group> &gr)
{
	if(gr.empty() || gr[0].studenci.empty()) return {}; // IMO lepiej, by typem zwracanym było std::optional<Group>
	
	auto tmp = average_of(gr[0].studenci[0]);
	auto best = gr[0];
	...

Przekazuj klasy/struktury przez const referencję.

Do sortowania użyj funkcji std::sort.

komentarz 23 grudnia 2021 przez MKolaj15 Bywalec (2,270 p.)

Cześć, przerobiłem trochę moją funkcję i wygląda teraz tak:

auto best_groups_name(const std::vector<Group> &gr) -> Group
{
        auto brak = Group("brak grupy lub studentow", {});

        if(gr.empty() || gr[0].studenci.empty()) return brak;

        auto tmp = average_of(gr[0].studenci[0]);
        auto best = gr[0];
        std::vector<float> sr;
        for(size_t i = 0; i < gr.size(); i++)
        {
                for(size_t j = 0; j < gr[i].studenci.size(); j++)
                {
                        sr[j] = average_of(gr[i].studenci[j]);
                }

                std::sort(sr.begin(), sr.end());

                if(gr[i].studenci.size() % 2 == 0)
                {
                        if(sr[sr.size()/2 - 1] + sr[sr.size()/2 + 1] > tmp)
                        {
                                tmp = sr[sr.size()/2 - 1] + sr[sr.size()/2 + 1]; 
                                best = gr[i];
                        }
                }
                else
                {
                        if(sr[sr.size()/2] > tmp)
                        {
                                tmp = sr[sr.size()/2];
                                best = gr[i];
                        }
                }

        }

        return best;
}

Pomyślałem, że dobrze będzie utworzyć oddzielny vector, który będzie przechowywał średnie oceny studentów danej grupy i dopiero potem posortować właśnie niego. Niestety przy próbie uruchomienia wyrzuca: Segmentation fault (core dumped)

1
komentarz 23 grudnia 2021 przez j23 Mędrzec (194,920 p.)

Zamiast:

sr[j] = average_of(gr[i].studenci[j]);

daj:

sr.push_back(average_of(gr[i].studenci[j]));

albo jeszcze lepiej zredukuj pętlę do:

for(auto &s : gr[i].studenci) {
        sr.push_back(average_of(s));
}

Definicję sr przenieś do wnętrza pierwszej pętli.


auto brak = Group("brak grupy lub studentow", {});

IMO nadużywasz auto. Można tak przecież:

Group brak("brak grupy lub studentow", {});

// lub jak lubisz klamry
Group brak{"brak grupy lub studentow", {}};

 

komentarz 23 grudnia 2021 przez MKolaj15 Bywalec (2,270 p.)
Dziękuję, bardzo mi pomogłeś, teraz wszystko działa :D
komentarz 23 grudnia 2021 przez MKolaj15 Bywalec (2,270 p.)

Notka dla innych poprawne warunki wyliczania mediany powinny wyglądać tak:

if(gr[i].studenci.size() % 2 == 0)
                {
                        if((sr[sr.size()/2 - 1] + sr[sr.size()/2]) / 2 > tmp)
                        {
                                tmp = (sr[sr.size()/2] + sr[sr.size()/2]) / 2; 
                                best = gr[i];
                        }
                }
                else
                {
                        if(sr[(sr.size() - 1) / 2] > tmp)
                        {
                                tmp = sr[(sr.size() - 1) / 2];
                                best = gr[i];
                        }
                }

jeśli się nie mylę laugh

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

0 głosów
0 odpowiedzi 422 wizyt
pytanie zadane 31 października 2021 w C i C++ przez MKolaj15 Bywalec (2,270 p.)
0 głosów
0 odpowiedzi 300 wizyt
+1 głos
2 odpowiedzi 588 wizyt

92,575 zapytań

141,424 odpowiedzi

319,649 komentarzy

61,960 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...