Basically I am relearning C++ and decided to create a lotto number generator.
The code creates the ticket and if that ticket does not already exist, it is added to a vector to store every possible combination.
The program works, but its just far too slow, adding an entry roughly every second, and It will get slower as it finds it more difficult to add unique combinations out of over 13 million possible combinations.
Anyway here is my code, any optimization tips would appreciated:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
using namespace std;
vector<string> lottoCombos;
const int NUMBERS_PER_TICKET = 6;
const int NUMBERS = 49;
const int POSSIBLE_COMBOS = 13983816;
string createTicket();
void startUp();
void getAllCombinations();
int main()
{
lottoCombos.reserve(POSSIBLE_COMBOS);
cout<< "Random Ticket: "<< createTicket()<< endl;
getAllCombinations();
for (int i = 0; i < POSSIBLE_COMBOS; i++)
{
cout << endl << lottoCombos[i];
}
system("PAUSE");
return 0;
}
string createTicket()
{
srand(static_cast<unsigned int>(time(0)));
vector<int> ticket;
vector<int> numbers;
vector<int>::iterator numberIterator;
//ADD AVAILABLE NUMBERS TO VECTOR
for (int i = 0; i < NUMBERS; i++)
{
numbers.push_back(i + 1);
}
for (int j = 0; j < NUMBERS_PER_TICKET; j++)
{
int ticketNumber = rand() % numbers.size();
numberIterator = numbers.begin()+ ticketNumber;
int nm = *numberIterator;
numbers.erase(numberIterator);
ticket.push_back(nm);
}
sort(ticket.begin(), ticket.end());
string result;
ostringstream convert;
convert << ticket[0] << ", " << ticket[1] << ", " << ticket[2] << ", " << ticket[3] << ", " << ticket[4] << ", " << ticket[5];
result = convert.str();
return result;
}
void getAllCombinations()
{
int i = 0;
cout << "Max Vector Size: " << lottoCombos.max_size() << endl;
cout << "Creating Entries" << endl;
while ( i != POSSIBLE_COMBOS )
{
bool matchFound = true;
string newNumbers = createTicket();
for (int j = 0; j < lottoCombos.size(); j++)
{
if ( newNumbers == lottoCombos[j] )
{
matchFound = false;
break;
}
}
if (matchFound != false)
{
lottoCombos.push_back(createTicket());
i++;
cout << "Entries: "<< i << endl;
}
}
sort(lottoCombos.begin(), lottoCombos.end());
cout << "\nCombination generation complete!!!\n\n";
}
The reason each lottery ticket is taking a second to generate is because you are misusing srand(). By calling srand(time(0)) every time createTicket() is called, you ensure that createTicket() returns the same numbers every time it is called, until the next time the value returned by time() changes, i.e. once per second. So your reject-duplicates algorithm will almost always find a duplicate until the next second goes by. You should move your srand(time(0)) call to the top of main() instead.
That said, there are perhaps larger issues to confront here: my first question would be, is it really necessary to generate and store every possible lottery ticket? (and if so, why?) IIRC real lotteries don't do that when issuing a ticket; they just generate some random numbers and print them out (and if there are multiple winning tickets printed with the same numbers, the owners of those tickets share the prize money).
Assuming you do need to generate every possible lottery ticket for some reason, there are better ways to do it than randomly. If you've ever watched the odometer increment while driving a car, you'll get the idea for how to do it linearly; just imagine an odometer with 6 wheels, where each wheel has 49 different possible positions it can be in (rather than the traditional 10).
Finally, a vector has O(N) lookup time, and if you are doing a lookup in the vector for every value you generate, then your algorithm has O(N^2) time, which is to say, it's going to get really slow really quickly as you generate more tickets. So if you have to store all known tickets in a data structure, you should definitely use a data structure with quicker lookup times, for example a std::map or a std::unordered_set, or even a std::bitset as suggested by #RedAlert.
Related
I have started studying arrays and have just started making some practice but I am having some problems with using loops to name the elements inside of a specific array.
I was trying to make this piece of code that assigned the numbers from 1 up to 12(to resemble the months of the year) to the ints inside of the array, this is what I came up with:
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
int array[12];
for (int i = 0; i < 12;) {
cout << "Month number " << i + 1 << endl;
array[i] = (i++);
}
return 0;
}
What I don't like about this is the fact that I had to leave the increment/decrement space inside of the for loop empty. I had initially tried making the code look something like this:
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
int array[12];
for (int i = 0; i < 12; i++) {
cout << "Month number " << i + 1 << endl;
array[i] = i++;
}
return 0;
}
But this way, even if the first element of the array came out correct, the subsequent ones didn't. I think the reason for this is that the i++ in the last statement of the loop makes the value of i increment but I couldn't find a way around it without having to add another line with i-- or doing as I did in the first code I posted.
Could anyone offer me a hand in understanding how to make it so that i can store the value of i, incremented by one, inside of that specific array element, without incrementing it for the whole loop(if it is possible)?
I know there are ways around it, just like I showed in the first code i posted, but it's something that's bugging me and so I would like to make it more visually pleasing.
Please, keep in mind that I am just a beginner :)
Thanks in advance for the answers, and sorry for the long question.
Edit: Apparently, coding like this:
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
int array[12];
for (int i = 0; i < 12; i++) {
cout << "Month number " << i + 1 << endl;
array[i] = i + 1;
}
cout << array[4] << endl;
return 0;
}
makes it so that the program works correctly and looks like I wanted, but I can't comprehend why it does :(
Edit 2: Apparently, as UnholySheep pointed out, I missed on the fact that + 1 does not modify the value of the integer, while ++ does.
Thanks to everyone that answered and explained how ++ and +1 work!
Simply do i+1 again.
for (int i = 0; i < 12; i++)
{
cout << "Month number " << i + 1 << endl;
array[i] = i + 1;
}
Now it's obvious you actually want to start at 1 and go to 12, so this seems somewhat better with less repetition:
for (int i = 1; i <= 12; i++)
{
cout << "Month number " << i << endl;
array[i-1] = i;
}
EDIT: As for your edit, the reason why this works is because i++ operator works on the particular i variable. It increments that existing i by one, making it so that the next time you access i, it will be 1 more than it was before.
Writing i+1, on the other hand, creates a completely new, temporary, variable (actually a constant). So when you write
array[i] = i+1;
you're saying that you want i to remain unchanged, but you want to create a new number, one bigger than i, and put that new number into the array.
You can even write it out longer to be completely explicit:
int newNumber = i+1;
array[i] = newNumber;
for (int i = 0; i < 12; i++) {
cout << "Month number " << i + 1 << endl;
array[i] = i+1;
}
No reason to increment i in the loop
I'm trying to convert a for loop to while loop in c++ and do some checking for duplicates in a random number generator for generating lotto numbers so far all the stuff i'm trying seems to make the compiler very unhappy and I could really use a few pointers. It's the for loop in the Harray() function that feeds the Balls[] array
that i want to convert to a while loop.
#include<iostream>
#include<cstdlib> // to call rand and srand.
#include<ctime> // to make rand a bit more random with srand(time(0)) as first call.
#include<iomanip> // to manipulate the output with leading 0 where neccesary.
using namespace std;
// Hrand() function create and return a random number.
int Hrand()
{
int num = rand()%45+1; // make and store a random number change 45 for more or less Balls.
return num; // return the random number.
}
// Harray() function create and fill an array with random numbers and some formatting.
void Harray()
{
int Balls[6]; // change the number in Balls[6] and in the for loop for more or less nrs. a row.
for(int x=0; x<=6; x++) //the loop to fill array with random numbers.
{
int a; // made to pass the Balls[x] data into so i can format output.
int m = Hrand(); // calling the Hrand() function and passing it's value in int m.
Balls[x] = m; // throwing it into the array tought i did this because of an error.
a = Balls[x]; // throwing it into int a because of an type error.
cout<<"["<<setfill('0')<<setw(02)<<a<<"]"; //format output with leading 0 if neccesary.
}
cout<<endl; // start new row on new line.
}
// Main function do the thing if compiler swallows the junk.
int main() // start the program.
{
int h; // int to store user cchoice.
srand(time(0)); // make rand more random.
cout<<"How many rows do you want to generate?"<<endl; // ask how many rows?
cin>>h; // store user input.
for(int i=h; h>0; h--) // produce rows from user input choice.
{
Harray(); // calling Harray function into action.
}
return 0; // return zero keep the comipler happy.
}
I would like to always have six diffrent numbers in a row but i don't see how to get there with the for loops i think the while loop is way to go but am open to any suggestion that will work. I'm just starting with c++ i might have overlooked some options.
int x=0;
while(x<6)
{
int a;format output.
int m = Hrand();value in int m.
Balls[x] = m; because of an error.
a = Balls[x];
cout<<"["<<setfill('0')<<setw(02)<<a<<"]";
x++;
}
Here, I also fixed a bug. Since Balls has 6 elements, the last element will be 5. Thus you want x<6 instead of x<=6. That goes for the for loop too.
One drawback of while loops is that you cannot declare local variables with them.
First of all, you should realize that the difference between a for loop and a while loop is mostly syntactic--anything you can do with one, you can also do with the other.
In this case, given what you've stated as your desired output, what you probably really want is something like this:
std::vector<int> numbers;
std::set<int> dupe_tracker;
while (dupe_tracker.size() < 6) {
int i = Hrand();
if (dupe_tracker.insert(i).second)
numbers.push_back(i);
}
The basic idea here is that dupe_tracker keeps a copy of each number you've generated. So, you generate a number, and insert it into the set. That will fail (and return false in retval.second) if the number is already in the set. So, we only add the number to the result vector if it was not already in the set (i.e., if it's unique).
How convert for-loop to while-loop
#include <iostream>
class T545_t
{
// private data attributes
int j;
public:
int exec()
{
// A for-loop has 3 parameters, authors often fill 2 of them with magic
// numbers. (magic numbers are usually discouraged, but are expected
// in for-loops)
// Here, I create names for these 3 for-loop parameters
const int StartNum = 2;
const int EndNum = 7;
const int StrideNum = 2;
std::cout << std::endl << " ";
for (int i = StartNum; i < EndNum; i += StrideNum ) {
std::cout << i << " " << std::flush;
}
std::cout << std::flush;
// A while-loop must use / provide each of these 3 items also, but
// because of the increased code-layout flexibility (compared to
// for-loop), the use of magic numbers should be discouraged.
std::cout << std::endl << " ";
j = StartNum;
do {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
} while(true);
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(true) {
if (j >= EndNum) break;
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::flush;
std::cout << std::endl << " ";
j = StartNum;
while(j < EndNum) {
std::cout << j << " " << std::flush;
j += StrideNum;
}
std::cout << std::endl;
return 0;
}
}; // class T545_t
int main(int , char** )
{
T545_t t545;
return(t545.exec());
}
Ask me where 'j' is declared?
This code is marked as C++, so in this case, I have declared 'j' in the private data attribute 'section' of this class definition. That is where you'd look for it, right?
If your c++ code does not have class, what's the point?
I have this program to write that I have a array of 11 numbers entered from me. Then I need to find the avarage sum of those numbers, and then im asked to find the closest number of this array to the avarage sum, and then the most distant element of the array to the avarage sum again. SO far I manage to write a program to create this array and find the avarage sum. I asssume there is something to do with abs function of cmath libary , but so far I only fail to make it.
#include <iostream>
using namespace std;
int main() {
unsigned const int size = 11;
float number[size];
for (unsigned i = 0; i<size; i++) {
cout << "Please enter value for number "
<< i + 1 << ":";
cin >> number[i];
}
for (unsigned i = 0; i<size; i++) {
cout << "Number " << i + 1 << " is : "
<< number[i] << endl;
}
unsigned int sum = 0;
for (unsigned i = 0; i<size; i++) {
sum += number[i];
}
What is the problem? You are not asking a question, just making a statement... It does seem that you have not posted the whole code..
In c++ usually to use "abs" you should use fabs from the "math.h" library!
You will be okay with the compare operators.
Just traverse your array in a loop and calculate the difference between your compare value and the current value on your array. Initiate a temporary variable that keeps the array entry that created the smallest difference.
Every time a difference that is smaller than the current one comes up replace the value in your temporary variable.
So you replace under the following condition: If |number[i] - average_value| < |tmp_closest_val -average_val| Then tmp_closest_val = number[i] EndIf.
I hope you get the concept from that rough draft.
I'm trying to make a program that will eventually show the runtime differences with large data inputs by using a binary search tree and a vector. But before I get to that, I'm testing to see if the insertion and search functions are working properly. It seems to be fine but whenever I assign SIZE to be 30 million or more, after about 10-20 seconds, it will only display Press any key to continue... with no output. However if I assign SIZE to equal to 20 million or less, it will output the search results as I programmed it. So what do you think is causing this problem?
Some side notes:
I'm storing a unique, (no duplicates) randomly generated value into the tree as well as the vector. So at the end, the tree and the vector will both have the exact same values. When the program runs the search portion, if a value is found in the BST, then it should be found in the vector as well. So far this has worked with no problems when using 20 million values or less.
Also, I'm using randValue = rand() * rand(); to generate the random values because I know the maximum value of rand() is 32767. So multiplying it by itself will guarantee a range of numbers from 0 - 1,073,741,824. I know the insertion and searching methods I'm using are inefficient because I'm making sure there are no duplicates but it's not my concern right now. This is just for my own practice.
I'm only posting up my main.cpp for the sake of simplicity. If you think the problem lies in one of my other files, I'll post the rest up.
Here's my main.cpp:
#include <iostream>
#include <time.h>
#include <vector>
#include "BSTTemplate.h"
#include "functions.h"
using namespace std;
int main()
{
const long long SIZE = 30000000;
vector<long long> vector1(SIZE);
long long randNum;
binarySearchTree<long long> bst1;
srand(time(NULL));
//inserts data into BST and into the vector AND makes sure there are no duplicates
for(long long i = 0; i < SIZE; i++)
{
randNum = randLLNum();
bst1.insert(randNum);
if(bst1.numDups == 1)//if the random number generated is duplicated, don't count it and redo that iteration
{
i--;
bst1.numDups = 0;
continue;
}
vector1[i] = randNum;
}
//search for a random value in both the BST and the vector
for(int i = 0; i < 5; i++)
{
randNum = randLLNum();
cout << endl << "The random number chosen is: " << randNum << endl << endl;
//searching with BST
cout << "Searching for " << randNum << " in BST..." << endl;
if(bst1.search(randNum))
cout << randNum << " = found" << endl;
else
cout << randNum << " = not found" << endl;
//searching with linear search using vectors
cout << endl << "Searching for " << randNum << " in vector..." << endl;
if(containsInVector(vector1, SIZE, randNum))
cout << randNum << " = found" << endl;
else
cout << randNum << " = not found" << endl;
}
cout << endl;
return 0;
}
(Comments reposted as answer at OP's request)
Options include: compile 64 bit (if you're not already - may make it better or worse depending on whether RAM or address space are the issue), buy more memory, adjust your operating system's swap memory settings (letting it use more disk), design a more memory-efficient tree (but at best you'll probably only get an order of magnitude improvement, maybe less, and it could impact other things like performance characteristics), redesign your tree so it manually saves data out to disk and reads it back (e.g. with an LRU).
Here's a how-to for compiling 64 bit on VC++: msdn.microsoft.com/en-us/library/9yb4317s.aspx
I have been trying to understand this code for hours unsuccessfully. I wrote my own version of bead sort algorithm however it is so slow.
I want to understand why this one works so much more quickly.
Here's info about the bead sort algorithm:
http://demonstrations.wolfram.com/ExtendedBeadSort/
Can you please help me to understand how this algorithm works?
#include <iostream>
#include <vector>
using std::cout;
using std::vector;
void distribute(int dist, vector<int> &List) {
//*beads* go down into different buckets using gravity (addition).
if (dist > List.size() )
List.resize(dist); //resize if too big for current vector
for (int i=0; i < dist; i++)
List[i]++;
}
vector<int> beadSort(int *myints, int n) {
vector<int> list, list2, fifth (myints, myints + n);
cout << "sakums\n";
cout << myints<< "\n";
// for (vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it) cout << " " << *it << "\n";
cout << "beigas\n";
cout << "#1 Beads falling down: ";
for (int i=0; i < fifth.size(); i++)
distribute (fifth[i], list);
cout << '\n';
cout << "\nBeads on their sides: ";
for (int i=0; i < list.size(); i++)
cout << " " << list[i];
cout << '\n';
//second part
cout << "#2 Beads right side up: ";
for (int i=0; i < list.size(); i++)
distribute (list[i], list2);
cout << '\n';
return list2;
}
int main() {
int myints[] = {734,3,1,24,324,324,32,432,42,3,4,1,1};
vector<int> sorted = beadSort(myints, sizeof(myints)/sizeof(int));
cout << "Sorted list/array";
for(unsigned int i=0; i<sorted.size(); i++)
cout << sorted[i] << ' ';
system("PAUSE");
return 0;
}
Its my implementation! I am the original author for the bead sort in C++ that you see on rosettacode.
The reason that the algorithm is so slow is because this sort has three major slowdown issues. One deals with the potential resize of the vector every time distribute runs O(S). This also is combined with the actual adding of the numbers one by one down each "pole" O(S)+O(S) or O(2S) and then doing this n times where n is the numbers to be sorted O(n)+O(2S). Since S is still larger in most cases, the algorithm is still O(S).
To be fair, all it will take is someone making a better implementation and less verbose version of my code to improve performance. I made this algorithm this way to showcase as easily as possible for people new to bead sort.
Also check the wiki page of bead sort if you wish to learn more about it.
Because of how distribute works:
Each of the other numbers contribute "beads" to the slots - there are 13 numbers so slot 1 has 13 in it when it finishes the first pass.
it "distributes" beads in "columns" I.e when you print it on its side, there are now 734 slots - the largest number.
When distribute runs again it shifts the "beads" down by summing the columns - it will perform a number of additions dependent on the max element * The number of numbers - plus memory allocations