i have this CS question that says:
We will define a series two three to be a series whose first term is some natural number. If the value of the member number n in the series is x, then the value of the (n 1)th member in the series is: (x % 2 ==0) ? x/2 : x*3 1.
You must write a program that prints two or three series starting with the numbers 1 to twenty-five (not inclusive), but the creation of each series will stop when a value greater than a thousand or a value that has already appeared in a previous series is produced (and therefore the sub-series that was produced from this array onwards has already been produced). The value that is produced must be displayed again, thus stopping the production of the series.
now the code i have written outputs a similar result to the solution output but it needs some changes in order to get the same exact result which i couldn't figure out, this is my code.
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
int array[25];
for (int i = 1; i < 25; i )
{
int currentNum = i;
int theNumAfter;
bool occured = false;
while (occured == false)
{
for (int i = 0; i <= 25; i )
{
if (array[i] == currentNum)
{
occured = true;
cout << endl;
}
}
array[currentNum] = currentNum;
cout << currentNum << " ";
if (currentNum % 2 == 0)
{
theNumAfter = currentNum / 2;
}
else
{
theNumAfter = (3 * currentNum) 1;
}
array[theNumAfter] = theNumAfter;
cout << theNumAfter << " ";
currentNum = theNumAfter;
}
}
}
the code doesn't take any input and there is only one right output which should be this:
1 4 2 1
2
3 10 5 16 8 4
4
5
6 3
7 22 11 34 17 52 26 13 40 20 10
8
9 28 14 7
10
11
12 6
13
14
15 46 23 70 35 106 53 160 80 40
16
17
18 9
19 58 29 88 44 22
20
21 64 32 16
22
23
24 12
the result of my code:
1 4
4 2
2 1 3 10
10 5
4 2
5 16 6 3
3 10 7 22
22 11 8 4
4 2 9 28 28 14
14 7
10 5
11 34 12 6
6 3 13 40 40 20
20 10
14 7 15 46 46 23
23 70
16 8 17 52 52 26 26 13
13 40 18 9
9 28 19 58 58 29 29 88 88 44 44 22
22 11
what should i change in the code, so we have matching outputs. thanks in advance
CodePudding user response:
the creation of each series will stop when a value greater than a thousand or a value that has already appeared in a previous series is produced.
Up to 24, none of the produced values is greater than a thousand, but the posted code still has an access out of bounds bug:
int main()
{
int array[25];
// ^^
for (int i = 1; i < 25; i )
{
int currentNum = i;
int theNumAfter;
// ...
array[currentNum] = currentNum;
// ...
array[theNumAfter] = theNumAfter;
// ...
}
// ...
}
Note the many of numbers in the expected output are greater than 25.
I'm not sure what this part was supposed to achive:
for (int i = 0; i <= 25; i )
{ // ^^^^^^^ it "checks" only the first 25 values that may occur
if (array[i] == currentNum)
{
occured = true;
cout << endl; // <-- The duplicate should be printed before the newline.
// Here it should break out of the loop.
}
}
array[currentNum] = currentNum;
cout << currentNum << " ";
But it fails to produce the expected output.
I'd use a simple array of 1000 bool
s to memorize the already occurred numbers.
#include <iostream>
int main()
{
constexpr int limit{ 1'000 };
bool already_seen[limit 1]{};
for (int i = 1; i < 25; i )
{
int current{ i };
while ( current <= limit and not already_seen[current] )
{
std::cout << current << ' ';
already_seen[current] = true;
if ( current % 2 == 0)
{
current /= 2;
}
else
{
current = (3 * current) 1;
}
}
std::cout << current << '\n';
}
}
Testable here.
CodePudding user response:
A possible solution:
- Loop from
1
to24
. - Print each number, then each series for that number, and a newline.
- Each of the series finishes when 1) the current number is greater than 1000, or 2) the next number in the series is already known.
- I've used a
memo
struct to encapsulate the memoization code so that the main loop may look clearer. You wouldn't actually need to store what number is the next one in the series; you would do, for example, with a(n infamous)vector<bool>
.
#include <iostream> // cout
#include <vector>
class memo {
public:
explicit memo(int size) : v(size, -1) {}
bool is_set(int index) {
return index < std::ssize(v) and v[index] != -1;
}
void set(int current, int next) {
if (current < std::ssize(v)) {
v[current] = next;
}
}
private:
std::vector<int> v;
};
int main() {
constexpr int max_int_allowed{ 1000 };
constexpr int sentinel{ 25 };
memo m{ max_int_allowed 1 };
for (int i{ 1 }; i < sentinel; i ) {
auto current{ i };
std::cout << current;
while (current <= max_int_allowed and not m.is_set(current)) {
auto next{ ((current % 2 == 0) ? (current / 2) : (current * 3 1)) };
std::cout << " " << next;
m.set(current, next);
current = next;
}
std::cout << "\n";
}
}
Another option would be to not check for out of range accesses, catch those exceptions if there happened in the while
loop, and carry on with the for
loop.
#include <iostream> // cout
#include <stdexcept> // out_of_range
#include <vector>
class memo {
public:
explicit memo(int size) : v(size, -1) {}
bool is_set(int index) {
return v.at(index) != -1;
}
void set(int current, int next) {
v.at(current) = next;
}
private:
std::vector<int> v;
};
int main() {
constexpr int max_int_allowed{ 1000 };
constexpr int sentinel{ 25 };
memo m{ max_int_allowed 1 };
for (int i{ 1 }; i < sentinel; i ) {
auto current{ i };
std::cout << current;
try {
while (not m.is_set(current)) {
auto next{ ((current % 2 == 0) ? (current / 2) : (current * 3 1)) };
std::cout << " " << next;
m.set(current, next);
current = next;
}
} catch (const std::out_of_range& ex) {
// Do nothing
}
std::cout << "\n";
}
}