Behöver hjälp med c++ klasser, linsökningar och Bubblesort.

Permalänk
Medlem

Behöver hjälp med c++ klasser, linsökningar och Bubblesort.

Så vad jag behöver hjälp med är en inlämning jag fått. Den ser ut såhär i sin helhet:
Skapa en klass Person som innehåller två attribut:
string namn int alder
som lagrar personens namn och ålder, samt metoden
void SkrivUt()
som skriver ut innehållet i variablerna namn och alder på skärmen.
Skriv en funktion för linjär sökning i en vektor p med Person-objekt.
int linsok(Person p[], int n, int a)
Funktionen ska söka igenom vektorn p efter en person med åldern a och returnera index för den personen. Om ingen person hittas returneras -1. Variabeln n är antalet element i vektorn.
Skriv också en funktion som sorterar en Person-vektor efter ålder (yngst först).
void bubblesort(Person p[], int n)
Se pseudokoden för bubblesort och exempel 15.3 på sidan134 i kursboken. För att förenkla kodningen lite grann, använd gärna nedanstående funktion för att byta plats på två element

void byt(Person &p, Person &q)
{ Person temp;
temp.namn = p.namn;
temp.alder = p.alder;
p.namn = q.namn;
p.alder = q.alder;
q.namn = temp.namn;
q.alder = temp.alder; }

Har suttit en bra stund och fått ihop detta. Försökt googla och hitta hur man ska göra men jag har fastnat. Såhär ser min kod ut nu:

#include <iostream> #include <string> #include <vector> using namespace std; class Person { private: string name; int age; public: void Print() { cout << "Personen heter " << name << " och \x84r " << age << " \x86r gammal" << endl; } string get_name() { return name; } void set_name(string set) { name = set; } int get_age() { return age; } void set_age(int set) { age = set; } }; int linesearch (Person p[], int n, int a) { int i = 0; for (i = 0; i < n; i++) { if (p[i].get_age() == a) return i; } return -i; }; void bubblesort(Person p[], int n) { for (int i = 0; i < n; i++) { int nrLeft = n-i; for (int j = 0; j < nrLeft; j++) { if (p[j].get_age() > p[j+1].get_age()) { Person temp = p[j]; p[j] = p[j+1]; p[j+1] = temp; } } } }; int main() { int age=0; Person familj[4]; Person pers1; Person pers2; Person pers3; Person pers4; pers1.set_age(19); pers1.set_name("Niklas"); pers2.set_age(58); pers2.set_name("Hasse"); pers3.set_age(5); pers3.set_name("Lasse"); pers4.set_age(33); pers4.set_name("Liselott"); familj[0] = pers1; familj[1] = pers2; familj[2] = pers3; familj[3] = pers4; bubblesort(familj,4); { cout << familj << endl; cout << "Ange en \x86lder " << endl; cin >> age; } }

Just nu så får jag ingen error. Jag har inte kallat på linesearchen ännu för jag ville först se om min bubblesort sorterade något. Hade först "print" mellan pers1 2 3 4 etc, därför är det mellanrum. Om jag kör programmet såhär, så får jag upp "0x6efe0c" och sedan "ange en ålder" som jag har längst ner med. Bubblesorten vill alltså inte sortera. Jag har försökt gå efter hur boken gjort, den har iförsig inte gjort något med en funktion.

Men jag vet verkligen inte hur jag ska fortsätta. Och jag lyckas inte få tag i någon mer information. Om någon har lite hjälp att erbjuda så jätte gärna. Vet att den inte är perfekt, är en nybörjare på detta och försöker så gott jag kan. Så behöver hjälp med att få min bubblesort att fungera, sedan hur man korrekt kallar på den och sen kalla på linesearchen.

Vill även tillägga att om jag lägger tillbaks print under varje person, så kommer inte det där "0x6efe0c" upp. Och den verkar skippa "cin" längst ner med, för klickar jag något stängs det ner.

Permalänk
99:e percentilen

Använd [code][/code] när du postar kod, så blir den lättare att läsa.

Visa signatur

Skrivet med hjälp av Better SweClockers

Permalänk
Medlem

familj är en array så cout på den gör nog inte vad du vill. du kanske hellre vill skriva ut objekten i arrayen var och ett för sig för att se vilken ordning de ligger i?

Permalänk
Medlem

Jag antar att ni inte gått igenom pekare ännu, men familj kommer i alla fall hanteras som en pekare i din utskrift, d.v.s. när du endast skriver familj utan något index så hanteras variabeln i många fall som om den har typen Person* istället för Person[4]. Och när man skriver ut värdet på en pekare så är det addressen som pekaren pekar på som skrivs ut, d.v.s. 0x6efe0c är minnesaddressen (0x betyder hexadecimalt format) som arrayen familj börjar på.

Permalänk
Medlem

@helmet: Om jag inte kan använda mig av cout för att skriva ut. Hur kan jag gå tillväga då?

Permalänk
Medlem
Skrivet av Freemind:

Om jag inte kan använda mig av cout för att skriva ut. Hur kan jag gå tillväga då?

Loopa igenom arrayen och skriv ut ett element i taget.

Permalänk
Medlem

@perost: Det har nämnts. Men mestadels så nämns en grej och så säger dom "vi går inte in mer på det." Så man lämnas i mörkret oftast.

Permalänk
Medlem

Vet inte hur jag ska göra exakt. Försöker jag med en loop, så får jag error som tex "Error: no match for operator."

Även flera rader med "note candidate std basic_ostream_chart_traits" osv. och "no known conversion for argument 1 from Person to 'long int'

Permalänk
Medlem

@perost: Får inte en loop att fungera. Kanske göra fel men försökte med en "for loop" under bubblesorten men fick de felmeddelande som nämnts innan. Men tänkte ifall det går att skriva "cout << get_age[0]" för varje position i vektorn. För att se om bubblesorten har sorterat åldrarna.

Permalänk
Medlem

@Freemind: cout vet inte hur man skriver ut en Person-instans. Du måste använda Print-metoden som du definierat i Person, eller använda get_name och get_age för att skriva ut med något annat format. Syntaxen är då t.ex. familj[0].get_age().

Permalänk
Medlem

Här är ett exempel på lösning. Lite snabbt/hafsigt kodat. Verkar funka... Inga fel/varningar i g++ och korrekt utmatning. Du bör utgå från att din lärare ser detta. Så du bör skriva om från scratch, men detta kan ge viss ledning. Säg till om det är något du undrar över i koden.

Edit: Att ordet vektor används i uppgiften istället för vector tolkar jag som att det som avses är en normal array och inte en vector. Att n anger storlek samt kodfragment tycks bekräfta detta.

p.cpp:

#include <iostream> #include <string> using namespace std; class Person { public: string namn; int alder; Person(void) { namn = ""; alder = 0; }; Person(const string n, int a) { namn = n; alder = a; }; Person(const char *n, int a) { namn = string(n); alder = a; }; Person(const Person &p) { namn = p.namn; alder = p.alder; }; void SkrivUt(void) { cout << namn << " " << alder << "\n"; }; }; void byt(Person &p, Person &q) { Person temp; temp.namn = p.namn; temp.alder = p.alder; p.namn = q.namn; p.alder = q.alder; q.namn = temp.namn; q.alder = temp.alder; } int linsok(Person p[], int n, int a) { for (int i = 0; i != n; i++) if(p[i].alder == a) return i; return -1; // ej funnen } // Se https://en.wikipedia.org/wiki/Bubble_sort void bubblesort(Person p[], int n) { bool swapped; do { swapped = false;; for (int i = 1; i < n; i++) { if(p[i - 1].alder > p[i].alder) { byt(p[i-1], p[i]); swapped = true; } } --n; } while(swapped); } void test_linsok(Person p[], int n, int a) { int resultat = linsok(p, n, a); if(resultat == -1) cout << "Ingen person med ålder " << a << " år funnen!\n"; else { cout << "Person med ålder " << a << " år funnen: "; p[resultat].SkrivUt(); } } void test_bubblesort(Person p[], int n) { cout << "\nFöre sortering:\n"; for(int i = 0; i != n; i++) p[i].SkrivUt(); bubblesort(p, n); cout << "\nEfter sortering:\n"; for(int i = 0; i != n; i++) p[i].SkrivUt(); } int main(void) { Person p[4]; p[0] = Person("Kalle", 23); p[1] = Person("Eva", 21); p[2] = Person("Nisse", 43); p[3] = Person("Lisa", 18); test_linsok(p, 4, 23); // Bör finna Kalle test_linsok(p, 4, 21); // Bör finna Eva test_linsok(p, 4, 11); test_linsok(p, 4, 99); test_linsok(p, 4, 18); // Bör finna Lisa test_bubblesort(p, 4); }

Kompilera och exekvera: (Linux)

g++ -o p p.cpp ./p

Utmatning:

Person med ålder 23 år funnen: Kalle 23 Person med ålder 21 år funnen: Eva 21 Ingen person med ålder 11 år funnen! Ingen person med ålder 99 år funnen! Person med ålder 18 år funnen: Lisa 18 Före sortering: Kalle 23 Eva 21 Nisse 43 Lisa 18 Efter sortering: Lisa 18 Eva 21 Kalle 23 Nisse 43

Visa signatur

Linux och Android

Permalänk

Posten är inte helt ny, men kan svara i vilket fall och komma med lite tips på förbättringar...

Skrivet av Adoby:

Edit: Att ordet vektor används i uppgiften istället för vector tolkar jag som att det som avses är en normal array och inte en vector. Att n anger storlek samt kodfragment tycks bekräfta detta.

Antagligen, fast jag tycker ändå man gott kan använda std::vector eftersom det är mer C++ att använda inbyggda containrar. Att använda C-arrayer är ju just precis C. Det borde åtminstone inte vara fel kan man tycka.

#include <iostream> #include <string> using namespace std; class Person { public: string namn; int alder; Person(void) { namn = ""; alder = 0; }; Person(const string n, int a) { namn = n; alder = a; }; Person(const char *n, int a) { namn = string(n); alder = a; }; Person(const Person &p) { namn = p.namn; alder = p.alder; }; void SkrivUt(void) { cout << namn << " " << alder << "\n"; }; };

Mycket bättre att initiera med konstruktorer som du gör än som TS gjorde, då lösa objekt utan data är rätt bad i många fall. Men nu är den ju inte inkapslad längre istället, medlemmarna borde vara privata och ha getters.

Konstruktorn som initierar deras värden är onödig också eftersom defaultkonstruktorn fungerar fint för det ändamålet. Person() = default skulle kunna användas om den nu behövs överhuvudtaget.

Kör const-ref på strängen när den skickas in som argument.

Använd initieringslista istället för att sätta värdena i kroppen av konstruktorn.

void byt(Person &p, Person &q) { Person temp; temp.namn = p.namn; temp.alder = p.alder; p.namn = q.namn; p.alder = q.alder; q.namn = temp.namn; q.alder = temp.alder; }

Här skulle man kunna överlagra operator= för Person-objekt istället för tydlighet och bara assigna dem istället för att anropa en särskild funktion. Men eftersom den är så trivial borde en std::swap duga.

void test_linsok(Person p[], int n, int a) { int resultat = linsok(p, n, a); if(resultat == -1) cout << "Ingen person med ålder " << a << " år funnen!\n"; else { cout << "Person med ålder " << a << " år funnen: "; p[resultat].SkrivUt(); } } void test_bubblesort(Person p[], int n) { cout << "\nFöre sortering:\n"; for(int i = 0; i != n; i++) p[i].SkrivUt(); bubblesort(p, n); cout << "\nEfter sortering:\n"; for(int i = 0; i != n; i++) p[i].SkrivUt(); }

Istället för att lägga printar i en funktion när man testar en metod/funktion för att tvingas kolla och verifiera resultatet, låt kompilatorn lösa ut det åt er istället. Gör ett riktigt unittest av det det vill säga med väntat resultat utifrån indata. Det blir mer cleant och tydligt då också eftersom funktionerna inte har sidoeffekter.

Exempel på hur dessa tester kan se ut i main sedan:
assert(test_linsok(p, 4, 23) == "kalle");
assert(test_linsok(p, 4, 21) == "eva");

Permalänk
Medlem

@Ståupptuppen: Bra synpunkter. Jag skrev att min kod var lite hafsig. Det var länge sedan jag lärde mig C++.

När jag pluggade C++ gjorde jag som träning/lathund en gång en ganska minimal "mall" med några klassdeklarationer/definitioner som visade enkla exempel på användning av abstrakt basklass, kombinerat olika typer av arv, typisk lista på medlemsfunktioner för konstruktion, destruktion, kopiering, jämförelse, operatorer och åtkomst. Och som visade alla rekommenderade varianter av defaults, const, referenser, initiering, parameterlistor och inline eller externa definitioner. Sådant som kompilatorn kan göra med automatik utkommenterat. Och så vidare. Tyvärr hittar jag inte min lathund längre. Och säkert vore den inte helt aktuell idag heller...

En detalj är att jag vill minnas att metoder/konstruktorer som kan tänkas används i uttryck/definitioner/beräkningar skall returnera referenser till sig själva. Och andra sådana knep för att göra en "komplett" klass.

Du råkar inte ha, eller skulle vilja skapa, en sådan lathund? Aktuell för dagens C++. Skulle nog också kunna vara till nytta för de som läser C++ idag.

Sedan började jag göra om den för användning som behållare med algoritmer, iteratorer, referensräknare och templates, men den gjorde jag aldrig färdig...

Visa signatur

Linux och Android

Permalänk
Skrivet av Adoby:

Tyvärr hittar jag inte min lathund längre. Och säkert vore den inte helt aktuell idag heller...

Jag vågar inte säga med säkerhet hur relevant olika saker är idag då jag började för ungefär 1 år sedan igen där jag innan bara hade rört vid C++98. Men jag tror att det mesta är relevant ännu idag. Språket är ju uppstädat så att säga och har mycket nytt som man bör använda, men jag tror det mesta ändå är relevant fortfarande.

Börjar man idag bör man ju åtminstone köra på C++11 iallafall. Saker som lambdas, automatisk type deduction, move semantics och så vidare introducerades. Det är som ett helt nytt språk.

Citat:

En detalj är att jag vill minnas att metoder/konstruktorer som kan tänkas används i uttryck/definitioner/beräkningar skall returnera referenser till sig själva. Och andra sådana knep för att göra en "komplett" klass.

Det låter som att det är på grund av att man ska kunna kedja uttrycken. Exempelvis om B ska vara beroende av resultatet av A så kan man skriva foo.A().B().C()...

Citat:

Du råkar inte ha, eller skulle vilja skapa, en sådan lathund? Aktuell för dagens C++. Skulle nog också kunna vara till nytta för de som läser C++ idag.

Det borde finnas några former av lathundar på det redan kan jag tro, fast jag tror att C++ är så komplext att det mer blir som en stor guide ändå. Men eftersom vi talar om specifikt klasser så finns det ju "Rule of zero", vilket är en ganska omfattande och viktig sak.