Generate non-repetitive random numbers without array

I'm fairly new to c++ and I'm making a random number generator program.

Update:
I've already done the generator part but the program requires that the random numbers must never repeat. I'm not sure how to do that without arrays so i would prefer simple looping if possible. Any help is greatly appreciated! Here's what I have so far:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream> 
#include <cstdlib>
#include <ctime>
#include <Windows.h>


using namespace std;

class Numbers {
private: int rndNum, howmany, ctr, even, odd;
		 char repeat;
public:  void GenerateRandNum();
};

void Numbers::GenerateRandNum()
{
	do {
		cout << "How many random numbers would you like to generate (1-100)? ";
		cin >> howmany;
		cout << endl << " The " << howmany << " random numbers are: " << endl;

		srand(time(0));
		for (ctr = 1; ctr <= howmany; ctr++)
		{
			rndNum = rand() % 100 + 1;
			cout << rndNum << "\t";

			if (rndNum % 2 == 0)
			{
				even++;
				cout << "Even Numbers: " << even << endl;

			}
			else
			{
				odd++;
				cout << "Odd Numbers: " << odd << endl;
			}

			cout << endl << "Press [Y/y] to continue." << endl;
			cin >> repeat;
			repeat = toupper(repeat);
		}

		while (repeat == 'Y');
	}
}
	
	int main()
{
	Numbers obj;
	obj.GenerateRandNum();
	system("pause");
	return 0;
}
Last edited on
You need to initialize your even and odd to 0 first.
the random numbers must never repeat ... without arrays

If you don't store what you have already got, then you cannot know what you have already got. If you don't remember the past, then I can give you 7 every single time and you will know no repeat.


Where does the "without arrays" come from and what is its exact formulation?
okay but how do I insert an array into the existing code?
No arrays? How about a set?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream> 
#include <cstdlib>
#include <ctime>
#include <set>
#include <Windows.h>


using namespace std;

class Numbers {
private: int rndNum, howmany, ctr, even, odd;
		 char repeat;
public:  void GenerateRandNum();
};

void Numbers::GenerateRandNum()
{
        set<int> generatedNumbers;
	do {
		cout << "How many random numbers would you like to generate (1-100)? ";
		cin >> howmany;
		cout << endl << " The " << howmany << " random numbers are: " << endl;

		srand(time(0));
		for (ctr = 1; ctr <= howmany; ctr++)
		{
			rndNum = rand() % 100 + 1;
                        while (generatedNumbers.find(rndNum ) != generatedNumbers.end())
                        {
        			rndNum = rand() % 100 + 1;                         
                         }
                         generatedNumbers.insert(rndNum );
			cout << rndNum << "\t";

			if (rndNum % 2 == 0)
			{
				even++;
				cout << "Even Numbers: " << even << endl;

			}
			else
			{
				odd++;
				cout << "Odd Numbers: " << odd << endl;
			}

			cout << endl << "Press [Y/y] to continue." << endl;
			cin >> repeat;
			repeat = toupper(repeat);
		}

		while (repeat == 'Y');
	}
}
	
	int main()
{
	Numbers obj;
	obj.GenerateRandNum();
	system("pause");
	return 0;
}
Last edited on
@Repeater, that doesn't seem to be working, although I'm more familiar with an array than with a set
Last edited on
First I'm going to argue that you can not do that without restrictions.

If you have a random number from 1-100 and you create 101 random more numbers, something is going to repeat, and your program will probably crash if it tries to prevent it, so you have to have some kind of restriction.

There are several silly ways to do this so easy it will seem like magic...
Create a random number from 1-10, then 11-20, 21-30 and so on...
or
Create a random number that ends in 1, another that ends in 2-9....
or
Create the numbers, sort them and remove any duplicates.
or
Create the first number and always make sure the next number is smaller or larger.

You may argue this is not truly random, but what your doing to prevent any number from reappearing is also not truly random....
Insert random numbers into a set<int> S while S.size() < howmany.

Then, AFTER S has the requisite number (and NOT during attempted inserts, which might fail because of repeats) ...

Count the odd numbers in S. (The number of evens will be S.size() minus number of odds).
Last edited on
Seems your code as originally posted got the braces wrong on your do-while.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream> 
#include <cstdlib>
#include <ctime>
#include <set>


using namespace std;

class Numbers {
private: int rndNum, howmany, ctr, even, odd;
		 char repeat;
public:  void GenerateRandNum();
};

void Numbers::GenerateRandNum()
{
    set<int> generatedNumbers;
	do {
		cout << "How many random numbers would you like to generate (1-100)? ";
		cin >> howmany;
		cout << endl << " The " << howmany << " random numbers are: " << endl;

		srand(time(0));
		for (ctr = 1; ctr <= howmany; ctr++)
		{
			rndNum = rand() % 100 + 1;
                        while (generatedNumbers.find(rndNum ) != generatedNumbers.end())
                          {
        			            rndNum = rand() % 100 + 1;                         
                           }
                         generatedNumbers.insert(rndNum );
			cout << rndNum << "\t";

			if (rndNum % 2 == 0)
			{
				even++;
				cout << "Even Numbers: " << even << endl;

			}
			else
			{
				odd++;
				cout << "Odd Numbers: " << odd << endl;
			}

			cout << endl << "Press [Y/y] to continue." << endl;
			cin >> repeat;
			repeat = toupper(repeat);
		}
	}

	while (repeat == 'Y');

}
	
	int main()
{
	Numbers obj;
	obj.GenerateRandNum();
	system("pause");
	return 0;
}
Last edited on
There are two common approaches to this problem.

1. You remember each value that you generate. If you happen to generate a value that has already been generated you just repeat until you get a value that has not yet been generated. This often works great when you just want to generate a small number of values from a much larger range of possible values. It can be terribly slow though if there are very few possible numbers left because it gets more likely that it will have to loop many times before finding a value that has not yet been generated.

2. You generate all possible values up-front and just pick one at a time. You can either randomize all numbers from the start and then pick one after each other in order, or you can just leave all numbers in order and then pick (and remove) a value at random each time. This does not have the problem of degrading performance but if the range of possible numbers is large it will require a lot of memory.
Last edited on
Did anybody else notice how the question to continue is asked too soon?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream> 
#include <cstdlib>
#include <ctime>



using namespace std;

class Numbers {
private: int rndNum, howmany, ctr, even=0, odd=0;
		 char repeat;
public:  void GenerateRandNum();
};

void Numbers::GenerateRandNum()
{
    
	do {
		cout << "How many random numbers would you like to generate (1-100)? ";
		cin >> howmany;
		cout << endl << " The " << howmany << " random numbers are: " << endl;

		
		for (ctr = 1; ctr <= howmany; ctr++)
		{
			rndNum = rand() % 100 + 1;
			cout << rndNum << "\t";

			if (rndNum % 2 == 0)
			{
				even++;
				cout << "Even Numbers: " << even << endl;

			}
			else
			{
				odd++;
				cout << "Odd Numbers: " << odd << endl;
			}

			
		}
            cout << endl << "Press [Y/y] to continue." << endl;
			cin >> repeat;
			repeat = toupper(repeat);
		}while (repeat == 'Y');
	
}
	
	int main()
{
    srand(time(0));
	Numbers obj;
	obj.GenerateRandNum();
	system("pause");
	return 0;
}


Also pull the seed out of the loop. srand(time(0)) in main instead.
Here is my attempt at a complete solution. Let me know what you think.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream> 
#include <cstdlib>
#include <ctime>
#include <vector>


using namespace std;

class Numbers {
private: int rndNum, howmany, ctr, even = 0, odd = 0;
		 char repeat;
		 vector<int> results;
public:  void GenerateRandNum();
		 void clearVector();
};

void Numbers::clearVector() {
	while (!results.empty()) {
		results.pop_back();
	}
}

void Numbers::GenerateRandNum()
{	
	
	do {
		do {
			cout << "How many random numbers would you like to generate (1-100)? ";
			cin >> howmany;
		} while (howmany > 100 || howmany < 1);

		clearVector();
		for (int i = 0; i < howmany; i++) {
			results.push_back(0);
		}

		cout << endl << " The " << howmany << " random numbers are: " << endl;
		even = 0;
		odd = 0;
		for (ctr = 1; ctr <= howmany; ctr++)
		{
			rndNum = rand() % 100 + 1;
			for (int j = 0; j < results.size(); j++) {
				if (rndNum == results[j]) {
					rndNum = rand() % 100 + 1;
					j = -1;
				}
			}
			results[ctr - 1] = rndNum;
			cout << rndNum << "\t";

			if (rndNum % 2 == 0)
			{
				even++;
				cout << "Even Numbers: " << even << endl;

			}
			else
			{
				odd++;
				cout << "Odd Numbers: " << odd << endl;
			}


		}
		cout << endl << "Press [Y/y] to continue." << endl;
		cin >> repeat;
		repeat = toupper(repeat);
	} while (repeat == 'Y');

}

int main()
{
	srand(time(0));
	Numbers obj;
	obj.GenerateRandNum();
	system("pause");
	return 0;
}
Last edited on
[Edit: bitmap<> should have been bitset<>]

You don't need the clearVector() method. Just call results.clear() at line 32.

The way you check for duplicates is very inefficient. I'd create an array of 101 numbers, initialize it to zero and then if the RNG gives K, set array[K]. You might find that using a bitset<101> is faster. It will initialize faster, but accessing it takes a little more time.

Personally, I'd rearrange the code somewhat. I'd make the class generate random numbers from 1 to100 without repeats. That's all it would do. I'd move the code that interacts with the user and counts odd/even numbers into main.
Last edited on
Topic archived. No new replies allowed.