Why my program is not printing string? - c++

My program takes name and age of student and this function should find print the name of youngest,eldest student , and average age.However it does not prints name of youngest student can anyone tell me why?
void check(string *nameStudent, int *ageStudent, int num) {
int i, young = 0, old = 0, sum = 0, mov = 0;
string a, b;
double average;
for (i = 0; i < num; i++){
if (*(ageStudent + mov) < young) {
young = *(ageStudent + mov);
a = *(nameStudent + mov);
}
if (*(ageStudent + mov) > old) {
old = *(ageStudent + mov);
b = *(nameStudent + mov);
}
sum += *(ageStudent + mov);
mov++;
}
average = (double) sum / num;
cout << a << " Is youngest student and " << b << " Is oldest student " << endl << average << " is average age of students";
}

You initialize young to 0. It will only change young and a if there's a student whose age is less than 0.
Instead of hard-coding the initial values of all these variables, get them from the first elements of the arrays.
if (num > 0) {
young = old = sum = *ageStudent;
a = b = *nameStudent;
}
Then you can change your loop to start from 1 instead of 0, since you've already processed the first element of the array.
BTW, there's no need for the mov variable, since it always contains the same thing as i. Use *(ageStudent + i) instead.
void check(string *nameStudent, int *ageStudent, int num) {
int i, young = 0, old = 0, sum = 0;
string a, b;
double average;
if (num > 0) {
young = old = sum = *ageStudent;
a = b = *nameStudent;
}
for (i = 1; i < num; i++){
if (*(ageStudent + i) < young) {
young = *(ageStudent + i);
a = *(nameStudent + i);
}
if (*(ageStudent + i) > old) {
old = *(ageStudent + i);
b = *(nameStudent + i);
}
sum += *(ageStudent + i);
mov++;
}
average = num ? (double) sum / num : 0; // prevent division by 0
cout << a << " Is youngest student and " << b << " Is oldest student " << endl << average << " is average age of students";
}

You're keeping the age of the youngest student in young, but initializing it to 0, so of course none of the students in the list are going to satisfy ageStudent[i] < young. Initialize it to a large value instead. Generally, the largest value that the type in question (int) can take is preferred. If that sounds complicated to you, you can use something like 1000 in this case, as long as none of your students are going to be over a thousand years old.

Set initial young to the maximum integer to force the comparison that is setting a.
Strictly speaking the initial old should be negative maximum (signed) integer to handle all formally possible cases and also the num=0 case should be adressed.

Your problem is the variable young.
You initialize it here to 0:
int i, young = 0, old = 0, sum = 0, mov = 0;
Then you check it here:
if (*(ageStudent + mov) < young) {
But the ageStudent variable will always be greater than 0, as long as nobody of your students is under 0 years old, so the condition will always evaluate to false.
You can solve the problem by setting young to a high number at the beginning of your function.

Related

How to find the maximum average marks in 2D vector of string?

I have taken the name and marks of each student in 2D vector of string.
How can we find the student name having maximum average Marks
I am not able to fetch the Marks of student as it is string in 2d vector.
I can do the same using STL Map. But how to do the same using 2D vector of string.
vector<vector<string>>vect {{"James", "70"}, {"Fernando", "40"}, {"Nick", "60"},{"James", "90"},{"Nick", "70"},{"Amit", "50"}};
Expected output is "James : 80"
You can do it this way as well
int max = stoi(vect[0][1]);
string name;
for(int i=0;i<vect.size();i++)
If(max < stoi(vect[i][1]))
{
max = stoi(vect[i][1]);
name.insert(0,vect[i][0]);
}
Here, name is the person who's scored the maximum average marks
If you want to do the calculation in place, that is with O(1) additional memory requirements, you can use the following approach:
Iterate over all the records.
Find out if the actual name hasn't been already processed before (by comparing the name with all the records having lower indexes).
If not, find all the records having the same name starting from the actual one while summing up the scores and their count.
Calculate the average (sum / count).
If the average is higher the up-to-now maximum, update this maximum to the actual one.
Hope you can write the code by yourself ;-)
Note that this approach does not modify the input vector. If you can to that, a better approach would be to sort it first by name and then perform one linear pass by its elements, as suggested by #mahbubcseju.
My approach: Use a map Student -> Vector of Marks, fill it, then average it.
map<string, vector<double> > marks;
for(const vector<string>& entry : vect)
{
string name = entry[0];
int mark = stod(entry[1]);
marks[name].push_back(mark);
}
Now you have a map filled with a vector of marks for each student, easy to handle. If you want the averages, go like:
string best_student = "nobody";
double best_average = 0.;
for(auto const& entry : marks)
{
const string& name = entry.first;
const vector<double>& student_marks = entry.second;
double average = accumulate(student_marks.begin(), student_marks.end(), 0) / student_marks.size();
cout << "The student " << name << " has an average mark of " << average << endl;
if(average > best_average)
{
best_average = average;
best_student = name;
}
}
cout << endl;
cout << "The student with the highest average mark is " << best_student << " with " << best_average << endl;
(Note that you need to #include<numeric> for std::accumulate, and that I used for each, thus you need at least C++11.)
Might not be the most time optimized approach, but works nicely and is quite readable as far as I see it.
I implemented this here: http://cpp.sh/6lijg
(I did some assumptions that one might check (/handle by something like throwing an exception if not met or printing some message): 1. The original vector is always correctly filled, that is every subvector has length 2; 2. the original vector always has at least one entry; 3. marks are non-negative and there is a student with a non-zero mark - else the initializations of best_student and best_mark are wrong.)
Firstly sort the vector by using the name as key .
After that all the same persons will be besides each others.
For Example:
vector<vector<string>>vect {{"James", "70"}, {"Fernando", "40"}, {"Nick", "60"},{"James", "90"},{"Nick", "70"},{"Amit", "50"}};
sort(vect.begin(),vect.end());
for(int i=0;i<vect.size();i++){
cout<<vect[i][0]<<" "<<vect[i][1]<<endl;
}
This will output like following:
Amit 50
Fernando 40
James 70
James 90
Nick 60
Nick 70
After that iterate through the row vector by the following way and calculate the average:
int ma=-1;
string maxPerson="";
int counter=0;
int cumSum=0;
for(int i=0;i<vect.size();i++){
if(i>0&&vect[i][0]!=vect[i-1][0]){
int avg=(cumSum/counter);
if(avg>ma){
ma=avg;
maxPerson=vect[i-1][0];
}
counter=1;
cumSum=stringTonumber(vect[i][1]);
}
else {
counter++;
cumSum+=stringTonumber(vect[i][1]);
}
}
int avg=(cumSum/counter);
if(avg>ma){
ma=avg;
maxPerson=vect[vect.size()-1][0];
}
You can declare ma and avg variable as double to calculate the real average if need. Cz sometimes result can be 90.5 but int will not consider .5.
Whole code:
#include <bits/stdc++.h>
#define LEN 150
using namespace std;
int stringTonumber(string x)
{
int num = 0;
for (int i = 0; i < x.size(); i++) {
num = num * 10 + x[i] - '0';
}
return num;
}
int main()
{
vector<vector<string> > vect{ { "James", "70" }, { "Fernando", "90" }, { "Fernando", "80" }, { "Fernando", "100" }, { "Nick", "60" }, { "James", "80" }, { "Nick", "70" }, { "Amit", "50" } };
sort(vect.begin(), vect.end());
for (int i = 0; i < vect.size(); i++) {
cout << vect[i][0] << " " << vect[i][1] << endl;
}
int ma = -1;
string maxPerson = "";
int counter = 0;
int cumSum = 0;
for (int i = 0; i < vect.size(); i++) {
if (i > 0 && vect[i][0] != vect[i - 1][0]) {
int avg = (cumSum / counter);
if (avg > ma) {
ma = avg;
maxPerson = vect[i - 1][0];
}
counter = 1;
cumSum = stringTonumber(vect[i][1]);
}
else {
counter++;
cumSum += stringTonumber(vect[i][1]);
}
}
int avg = (cumSum / counter);
if (avg > ma) {
ma = avg;
maxPerson = vect[vect.size() - 1][0];
}
cout << maxPerson << " " << ma << endl;
return 0;
}

Rubik's Cube Scramble Generator algorithm

I've been recently working on a project which includes a Rubik's Cube scramble generator. Basically the program should generate and display random cube notations so that the user can follow each move and have a fairly scrambled cube. Notations include "R" for turning the right layer , "L" for turning the left layer, "F" for turning front layer, "D" for down, "U" for up and "B" for back. And so you have a total of 6 sides "R, L, U, D, F, B". The appostrophe after any of these notations means moving that layer counter clockwise and "2" means moving that layer twice. The problem is you can't have the same notation be repeated next to each other like "R, R" as it would be the same as "R2", nor you can have "R, R' " next to each other as they would cancel each other out. My solution to this was making a 2 dimensional array for storing the 3 groups of notations for every type.
string notation_group[row][column] = { { "R ", "L ", "F ", "B ", "U ", "D " },
{"R' ", "L' ", "F' ", "B' ", "U' ", "D' "}, { "R2", "L2", "F2", "B2", "U2", "D2"} };
This means that whenever the program picks a random column from any of these groups, the program has to prevent the next generated notation from choosing the same column in any other group. So let's say if the program picks the first element of the first group "R", then for the next iteration it can choose any notation except "R", "R' " and "R2", all of which belong to the first column of their respective groups. So all the program has to do is not to pick that column during the next iteration.
I used a "temp" variable to keep in mind the current randomly generated notation and compare it to the next one, and generating a new one whenever those are equal.
int temp;
scrambled_notation[i] = notation_group[pickGroup][pickColumn];
temp = pickColumn;
pickColumn = 0 + rand() % 6;
while (temp == pickColumn) {
pickColumn = 0 + rand() % 6;
}
It does work but there is still another problem, whenever you have something like "R, L" or "R, L', R" be repeated multiple times next to each other they would again cancel each other out leaving no affect on the cube. Is there any idea for how can I prevent two of the opposing sides being repeated next to each other for more than once? I would greatly appreciate the help.
void initScramble(const int, string[][6], string[]);
int main() {
srand(time(0));
const int row = 3, column = 6;
string notation_group[row][column] = { { "R", "L", "F", "B", "U", "D" },
{"R'", "L'", "F'", "B'", "U'", "D'"}, { "R2", "L2", "F2", "B2", "U2", "D2"} };
const int scrambleSize = 22;
string scrambled_notation[scrambleSize];
cout << "SCRAMBLE: " << endl;
initScramble(scrambleSize, notation_group, scrambled_notation);
system("pause");
return 0;
}
void initScramble(const int scrambleSize, string notation_group[][6], string scrambled_notation[]) {
int pickColumn = 0 + rand() % 6;
while (true) {
cin.get();
for (int i = 0; i < scrambleSize; i++) {
int pickGroup = 0 + rand() % 3;
int temp;
scrambled_notation[i] = notation_group[pickGroup][pickColumn];
temp = pickColumn;
pickColumn = 0 + rand() % 6;
while (temp == pickColumn) {
pickColumn = 0 + rand() % 6;
}
}
for (int i = 0; i < scrambleSize; i++) {
cout << scrambled_notation[i] << " ";
}
cin.get();
system("CLS");
}
}
You have to look for the last two moves as long as they are commutative. If not, then you only check for the last move. This is simplified by the fact that each pair of columns are commutative:
void initScramble(const int scrambleSize, string notation_group[][6], string scrambled_notation[]) {
while (true) {
int lastColumn = 7; // Invalid columns
int beforeLastColumn = 7;
cin.get();
for (int i = 0; i < scrambleSize; i++) {
int pickGroup = 0 + rand() % 3;
int pickColumn = 0 + rand() % 6;
bool isCommutative = (lastColumn / 2) == (beforeLastColumn / 2);
while (pickColumn == lastColumn || isCommutative && pickColumn == beforeLastColumn) {
pickColumn = 0 + rand() % 6;
}
scrambled_notation[i] = notation_group[pickGroup][pickColumn];
beforeLastColumn = lastColumn;
lastColumn = pickColumn;
}
for (int i = 0; i < scrambleSize; i++) {
cout << scrambled_notation[i] << " ";
}
cin.get();
system("CLS");
}
}
You don't have to look further since you can have only 2 commutative consecutive moves following your rules of scrambling. For example, 'L,R,L' and 'L,R,R' will be discarded, and thus, 3 commutative moves will never be generated.

finding minimum number of jumps

Working on below algorithm puzzle of finding minimum number of jumps. Posted detailed problem statement and two code versions to resolve this issue. I have did testing and it seems both version works, and my 2nd version is an optimized version of version one code, which makes i starts from i=maxIndex, other than continuous increase, which could save time by not iteration all the slots of the array.
My question is, wondering if my 2nd version code is 100% correct? If anyone found any logical issues, appreciate for pointing out.
Problem Statement
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Your goal is to reach the last index in the minimum number of jumps.
For example:
Given array A = [2,3,1,1,4]
The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)
First version code
class Solution {
public:
int jump(vector<int>& nums) {
int i = 0, n = nums.size(), step = 0, end = 0, maxend = 0;
while (end < n - 1) {
step++;
for (;i <= end; i++) {
maxend = max(maxend, i + nums[i]);
if (maxend >= n - 1) return step;
}
if(end == maxend) break;
end = maxend;
}
return n == 1 ? 0 : -1;
}
};
2nd version code
class Solution {
public:
int jump(vector<int>& nums) {
int i = 0, n = nums.size(), step = 0, end = 0, maxend = 0;
int maxIndex = 0;
while (end < n - 1) {
step++;
for (i=maxIndex;i <= end; i++) {
if ((i + nums[i]) > maxend)
{
maxend = i + nums[i];
maxIndex = i;
}
if (maxend >= n - 1) return step;
}
if(end == maxend) break;
end = maxend;
}
return n == 1 ? 0 : -1;
}
};
thanks in advance,
Lin
The best way is always to test it. A human cannot always think about special cases but a automated test can cover the most of speciale cases. If you think that your first version works well, you can compare the result of the first with the second one. Here an exemple:
/*
* arraySize : array size to use for the test
* min : min jump in the array
* max : max jump in the array
*/
void testJumps(int arraySize, int min, int max){
static int counter = 0;
std::cout << "-----------Test " << counter << "------------" << std::endl;
std::cout << "Array size : " << arraySize << " Minimum Jump : " << min << " Max Jump" << max << std::endl;
//Create vector with random numbers
std::vector<int> vecNumbers(arraySize, 0);
for(unsigned int i = 0; i < vecNumbers.size(); i++)
vecNumbers[i] = rand() % max + min;
//Value of first function
int iVersion1 = jump1(vecNumbers);
//Second fucntion
int iVersion2 = jump2(vecNumbers);
assert(iVersion1 == iVersion2);
std::cout << "Test " << counter << " succeeded" << std::endl;
std::cout << "-----------------------" << std::endl;
counter++;
}
int main()
{
//Two test
testJumps(10, 1, 100);
testJumps(20, 10, 200);
//You can even make a loop of test
//...
}

Sum two Dynamic Arrays

I'm doing a homework problem where I have two take input from a user in the form of two dynamic char arrays (max of 100 characters each) and returning their sum.
I'm struggling with coming up with a sum function that works correctly when the two numbers are of different length or when the answer is less than 100 digits. When the numbers are of different length, they get added as if they were the same (e.g. 100 + 1000 becomes 1000+1000). When the result is less than 100 digits, the full arrays is printed anyway (so there are dozens of trailing zeros). (EDIT: Fixed, see below).
I know that there is no way to tell the actual size of a dynamic array, and I can't figure out any way to place some sort of sentinel value that stops the program from processing farther. I'm not allowed to use vectors or traditional arrays, which would give me a clear path to the solution. EDIT: This has been fixed by checking for '\0'.
I know SO doesn't want to do people's homework for them (nor am I asking that), but I do need some guidance as to how I can solve this problem. I've been working for hours and still can't think of a solution.
My program is as follows:
#include <iostream>
#include <algorithm>
int* sum(char*, char*);
int main() {
char * arr = new char[100];
char * arr2 = new char[100];
std::cout << "Enter value 1: ";
std::cin >> arr;
std::cout << "Enter value 2: ";
std::cin >> arr2;
int * result = sum(arr, arr2);
std::cout << "Result: ";
for (int i = 0; i < 100 && result[i] != '\0'; i++) {
std::cout << result[i];
}
std::cout << std::endl;
return 0;
}
int* sum(char * num1, char* num2) {
std::reverse(num1, num1 + 100);
std::reverse(num2, num2 + 100);
bool carryOver = false;
int* retarr = new int[100]; //Array to return to user
for (int i = 0; i < 100; i++) {
//Numerical value is char - 48, unless
//char value is zero, then int val is zero
int val1 = std::max(num1[i] - 48, 0);
int val2 = std::max(num2[i] - 48, 0);
int carry = (carryOver)? 1 : 0;
carryOver = false; //Reset carryOver var
int t = val1 + val2 + carry;
if (t >= 10) {
t = t % 10;
carryOver = true;
}
retarr[99 - i] = t;
}
return retarr;
}

Same random numbers being created everytime the loop goes around.

I am a beginner at C++ and for one of my project involves loop inside loops and creating random numbers. Here is what I have so far:
`
using namespace std;
int main()
{
srand((unsigned int)time(0));
{
cout << "Name of reservoir: ";
string reservior_name;
cin >> reservior_name;
cout << "Capacity in MAF: ";
double capacity;
cin >> capacity;
cout << "Maximum inflow in MAF: ";
int max;
cin>> max;
cout << "minimum inflow in MAF: ";
int min;
cin >> min;
if(min>max)
{cout<<endl<<"Error: The minimum inflow is higher than the maximum inflow."<<endl
<< "Please re-enter your minimum inflow: ";
cin>>min;
}
double inflow_range= max-min;
cout <<"required outflow in MAF: ";
double required;
cin >> required;
if (required > 0.9 * (min + max)/2)
{
cout<<endl<< "Warning: required ouflow is over 90% of the average inflow."<<endl
<< "Returning to main menu ";
}
else
{ const int simulations = 10;
int water_level = 0;
int years = 1;
cout << "Running simulation..." << endl;
for (int i = 1; i <= simulations; i++)
{
int x = (rand()% (max-min + 1)) + min;
while (water_level < capacity)
{
//double r = rand() * 1.0 / RAND_MAX;
//double x = min + inflow_range * r;
//int x = (rand()% (max-min + 1)) + min;
if (water_level + x > required)
{
water_level = water_level + x - required;
}
else
{
water_level= 0;
}
years++;
}
cout <<"Simulation "<< i <<" took " << years <<" years to finish"<< endl;
}
}
}
system ("pause");
return 0;
}
`
So my main question is I'm running into a wall concerning setting up the for loops underneath "Running simulation" where I need to set up the first for loop to run the internal for loop 10 times, with each of those 10 iterations of the internal for loop coming up with random numbers for the range of acceptable results from the query for a random value. I've been told that the idea is to use the Monte Carlo method, i.e. I put in here both the Monte Carlo method and the normal random number generating method. Here it is:
for (int i = 1; i <= simulations; i++)
{
int x = (rand()% (max-min + 1)) + min;
while (water_level < capacity)
{
//double r = rand() * 1.0 / RAND_MAX;
//double x = min + inflow_range * r;
//int x = (rand()% (max-min + 1)) + min;
so the program will create a random value for the inflow. The idea is that the internal for loop will continue to run until the fill_level of the reservoir, which starts at 0, hits the capacity. The process of simulating how many years (each iteration of the internal for loop representing a year) is to be repeated 10 times by the parent for loop of the water_level simulation for loop.
The problem is that the random number that is supposed to created are the same number. THey are different every time I run it, but they are the same every time the loops repeat to make a new simulation. I have tried to figure out what the problem is for hours and still stuck. Any help is very appreciated.
The x is random in your code, the problem is the algorithm and calculation after that. See your code live.
You've forgotten to reset simulation parameter at each iteration, put these inside simulation loop:
--------------------------------------------+
|
for (int i = 1; i <= simulations; i++) |
{ |
int water_level = 0; <--+
int years = 1; <--+
int x = (rand() % (max - min + 1)) + min;
See the code after this edition: live code. The output is
Simulation 1 took 68 years to finish
Simulation 2 took 101 years to finish
Simulation 3 took 8 years to finish
With the code as shown, each iteration (simulation) gets a single value of x for all the years that are simulated. Your commented out code generates a new value of x for each year. Which is the method you want? I'm inclined to think that the inflow varies from year to year, so you should generate a new value of x for each year.
It also looks like you should reset years and water_level for each simulation.
cout << "Running simulation..." << endl;
for (int i = 1; i <= simulations; i++)
{
int water_level = 0;
int years = 1;
while (water_level < capacity)
{
int x = (rand() % (max - min + 1)) + min;
if (water_level + x > required)
water_level += x - required;
else
water_level = 0;
years++;
}
cout <<"Simulation "<< i <<" took " << years <<" years to finish"<< endl;
}
And for debugging, I'd want to print the control parameters (min, max, capacity, required), and then print the key values (year, x, water_level) on each iteration of the inner while loop until I was satisfied it was working correctly.