complex looping question. Maybe impossible - c++

Is there a way to loop this so I don't have to write it out 10 times?
Basically, I'm creating instances for a DVD class which each has different member values. It would be nice if I could make my file more readable. I've got this far.
for (int i=n; i<= 10; i++) {
for (int j=0; j<=9; j++) {
if (n == i) {
dvd[j].print();
}
}
}
but it's obviously wrong and I know why to. I just don't know if it's possible.
DVD dvd[10];
dvd[0].id = d[2];
dvd[0].name = d[3];
dvd[0].genre = d[4];
dvd[0].cast = d[5];
dvd[0].desc = d[6];
dvd[0].dateRent = d[7];
dvd[0].dateRet = d[8];
dvd[0].cost = d[9];
dvd[1].id = d[12];
dvd[1].name = d[13];
dvd[1].genre = d[14];
dvd[1].cast = d[15];
dvd[1].desc = d[16];
dvd[1].dateRent = d[17];
dvd[1].dateRet = d[18];
dvd[1].cost = d[19];
dvd[2].id = d[22];
dvd[2].name = d[23];
dvd[2].genre = d[24];
dvd[2].cast = d[25];
dvd[2].desc = d[26];
dvd[2].dateRent = d[27];
dvd[2].dateRet = d[28];
dvd[2].cost = d[29];
dvd[3].id = d[32];
dvd[3].name = d[33];
dvd[3].genre = d[34];
dvd[3].cast = d[35];
dvd[3].desc = d[36];
dvd[3].dateRent = d[37];
dvd[3].dateRet = d[38];
dvd[3].cost = d[39];
dvd[4].id = d[42];
dvd[4].name = d[43];
dvd[4].genre = d[44];
dvd[4].cast = d[45];
dvd[4].desc = d[46];
dvd[4].dateRent = d[47];
dvd[4].dateRet = d[48];
dvd[4].cost = d[49];
dvd[5].name = d[53];
dvd[5].id = d[52];
dvd[5].genre = d[54];
dvd[5].cast = d[55];
dvd[5].desc = d[56];
dvd[5].dateRent = d[57];
dvd[5].dateRet = d[58];
dvd[5].cost = d[59];
dvd[8].id = d[62];
dvd[8].name = d[63];
dvd[8].genre = d[64];
dvd[8].cast = d[65];
dvd[8].desc = d[66];
dvd[8].dateRent = d[67];
dvd[8].dateRet = d[68];
dvd[8].cost = d[69];
dvd[7].id = d[72];
dvd[7].name = d[73];
dvd[7].genre = d[74];
dvd[7].cast = d[75];
dvd[7].desc = d[76];
dvd[7].dateRent = d[77];
dvd[7].dateRet = d[78];
dvd[7].cost = d[79];
dvd[8].id = d[82];
dvd[8].name = d[83];
dvd[8].genre = d[84];
dvd[8].cast = d[85];
dvd[8].desc = d[86];
dvd[8].dateRent = d[87];
dvd[8].dateRet = d[88];
dvd[8].cost = d[89];
dvd[9].id = d[92];
dvd[9].name = d[93];
dvd[9].genre = d[94];
dvd[9].cast = d[95];
dvd[9].desc = d[96];
dvd[9].dateRent = d[97];
dvd[9].dateRet = d[98];
dvd[9].cost = d[99];
and
if (n == 1) {
dvd[0].print();
}
if (n == 2) {
dvd[1].print();
}
if (n == 3) {
dvd[2].print();
}
if (n == 4) {
dvd[3].print();
}
if (n == 5) {
dvd[4].print();
}
if (n == 6) {
dvd[5].print();
}
if (n == 7) {
dvd[6].print();
}
if (n == 8) {
dvd[7].print();
}
if (n == 9) {
dvd[8].print();
}
if (n == 10) {
dvd[9].print();
}

eglease's comment was spot on: You'll notice that the index you want to print is one smaller than your n (wherever that comes form), so you can simply use n-1 as an index to print. That is, I think, what you tried to achieve with your nested loop and did with your if-chain, but you were thinking too complicated: No loop is required! You could have spotted the connection between n and the array index when you wrote the if-chain: The index is always one smaller than the n. You can simply write that ;-).
void print dvd_number_n(int n) { dvd[n-1].print(); }
If you want to loop over all your DVDs you can loop from 0 to n-1, which is very common in C or C++ because it has zero-based arrays, that is, the first element is at index 0.
The idiomatic way to code that is a for loop starting at 0 and testing the loop variable for being truly smaller than the number of elements.
For an array with 3 DVDs array alements would be dvd[0], dvd[1], and dvd[2]. dvd[3] would be out-of-bounds, because there are only 3 elements in the array, not 4. Such boundary violations are one of the most common errors in C or C++ which do not check array indices (and typically can't do that at all because the array size is unknown at the site of use). The print loop for an array of 3 DVDs would be
for( int i=0; i<3; i++) { dvd[i].print(); }
The index i
starts with 0, execute loop (1)
is incremented to 1, smaller than 3, execute loop (2)
is incremented to 2, smaller than 3, execute loop (3)
is incremented to 3, equal to 3, loop condition is false, loop is left.
This gives us the 3 loop executions with the indices 0,1,2 as desired.
There is a lot of room for improvement: Give your class a constructor and use a vector, not an array. Here is an example that may give you an idea.
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
/// A simple data holder for DVD information with a constructor.
class DVD_T
{
std::string mTitle;
unsigned int mCost; // in cent
public:
DVD_T(std::string title, unsigned int cost): mTitle(title), mCost(cost) {}
void print(std::ostream &os)
{
os << "Title: \"" << mTitle
<< "\", cost: $" << mCost/100 << "." << std::setw(2) << std::setfill('0') << mCost%100;
}
};
std::vector<DVD_T> &initDVDs()
{
// This initialization of a static local variable will be run only once.
static std::vector<DVD_T> DVDs
{
// You'll probably want to obtain data from your data array d.
{"Title 1", 109},
{"Title 2", 99}
};
return DVDs;
}
int main()
{
// Get reference to initialized vector of DVDs
std::vector<DVD_T> &DVDs = initDVDs();
// Print them all. "Look mama, no index!"
for(auto dvd: DVDs)
{
dvd.print(std::cout);
std::cout << '\n';
}
}
Output:
Title: "Title 1", cost: $1.09
Title: "Title 2", cost: $0.99

Related

C++ - I want to combine data from pointer of vectors of strings into a static vector of strings in the following format

My vector of strings with dynamic size based of what user wants
std::vector<std::string>* allTags = new std::vector<std::string>[tvSize];
Filling the allTags variable
for (unsigned int i = 0; i < tvSize; i++)
allTags[i] = ParseData(vals[i]);
Now suppose that size of allTags pointer is 3 and following are the values in each:-
allTags[0] = { "0", "1", "2"}
allTags[1] = { "a", "b", "c"}
allTags[2] = { "X", "Y", "Z"}
I want to combine the data of all 3 allTags in vector of string say combined_data. But I want to do it in the following way:-
combined_data[0] = "0->a->X"; combined_data[1] = "0->a->Y"; combined_data[2] = "0->a->Z";
combined_data[3] = "0->b->X"; combined_data[4] = "0->b->Y"; combined_data[5] = "0->b->Z";
combined_data[6] = "0->c->X"; combined_data[7] = "0->c->Y"; combined_data[8] = "0->c->Z";
combined_data[9] = "1->a->X"; combined_data[10] = "1->a->Y"; combined_data[11] = "1->a->Z";
And so on. But I'm not able to come up with an algorithm for this. Can anyone help?
You want something like this:
vector<string> function(int lvl)
{
if (lvl == tvSize) return vector<string>(0);
vector<string> r; // some compilers will complain because of ()
vector<string> v = funtion(lvl + 1);
for(int i = 0; i < allTags[lvl].size(); i++)
{
if (v.size() != 0)
{
for(int k = 0; k < v.size(); k++)
{
string result = allTags[lvl][i];
//result += new string("->").append(v[k]); - memory leak
string pom("->");
result += pom.append(v[k]);
r.push_back(result);
}
}
else{ r.push_back(allTags[lvl][i]); }
}
return r;
}
Read std::vector documentation.
What you want is all permutations on every level, so complexity is O(n^(r + 1)), where n is number of elements in every row and r is tvSize in your example, and you can't do much about that, but if you don't need every permutation you could exclude some element on any level of recursion. So if you don't need permutations with 'c' your algorithm will be faster for O(n^(r + 1 - l)), where l is level of 'c'.

How to find all possible combinations of adding two variables, each attached to a multiplier, summing up to a given number (cin)?

In my situation, a lorry has a capacity of 30, while a van has a capacity of 10. I need to find the number of vans/lorries needed to transport a given amount of cargo, say 100. I need to find all possible combinations of lorries + vans that will add up to 100.
The basic math calculation would be: (30*lorrycount) + (10*vancount) = n, where n is number of cargo.
Output Example
Cargo to be transported: 100
Number of Lorry: 0 3 2 1
Number of Van: 10 1 4 7
For example, the 2nd combination is 3 lorries, 1 van. Considering that lorries have capacity = 30 and van capacity = 10, (30*3)+(10*1) = 100 = n.
For now, we only have this code, which finds literally all combinations of numbers that add up to given number n, without considering the formula given above.
#include <iostream>
#include <vector>
using namespace std;
void findCombinationsUtil(int arr[], int index,
int num, int reducedNum)
{
int lorry_capacity = 30;
int van_capacity = 10;
// Base condition
if (reducedNum < 0)
return;
// If combination is found, print it
if (reducedNum == 0)
{
for (int i = 0; i < index; i++)
cout << arr[i] << " ";
cout << endl;
return;
}
// Find the previous number stored in arr[]
// It helps in maintaining increasing order
int prev = (index == 0) ? 1 : arr[index - 1];
// note loop starts from previous number
// i.e. at array location index - 1
for (int k = prev; k <= num; k++)
{
// next element of array is k
arr[index] = k;
// call recursively with reduced number
findCombinationsUtil(arr, index + 1, num,
reducedNum - k);
}
}
void findCombinations(int n)
{
// array to store the combinations
// It can contain max n elements
std::vector<int> arr(n); // allocate n elements
//find all combinations
findCombinationsUtil(&*arr.begin(), 0, n, n);
}
int main()
{
int n;
cout << "Enter the amount of cargo you want to transport: ";
cin >> n;
cout << endl;
//const int n = 10;
findCombinations(n);
return 0;
}
Do let me know if you have any solution to this, thank you.
An iterative way of finding all possible combinations
#include <iostream>
#include <vector>
int main()
{
int cw = 100;
int lw = 30, vw = 10;
int maxl = cw/lw; // maximum no. of lorries that can be there
std::vector<std::pair<int,int>> solutions;
// for the inclusive range of 0 to maxl, find the corresponding no. of vans for each variant of no of lorries
for(int l = 0; l<= maxl; ++l){
bool is_integer = (cw - l*lw)%vw == 0; // only if this is true, then there is an integer which satisfies for given l
if(is_integer){
int v = (cw-l*lw)/vw; // no of vans
solutions.push_back(std::make_pair(l,v));
}
}
for( auto& solution : solutions){
std::cout<<solution.first<<" lorries and "<< solution.second<<" vans" <<std::endl;
}
return 0;
}
We will create a recursive function that walks a global capacities array left to right and tries to load cargo into the various vehicle types. We keep track of how much we still have to load and pass that on to any recursive call. If we reach the end of the array, we produce a solution only if the remaining cargo is zero.
std::vector<int> capacities = { 30, 10 };
using Solution = std::vector<int>;
using Solutions = std::vector<Solution>;
void tryLoad(int remaining_cargo, int vehicle_index, Solution so_far, std::back_insert_iterator<Solutions>& solutions) {
if (vehicle_index == capacities.size()) {
if (remaining_cargo == 0) // we have a solution
*solutions++ = so_far;
return;
}
int capacity = capacities[vehicle_index];
for (int vehicles = 0; vehicles <= remaining_cargo / capacity; vehicles++) {
Solution new_solution = so_far;
new_solution.push_back(vehicles);
tryLoad(remaining_cargo - vehicles * capacity, vehicle_index + 1, new_solution, solutions);
}
}
Calling this as follows should produce the desired output in all_solutions:
Solutions all_solutions;
auto inserter = std::back_inserter(all_solutions)
tryLoad(100, 0, Solution{}, inserter);

How would I write an algorithm to find the greatest jump from number to number in a sequence?

If your sequence is 4 2 1, the largest jump is from 4 to 2. If your sequence is 3 10 5 16 8 4 2 1, the largest jump is from 5 to 16.
I've made an algorithm however I'm not completely sure what I have done wrong (whever I haven't made the loop properly, set my variables correctly, or something else). I'm not sure what I need to set my index, BiggestDiff, or CurrentDiff too. I tried using a while loop to compare each number in my vector but I get zero (I'm assuming because I set BiggestDiff to zero)
If anyone can point me in the right direction, show me an example, or something else, that will be greatly appreciated.
Here is my code below
int findBiggestDiff(std::vector<int> sequence)
{
int index = 0;
int BiggestDiff = 0 ;
int CurrentDiff = BiggestDiff;
CurrentDiff = std::abs(sequence[index] - sequence[index + 1]);
while (index < sequence.size())
{
if (CurrentDiff > BiggestDiff)
{
BiggestDiff = CurrentDiff;
}
return index;
}
}
Try this:
{
int indexOfBiggestJump = 0;
int BiggestDiff = 0 ;
int CurrentDiff = BiggestDiff;
for(int i = 0; i < sequence.size() - 1; i++) {
CurrentDiff = std::abs(sequence[i] - sequence[i + 1]);
if (CurrentDiff > BiggestDiff)
{
BiggestDiff = CurrentDiff;
indexOfBiggestJump = i;
}
}
return indexOfBiggestJump;
}
There are several errors in your code.
your return index literally does nothing, only returns index (which will be 0) always.
you are not saving the index of the biggest jump anywhere.
if you are looking positions i and i + 1, you must go until sequence.size() - 1, otherwise you will look out of the bounds of sequence.
You aren't recalculating CurrentDiff at all. Also, your return statement in the in the wrong spot. You can do something like this (not tested)
int findLargest( const std::vector<int> &sequence ) {
if ( sequence.size() < 2 ) return -1; // if there's not at least two elements, there's nothing valid.
int index = 0;
int biggestIndex = -1;
int biggestDiff = -1;
while (index < sequence.size() - 1) // -1 so that the +1 below doesn't go out of range
{
// get the current difference
int currentDiff = std::abs(sequence[index] - sequence[index + 1]);
if (currentDiff > biggestDiff)
{
// update stats
biggestIndex = index;
biggestDiff = currentDiff;
}
++index;
}
return biggestIndex
}
int main() {
//…
int index = findLargest( sequence );
if ( index != -1 ) {
std::cout << "Biggest difference was between " << sequence[index] << " and " << sequence[index+1];
}
}

Print the solution to maximum sum of non-consecutive elements in an array

I'm trying to display the elements in an array that sum up to a max number and no two elements are consecutive(adjacent).
I figured out how to calculate the max sum by maintaining an inclusive and exclusive sum of the array elements. Is there any optimized way to capture all the elements that constitute the max sum and display it in reverse order
Code :
int i_sum = tickets[0];
int e_sum = 0;
int new_sum = 0
int sum = 0;
for (int i = 1; i < n; i++)
{
new_sum = (i_sum > e_sum) ? i_sum : e_sum;
i_sum = e_sum + tickets[i];
e_sum = new_sum;
}
(i_sum >= e_sum) ? std::cout << "incl " << i_sum : std::cout << "excl " << e_sum;
For example :
n = 8
array = [ 100 , -3 , 200 , 50 , 400 , -7 , 20 , 80 ]
max sum = 780
output :
80,400,200,100
And if both the inclusive and exclusive sum is alike the output would be the one with the greater element set.
Case :
n = 4
array = [4 , 5 , 4, 3]
max sum = 8
output : 4, 4
Should I maintain two different arrays to hold all the possible values, or insert them one at a time on each pass?
Thanks in advance.
Yes, you could maintain two arrays and copy and swap them at each step. However, that is not optimal. It will make your algorithm O(n2).
std::vector<int> incl, excl;
if (tickets[0] > 0)
incl.push_back(tickets[0]);
for (int i = 1; i < n; i++)
{
std::vector<int> temp;
if (i_sum > e_sum) {
new_sum = i_sum;
} else {
new_sum = e_sum;
temp = excl;
}
i_sum = e_sum + tickets[i];
e_sum = new_sum;
excl.push_back(tickets[i]);
std::swap(incl, excl);
if (temp.size())
excl = temp;
}
incl or excl will contain your solution depending whichever is larger.
I've made a small optimization using std::swap to use move semantics that avoids copies but when e_sum > i_sum, we can't avoid copying temp to excl.
Instead, formulating the same problem using dynamic programming, you can accomplish this in O(n). The idea is similar. Either you include the current element and add to the solution to max sum of second previous element or you exclude the current element to have the solution for the previous element. Code as follows:
vector <int> dp(n);
vector <int> parent(n, 0);
if (tickets[0] > 0) {
dp[0] = tickets[0];
parent[0] = tickets[0];
}
if (tickets[1] > 0) {
dp[1] = tickets[1];
parent[1] = tickets[1];
}
for (int i = 2; i < n ; i++) {
if (dp[i-1] > tickets[i] + dp[i-2]) {
dp[i] = dp[i-1];
} else {
dp[i] = tickets[i] + dp[i-2];
parent[i] = tickets[i];
}
}
cout << "Max sum: " << dp[n-1] << endl;
for(int i = n - 1; i >= 0;) {
if (parent[i]) {
cout << parent[i] << ' ';
i = i - 2;
} else {
i--;
}
}
parent vector can be utilized to trace back the steps taken for the dynamic programming solution.
As a side note, the solution mentioned in your question is slightly incorrect. If the first element is negative, you'd get an unoptimal result.

Shifting Objects Up in an Array

I'm creating a program that creates an array of objects in random positions in an array size 8. Once created, I need them to sort so that all the objects in the array are shifted up to the top, so no gaps exist between them. I'm almost there, but I cannot seem to get them to swap to index 0 in the array, and they instead swap to index 1. Any suggestions? (Must be done the way I'm doing it, not with other sorting algorithms or whatnot)
#include <iostream>
#include <string>
#include <ctime>
using namespace std;
struct WordCount {
string name = "";
int count = 0;
};
int main() {
cout << "Original random array: " << endl;
srand(static_cast<int>(time(0)));
int i = 0;
WordCount wordArr[8];
while (i < 4) {
int randomNum = 0 + (rand() % static_cast<int>(7 + 1));
if(wordArr[randomNum].name == "") {
wordArr[randomNum].name = "word" + static_cast<char>(i);
wordArr[randomNum].count = i;
i++;
}
}
int j = 0;
while (j < 8) {
cout << wordArr[j].name << " " << wordArr[j].count << endl;
j++;
}
cout << "\n\nSorted array: " << endl;
for (int i = 7; i >= 0; i--) {
for (int j = 0; j <= 7; j++) {
if (wordArr[i].name != "") {
if (wordArr[j].name == "") {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
}
}
}
}
int k = 0;
while (k < 8) {
cout << wordArr[k].name << " " << wordArr[k].count << endl;
k++;
}
return 0;
}
If I understand your requirement correctly, you want to move all the non-blank entries to the start of the array. To do this, you need an algorithm like this for example:
for i = 0 to 7
if wordArr[i].name is blank
for j = i + 1 to 7
if wordArr[j].name is not blank
swap [i] and [j]
break
So, starting from the beginning, if we encounter a blank entry, we look forward for the next non-blank entry. If we find such an entry, we swap the blank and non-blank entry, then break to loop again looking for the next blank entry.
Note, this isn't the most efficient of solutions, but it will get you started.
Note also I'd replace the 4 and 8 with definitions like:
#define MAX_ENTRIES (8)
#define TO_GENERATE_ENTRIES (4)
Finally:
wordArr[randomNum].name = "word" + static_cast<char>(i);
That will not do what you want it to do; try:
wordArr[randomNum].name = "word" + static_cast<char>('0' + i);
To append the digits, not the byte codes, to the end of the number. Or perhaps, if you have C++11:
wordArr[randomNum].name = "word" + std::to_string(i);
I see couple of problems.
The expression "word" + static_cast<char>(i); doesn't do what you are hoping to do.
It is equivalent to:
char const* w = "word";
char const* p = w + i;
When i is 2, p will be "rd". You need to use std::string("word") + std::to_string(i).
The logic for moving objects with the non-empty names to objects with empty names did not make sense to me. It obviously does not work for you. The following updated version works for me:
for (int i = 0; i <= 7; ++i) {
// If the name of the object at wordArr[i] is not empty, move on to the
// next item in the array. If it is empty, copy the next object that
// has a non-empty name.
if ( wordArr[i].name == "") {
// Start comparing from the object at wordArr[i+1]. There
// is no need to start at wordArr[i]. We know that it is empty.
for (int j = i+1; j <= 7; ++j) {
if (wordArr[j].name != "") {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
}
}
}
}
There was two problems as :
wordArr[randomNum].name = "word" + static_cast<char>(i); this is not what your are looking for, if you want that your names generate correctly you need something like this :
wordArr[randomNum].name = "word " + std::to_string(i);
Your sorting loop does not do what you want, it's just check for the "gaps" as you said, you need something like this :
for (int i = 0; i < 8; ++i) {
for (int j = i+1; j < 8; ++j) {
if (wordArr[i].name == "" || (wordArr[i].count < wordArr[j].count)) {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
}
}
}
Your algorithm sorts the array, but then looses the sorting again.
You want to swap elements only when i > j, in order to push elements to the top only. As a result, you need to change this:
if (wordArr[j].name == "")
to this:
if (wordArr[j].name == "" && i > j)
Consider this array example:
0
ord 1
0
0
rd 2
word 0
d 3
0
Your code will sort it to:
d 3
ord 1
word 0
rd 2
0
0
0
0
but when i = 3, it will try to populate the 5th cell, and it will swap it with rd 2, which is not what we want.
This will push rd 2 down, but we don't want that, we want gaps (zeroes) to go to the end of the array, thus we need to swap eleemnts only when they are going to go higher, not lower, which is equivalent to say when i > j.
PS: If you are a beginner skip that part.
You can optimize the inner loop by using one if statement and a break keyword, like this:
for (int j = 0; j <= 7; j++) {
if (wordArr[i].name != "" && wordArr[j].name == "" && i > j) {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
break;
}
}