I wrote a program which shows the data about 5 students I want to know how to show the student name registration number and marks who obtained highest marks in the array.
The program is like that:
#include "stdio.h"
#include "conio.h"
struct student
{
char name[30];
char reg[10];
short int marks_dbms;
short int marks_prog;
};
void main()
{
short int i;
student a[5]={
{"salman","B-1499",92,98},
{"Haider","B-1489",34,87},
{"zeeshan","B-1897",87,90},
{"faizan","B-1237",56,66},
{"Asif","B-1233",88,83}
};
for(i=0; i<5; i++)
{
printf("%s\t",a[i].name);
printf("%s\t",a[i].reg);
printf("%d\t",a[i].marks_dbms);
printf("%d\t\n",a[i].marks_prog);
}
getch();
}
Thats a simple one.
int maxDbmsMarks = 0;
int maxMarksIndex = 0;
for(int i = 0; i < 5; i++)
{
if(a[i].marks_dbms > maxDbmsMarks )
{
maxDbmsMarks = a[i].marks_dbms;
maxMarksIndex = i;
}
}
printf("Student with the maximum dbms marks :\n");
printf("Name : %s, Reg : %s, dbmsMarks: %d, progMarks : %d\n", a[maxMarksIndex].name, a[maxMarksIndex].reg, a[maxMarksIndex].makrs_dbms, a[maxMarksIndex].marks_prog);
It is the same as finding the maximum number in an array. The above logic is for 'highest dbms marks', you can modify it to find the highest prog marks or highest combined marks.
First, write a function to compare students by their marks. It should accept two student parameters, and return true if the first student should be considered less than the second.
bool compareStudentsByMarks(const student & lhs, const student & rhs)
{
// This only compares by marks_dbms, I'm not sure how you want to do it.
return lhs.marks_dbms < rhs.marks_dbms;
}
Then, after including the <algorithm> header, use the function std::max_element, passing your function as the last argument.
const int SIZE_OF_STUDENT_ARRAY = 5;
student * pmax = std::max_element(a, a+SIZE_OF_STUDENT_ARRAY, compareStudentsByMarks);
// now pmax is a pointer to the student with the highest marks,
// you already know how to display their info
If you have access to C++0x, this is all a lot easier:
auto pmax = std::max_element(a, a+SIZE_OF_STUDENT_ARRAY,
[](const student & lhs, const student & rhs)
{
return lhs.marks_dbms < rhs.marks_dbms;
});
Related
I am trying to write C++ code suitable for object oriented programming.
I have two classes, namely, Student and Course. In the Student class, I have quiz_scores which is a 1-D array of 4 integers. I need both set and get methods, both are used in natural common way.
In the following, I implement setQuizScores method:
void Student :: setQuizScores(int* quizscores){
for(int i = 0; i<4; i++){
quiz_scores[i] = quizscores[i];
}
Where quizscores are my private members.
Now, next thing is that I want to return this quiz_scores array in the getQuizScores for each students of Student class.
However, the problem is that C++ does not allow us to return arrays directly. Instead, I want the structure of my code as following:
int Student :: getQuizScores(){
Do something;
return the elements of quiz_scores;
}
How can I do that efficiently?
I prefer not to use the Standard Template Library (STL), so I need to create my own arrays and access them according to the explanation above.
There are a few ways how you could return an array:
Pass in an array to copy to
void Student::getQuizScores(int* out) {
for(int i = 0; i < 4; i++)
out[i] = quiz_scores[i];
}
Student student;
int scores[4];
student.getQuizScores(scores);
// use scores[0], etc...
return a struct containing the array
struct Scores {
int values[4];
};
Scores Student::getQuizScores() {
Scores s;
for(int i = 0; i < 4; i++)
s.values[i] = quiz_scores[i];
return s;
}
Student student;
Scores s = student.getQuizScores();
// use s.values[0], etc...
return a reference to the quiz_scores array inside the class
using Scores = int[4];
Scores const& Student::getQuizScores() const {
return quiz_scores;
}
Student student;
Scores const& scores = student.getQuizScores();
// use scores[0], etc...
Just as setQuizScores() is able to take a pointer to an array, so too can getQuizScores() return a pointer to the quiz_scores member array, eg:
const int* Student::getQuizScores() const {
// do something...
return quiz_scores;
}
The caller can then access the array elements as needed, eg:
Student s;
...
const int *scores = s.getQuizScores();
for(int i = 0; i < 4; ++i){
cout << scores[i] << ' ';
}
Alternatively, since the array is fixed size, you can return a reference to the array instead, eg:
typedef int scoresArr[4];
scoresArr quiz_scores;
...
const scoresArr& Student::getQuizScores() const {
// do something...
return quiz_scores;
}
Student s;
...
const scoresArr &scores = s.getQuizScores();
for(int i = 0; i < 4; ++i){
cout << scores[i] << ' ';
}
You can return a pointer to the quiz_scores array through getQuizScores method as shown below:
Version 1: Using trailing return type
auto getQuizScores() -> int(*)[4]
{
//Do something;
return &quiz_scores;//NOTE THE & INFRONT OF quiz_scores
}
Now you can use this returned pointer to initialize other arrays. One possible example would be:
#include <iostream>
struct Student
{
int quiz_scores[4]= {1,2,3,4};
//getQuizScores returns a pointer to an array of size 4 with element of type int
auto getQuizScores() -> int(*)[4]
{
//Do something;
return &quiz_scores;//NOTE THE & INFRONT OF quiz_scores
}
void setQuizScores(int* quizscores)
{
for(int i = 0; i<4; i++)
{
quiz_scores[i] = quizscores[i];
}
}
};
int main()
{
Student s;
int arr[4];
for(int i = 0; i< 4; ++i)
{
arr[i] = (*s.getQuizScores())[i];
std::cout<<arr[i]<<std::endl;
}
return 0;
}
Version 2: Without using trailing return type
int (*getQuizScores())[4]
{
//Do something;
return &quiz_scores;//NOTE THE & INFRONT OF quiz_scores
}
Version 2 is the same as version 1 except that this time the getQuizScores method does not uses trialing return type.
There are other possibilities also like returning a reference to the quiz_scores array.
My professor has asked us to make a program that will take a user's input and continue reading until the end of input. Only then, can the program output what the user has typed.
Input should be based on video title, it's url, comments made on the video, length (in minutes), and rating (in *).
For example:
United Break Guitars, https://www.youtube.com/watch?v+5YGc4zOqozo, Great example of one person getting a giant company to listen, 4.5, ***, Space Versus Tabs, https://www.youtube.com/watch?v=SsoOG6ZeyUl, Decide for yourself: spaces or tabs?, 2.83, ****
Up until what is explained, I have completed and tested to see if everything works. My problem is the next part of the project which requires the user to choose between Rating, Length, or title then sort them based on what the user chose.
If I chose Rating, then the input above should be sorted from highest rated video to lowest.
This is what I have so far:
#include <iostream>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
using namespace std;
#include "video.h"
int main()
{
string user, url, comment, title;
int rating;
double length;
int i = 0, last = 0;
Video *videoObj[100];
Video *temp[100];
// specifies how the videos should be sorted
cin >> user;
cin.ignore();
while (getline(cin,title) ) {
getline(cin, url);
getline(cin, comment);
cin >> length;
cin >> rating;
cin.ignore();
videoObj[i] = new Video(title, url, comment, length, rating);
i++;
last++;
}
temp[i] = new Video(title, url, comment, length, rating);
if(user=="rating"){
for(int i = 0; i < last - 1; i++){
for(int j = i+1; j< last; j++){
if(videoObj[i] -> Rating(videoObj[j])) {
temp[i] = videoObj[i];
videoObj[i]= Rating(videoObj[j]);
Rating(videoObj[j]) = temp[i];
}
}
}
}
for(int i= 0; i < last; i++)
{
videoObj[i]->print();
}
//delete[] videoObj;
return 0;
}
video.cpp file:
#include <iostream>
#include <algorithm>
using namespace std;
#include "video.h"
Video::Video(string video_title, string video_link, string video_comment, double video_length, int video_number)
: title(video_title), link(video_link), comment(video_comment), length(video_length), rating(video_number)
{
}
bool Video::Rating(Video *videoObj) {
if(rating > videoObj-> rating )
{
return true;
}
else
{
return false;
}
}
void Video::print(){
string star;
switch(rating){
case 1:
star = "*";
break;
case 2:
star = "**";
break;
case 3:
star = "***";
break;
case 4:
star = "****";
break;
case 5:
star = "*****";
break;
}
cout << title << ", " << link << ", " << comment << ", " << length << ", " << star << endl;
}
void Video::temp(){
title, link, comment, length, rating;
}
video.h file:
#ifndef VIDEO_H
#define VIDEO_H
using namespace std;
class Video {
public:
Video(string video_title, string video_link, string video_comment, double video_length, int video_number);
void print();
bool Rating(Video *videoObj);
void temp();
private:
string title;
string link;
string comment;
double length;
int rating;
};
#endif
I honestly have no idea how to implement the bubble sort correctly. I have looked up multiple different videos on youtube and posts on stackoverflow, but I can't seem to figure out how to sort a specific parameter within my class.
My professor gave us these instructions for sorting within our class:
When sorting the videos you need to be able to determine how two video objects should be
ordered. The easiest way to do this is to write member functions to handle the comparisons in
class Video. For example, this method could be used when sorting the videos by length:
// return true if the current video is longer than the given video (other) ,
// otherwise return false
bool Video :: longer(Video *other) {
return (mlength > other -> mlength ;
}
I'm not even sure if I did that part correctly in my video.cpp file. Any ideas on how I can get the sorting method to work properly?
Please be gentle, I'm very new to programming. I realize my bubble sort is wrong as well, I just don't know where to start fixing it...
I'd normally use std::sort with a comparison operator for each field you want to be able to compare. You can implement those either as named classes:
struct by_title {
bool operator()(Video const &a, Video const &b) {
return a.title < b.title;
}
};
struct by_rating {
bool operator()(Video const &a, Video const &b) {
return a.rating < b.rating;
}
};
// ...
std::sort(videos.begin(), videos.end(), by_rating);
std::sort(videos.begin(), videos.end(), by_title);
...or you can use a lambda expression to define a comparison:
// sort by rating
std::sort(videos.begin(), videos.end(), [](auto &a, auto &b) { return a.rating < b.rating; });
// sort by title
std::sort(videos.begin(), videos.end(), [](auto &a, auto &b) { return a.title < b.title; });
I had sort the mark for all tests, quizzes, assignments and final exam in ASCENDING order. But I don't know how to display all student's name in ascending order based on their mark for each tests, quizzes, assignments and final exam.
Below are my code to sort each mark for tests, quizzes, assignments and final exam in ascending order. How to change the code so that it will display the students name, not the marks for each tests, quizzes, assignments and final exam?
Please, help. Thank you in advance.
#include <iostream>
#include <string>
using namespace std;
//global constant
const int NUM_STUDENTS=5;//row
const int NUM_SCORES=4;//col
string name[5]={"Hani","Haziq","Aiman","Farah","Sabrina"};
string mark[4]={"test","quiz","assignment","final exam"};
//Function prototypes
void ascenDescen(double [ ][NUM_SCORES],int);
int main ( )
{
cout<<"This program will help you keep track of your academic record!"<<endl;
double scores[NUM_STUDENTS][NUM_SCORES]=
{{9.0,2.7,16.0,78.0},
{7.4,2.7,19.0,88.0},
{8.9,3.5,17.5,93.7},
{10.0,3.0,19.5,64.8},
{6.3,3.0,16.0,74.2}};
//function call
ascenDescen(scores,NUM_STUDENTS);
cout<<endl;
cout<<"THANK YOU."<<endl;
return 0;
}
void ascenDescen (double table[][NUM_SCORES],int rows)
{
//for ascending
cout<<"Press ENTER to sort the mark for all tests, quizzes, assignments and final exam in ASCENDING order : \n\n";
char ch;
ch=cin.get();
double ascen;
for(int col=0;col<NUM_SCORES;col++)
{
for(int row=0;row<NUM_STUDENTS;row++)
{
for(int j=row+1;j<NUM_STUDENTS;++j)
{
if(table[row][col]>table[j][col])
{
ascen=table[row][col];
table[row][col]=table[j][col];
table[j][col]=ascen;
}
}
}
cout<<mark[col]<<" mark in ASCENDING order : \n";
for(int row=0;row<NUM_STUDENTS;row++)
{
cout<<" ";
cout<<table[row][col];
cout<<endl;
}
}
cout<<"________________________"<<endl;
}
A rule of thumb: If you need parallel arrays, chances are you should have a vector of struct.
Let's try modeling the data using a Student structure:
struct Student
{
std::string name;
std::vector<int> marks;
};
Thus far, every Student has a name and has some marks. The has-a relationship indicates composition. The is-a relationship indicates inheritance.
Let's add a sort method for the marks. The students will be easier to order by marks, if the marks are sorted.
struct Student
{
//...
void sort_marks()
{
std::sort(marks.begin(), marks.end()); // Assume default of `std::less<int>`
}
};
To perform an ordering other than the default, we'll need to define a custom ordering function:
bool Order_By_Marks(const Student& a, const Student& b)
{
bool a_is_less_than_b = true;
unsigned int quantity_of_marks = a.marks.size();
if (b.marks.size() < quantity_of_marks)
{
quantity_of_marks = b.marks.size();
}
for (unsigned int i = 0; i < quantity_of_marks; ++i)
{
if (a.marks[i] > b.marks[i])
{
a_is_less_than_b = false;
break;
}
}
return a_is_less_than_b;
}
To sort a database of Student by marks:
std::vector<Student> database;
// ... input students ...
for (i = 0; i < database.size(); ++i)
{
database[i].sort_marks();
}
std::sort(database.begin(), database.end(), Order_By_Marks);
You'll need to walk through the code with a debugger to verify the ordering of the student marks and also the ordering of the students by mark.
#include <iostream>
#include <string>
using namespace std;
//global constant
const int NUM_STUDENTS=5;//row
const int NUM_SCORES=4;//col
string name[5]={"Hani","Haziq","Aiman","Farah","Sabrina"};
string mark[4]={"test","quiz","assignment","final exam"};
struct student {
};
//Function prototypes
void ascenDescen(double [ ][NUM_SCORES],int);
int main ( )
{
cout<<"This program will help you keep track of your academic record!"<<endl;
double scores[NUM_STUDENTS][NUM_SCORES]=
{{9.0,2.7,16.0,78.0},
{7.4,2.7,19.0,88.0},
{8.9,3.5,17.5,93.7},
{10.0,3.0,19.5,64.8},
{6.3,3.0,16.0,74.2}};
//function call
ascenDescen(scores,NUM_STUDENTS);
cout<<endl;
cout<<"THANK YOU."<<endl;
return 0;
}
void ascenDescen (double table[][NUM_SCORES],int rows)
{
//for ascending
cout<<"Press ENTER to sort the mark for all tests, quizzes, assignments and final exam in ASCENDING order : \n\n";
cin.get();
double ascen;
string temp1[5] = name;
string temp2;
for(int col=0;col<NUM_SCORES;col++)
{
for(int row=0;row<NUM_STUDENTS;row++)
{
for(int j=row+1;j<NUM_STUDENTS;++j)
{
if(table[row][col]>table[j][col])
{
ascen=table[row][col];
temp2 = temp1[row];
table[row][col]=table[j][col];
temp1[row] = temp1[j];
table[j][col]=ascen;
temp1[j] = temp2;
}
}
}
cout<<mark[col]<<" mark in ASCENDING order : \n";
for(int row=0;row<NUM_STUDENTS;row++)
{
cout<<" ";
cout << temp1[row] << " " <<table[row][col];
cout<<endl;
}
for(int i = 0; i < NUM_STUDENTS; i++)
{
temp1[i] = name[i];
}
}
cout<<"________________________"<<endl;
}
This question already has an answer here:
How to sort an array of structs in C?
(1 answer)
Closed 6 years ago.
I have a C struct declared as below (just a simple example):
typedef struct
{
float score;
char* name;
}
person;
So, along the program, I changed the value of the person's score (i gave them an initial value). So, i plan to put all of the scores inside a vector and sort them. Then, I would like to print a list of the name of all the persons, starting from biggest score to smallest score. Any idea on this last part? I'm not sure how to code it. Thanks.
Similar to the C++ approach above, there is a library function in the C standard library called qsort. It is based upon a comparision function, that creates the ordering on the array members.
For your case a minimal example could look like this:
#include <stdlib.h>
#include <stdio.h>
// Definitiion of a person
typedef struct person
{
float score;
char *name;
} person;
// Some small epsilon
#define EPSILON 1.0e-3f
// Comaprision function. Returns <0 for a<b =0 for a=b and >0 for a>b
static int compare_people( const void *a, const void *b )
{
// Cast to the correct pointer type
const person *p1 = (const person*) a;
const person *p2 = (const person*) b;
// There are different ways of comparing floats to each other. In this case we use |a - b| < epsilon for some small epsilon
float difference = p2->score - p1->score;
if( difference <= -EPSILON )
{
return -1;
}
else if( difference >= +EPSILON )
{
return +1;
}
return 0;
}
int main()
{
// Initialize list of people
size_t num_people = 5;
person people[num_people];
people[0].score = 0.3f;
people[0].name = "Homer";
people[1].score = 1.4f;
people[1].name = "Marge";
people[2].score = 0.02f;
people[2].name = "Bart";
people[3].score = 13.2f;
people[3].name = "Lisa";
people[4].score = 1.0f;
people[4].name = "Maggie";
// Print unsorted
printf( "Unsorted:\n" );
for( size_t i = 0; i < num_people; ++i )
{
printf( " %s - %2.2f\n", people[i].name, people[i].score );
}
printf( "\n" );
// Sort
qsort( people, num_people, sizeof(person), &compare_people );
// Print sorted
printf( "Sorted:\n" ) ;
for( size_t i = 0; i < num_people; ++i )
{
printf( " %s - %2.2f\n", people[i].name, people[i].score );
}
printf( "\n" );
// Done
return EXIT_SUCCESS;
}
Note the comment about comparing floating point values.
If you are using Linux, you can investigate system calls and functions of the C standard library by looking up the corresponding man page, e.g.
man qsort
For example you ll have
vector<person> vec;
Now you want sort this using sort from STL
You first must create method for operator " < "
bool operator<(const person& a, const person& b){
return a.score<b.score;
}
I hope this helps you I m sorry for my bad grammar :)
Example of usage
sort(vec.begin(),vec.end(),[](const person& a, const person&b){return b<a});
Now your vector of person will be sorted upside - down order.
I've been working on a very in depth project for one of my classes. It supposed to read in Person objects and put them into a hash table. I'm still trying to get my head around the concept of a hash table so any help would be appreciated.
It will be hashing based on last name and since some people may have the same last name, I was going to make each bucket a vector of Person objects. I'm trying to test the class by adding a person to the hash function and then returning it. My code compiles successfully but I get a thread error in the put function on this line: table[index].push_back(p);
Could anyone please help me figure out what is going wrong? Thank you!
int main()
{
HashTable ht(10);
ht.put(p1, p1->lName);
ht.getName("Booras");
}
HashTable:
#include "Person.h"
#include <vector>
class HashTable: public DataStructures
{
private:
vector<vector<Person>> table;
public:
HashTable(int tableSize);
~HashTable();
int tableSize;
void getName(string str); //prints out friends with matching name
void put(Person p, string str);
void remove(Person *p, string str);
int hash(string str);
};
HashTable::HashTable(int tableSize)
{
vector< vector<Person> > table(tableSize, vector<Person>(tableSize));
for (int i = 0; i < tableSize; i++) {
table.push_back(vector<Person>()); // Add an empty row
}
}
HashTable::~HashTable()
{
}
//Find a person with the given last name
void HashTable::getName(string key)
{
int index = hash(key);
for(int i=0; i<table[index].size(); i++)
{
if(table[index][i].lName.compare(key) == 0)
std::cout << "Bucket: " << index << "Bin: " << i;
table[index][i].print();
}
//create exception for person not found
}
void HashTable::put(Person p, string str)
{
int index = hash(str);
table[index].push_back(p);
}
void HashTable::remove(Person *p, string str)
{
int index = hash(str);
int i=0;
while(&table[index][i] != p && i<table[index].size())
i++;
for(int j=i; j<table[index].size()-1; j++)
table[index][j] = table[index][j+1];
table[index].pop_back();
}
int HashTable::hash(string str)
{
int hashValue = 0;
for(int i=0; i<str.length(); i++)
{
hashValue = hashValue + int(str[i]);
}
hashValue %= tableSize;
if(hashValue<0) hashValue += tableSize;
return hashValue;
}
Main:
int main() {
Person *p1 = new Person("Kristy", "Booras", "Reston", "03/15");
HashTable ht(10);
ht.put(*p1, p1->lName);
ht.get("Booras");
return 0;
}
You don't show us the HashTable::hash(string) member function, but I'd assume that your problems originate in the HashTableconstructor: You don't initialize the tableSize member variable, which you'll need to calculate a valid hashed index.
While looking at the constructor:
HashTable::HashTable(int tableSize)
{
vector< vector<Person> > table(tableSize, vector<Person>(tableSize));
This has initialized table to have tableSize non-empty elements, for a total of tableSize * tableSizedefault-constructed Person objects.
for (int i = 0; i < tableSize; i++) {
table.push_back(vector<Person>()); // Add an empty row
}
}
Now you have added more rows, so that table.size() == 2*tableSize, with the first half of entries non-empty (as explained above) and the second half holding empty vectors.
That is probably not what you intended.
And in all of that you haven't initialized the member tableSize. It easily gets confusing, if you use local variables or argument names that hide member names.