Random Permutation Generation - c

I am having a hard time understand this code example out of my text book. I hope someone can better explain a part of this code then my book. I am sorry for the lack of comments in this program so I will try my best to be very specific in what I am asking. Ok has the title suggest this program is a "Random Permutation Generation". Where I get confused in the code is in the function called bldPerm()
Function bldPerm():
void bldPerm(int randNos[])
{
int oneRandno;
int haveRand[ARY_SIZE] = { 0 };
for (int i = 0 ; i < ARY_SIZE; i++)
{
do
{
oneRandno = rand() % ARY_SIZE;
} while (haveRand[oneRandno] == 1);
haveRand[oneRandno] = 1;
randNos[i] = oneRandno;
}
return;
}
I don't understand how and why the do while loop while(haveRand[oneRandno]) == 1; checks the array by comparing it to 1. Then what confuses me is that haveRand[oneRandno] = 1; is set to one in that element. Then that element being "1" is set to randNos[i] = oneRandno; and returns other numbers other then 1. The program works out of my book and does print out other numbers then 1 yet I just can't see how it works. I have been trying to warp my head around this what I am sure is a simple thing... yet I don't get it. So my question is can anyone explain what is going on in this function in detail and how it works?
FULL CODE:
#define _CRT_SECURE_NO_WARNINGS
#define ARY_SIZE 20
#include <stdio.h>
#include <stdlib.h>
void bldPerm(int randNos[]);
void printData(int data[], int size, int linesSize);
int main(void)
{
int randNos[ARY_SIZE];
printf("Begin Random Permutation Generation\n");
bldPerm(randNos);
printData(randNos, ARY_SIZE, 10);
return 0;
}
void bldPerm(int randNos[])
{
int oneRandno;
int haveRand[ARY_SIZE] = { 0 };
for (int i = 0 ; i < ARY_SIZE; i++)
{
do
{
oneRandno = rand() % ARY_SIZE;
} while (haveRand[oneRandno] == 1);
haveRand[oneRandno] = 1;
randNos[i] = oneRandno;
}
return;
}
void printData(int data[], int size, int linesSize)
{
int numPrinted = 0;
printf("\n");
for (int i = 0; i < size; i++)
{
numPrinted++;
printf("%2d ", data[i]);
if (numPrinted >= linesSize)
{
printf("\n");
numPrinted = 0;
}
}
printf("\n");
return;
}

We want to fill an array with a random permutation of the numbers 0,...,ARY_SIZE-1. This means these number in a completely random ordering.
void bldPerm(int randNos[]) {
int oneRandno;
We keep an array called haveRand which indicates if the number i has already been chosen for our permutation. If the number is chosen haveRand[i] will be set to 1. At the beginning no number is chosen, so we initialize it with 0.
int haveRand[ARY_SIZE] = { 0 };
For each position in our output array we randomly select one of the numbers which have not been selected yet.
for (int i = 0 ; i < ARY_SIZE; i++)
{
Lets find a number which has not been selected yet.
do
{
To do this we sample any random number and call it oneRandno.
oneRandno = rand() % ARY_SIZE;
We check if it not chosen yet. If this is the case, then haveRand[oneRandno] is 0 and the while look will finish. Otherwise we continue and try a new.
} while (haveRand[oneRandno] == 1);
No we mark the selected number as chosen by setting haveRand[oneRandno] to 1.
haveRand[oneRandno] = 1;
Write the chosen number to the output array.
randNos[i] = oneRandno;
}
}
This algorithm is actually quite bad... For example to fill the last element there is only one candidate left as all other numbers are already selected. But the while loop tries to find this number by random sampling which can take a long time.
I would recommend creating an array with numbers 0 to ARY_SIZE-1 and use the Fisher-Yates algorithm to shuffle them.

I went through the code and wrote some comments with the code, i hope that clears it up.
void bldPerm(int randNos[]) // here you give an array of random numbers that is empty
{
// declare an int to store the randomly generated number
int oneRandno;
// initialize an array to store random numbers of size ARY_SIZE
int haveRand[ARY_SIZE] = { 0 };
// now loop while i is smaller then ARY_SIZE and increment i
for (int i = 0 ; i < ARY_SIZE; i++)
{
// here do generate the random number
do
{
// oneRandno will ALWAYS be between -1 and ARY_SIZE
// or i.o.w. from 0 to ARY_SIZE - 1
oneRandno = rand() % ARY_SIZE;
}
// because the numbers have to be unique, if oneRandno
// was already generated loop again
while (haveRand[oneRandno] == 1);
// Set to 1 because the next iteration oneRandno could have the same value,
// however very unlikely because rand() has a period of at least 2^32 which
// gives you enough room to have it generate a whole lot of numbers before
// it generates the same number again. So basically the while loop will
// never loop and act like a glorified if statement.
// and that the values in randNos should unique, if oneRandno has the
// same value the do while loop will iterate once more
// and generate another oneRandno
haveRand[oneRandno] = 1;
// finally store the uniquely generated number
randNos[i] = oneRandno;
//go to the next iteration
}
return;
}

Related

How to check for duplicates in random numbers [duplicate]

I tried generating 10 unique random numbers in C. I have an array numout[] for 10 numbers but this gets to "segmentation fault" after some time.
Tho code is:
int i,j,numout[10],randnum;
void main()
{
srand(time(NULL));
for(i=0;i<10;i++)
{
numout[i]=generate();
printf("%d",numout[i]);
fflush(stdout);
sleep(1);
printf("\b");
}
}
int generate()
{
randnum=1+(int)(rand()*mul_val/(RAND_MAX+1.0));
for(j=0;j<i;j++)
{
if(randnum==0 || randnum==numout[j])
{
randnum=generate();
}
}
return(randnum);
}
Throw that code away, seriously. You need a shuffling algorithm, not a piece of code that checks older values for duplicates. Doing it your way will end up taking longer and longer as your pool runs out. The advantage of a shuffling algorithm is that it doesn't degrade as the pool becomes smaller.
Here's a piece of code I used in answering a different question. It maintains a list of numbers and, when it returns a random one to you, it removes it from the list and decrements the count for the next random selection.
#include <stdio.h>
#include <stdlib.h>
#define ERR_NO_NUM -1
#define ERR_NO_MEM -2
int myRandom (int size) {
int i, n;
static int numNums = 0;
static int *numArr = NULL;
// Initialize with a specific size.
if (size >= 0) {
if (numArr != NULL)
free (numArr);
if ((numArr = malloc (sizeof(int) * size)) == NULL)
return ERR_NO_MEM;
for (i = 0; i < size; i++)
numArr[i] = i;
numNums = size;
}
// Error if no numbers left in pool.
if (numNums == 0)
return ERR_NO_NUM;
// Get random number from pool and remove it (rnd in this
// case returns a number between 0 and numNums-1 inclusive).
n = rand() % numNums;
i = numArr[n];
numArr[n] = numArr[numNums-1];
numNums--;
if (numNums == 0) {
free (numArr);
numArr = 0;
}
return i;
}
int main (void) {
int i;
srand (time (NULL));
i = myRandom (20);
while (i >= 0) {
printf ("Number = %3d\n", i);
i = myRandom (-1);
}
printf ("Final = %3d\n", i);
return 0;
}
A sample output shows it in action:
Number = 19
Number = 10
Number = 2
Number = 15
Number = 0
Number = 6
Number = 1
Number = 3
Number = 17
Number = 14
Number = 12
Number = 18
Number = 4
Number = 9
Number = 7
Number = 8
Number = 16
Number = 5
Number = 11
Number = 13
Final = -1
Call it with a non-negative pool size and it sets up a new sequence and returns the first random value. Following that, you can call it with -1 and it will get the next random, unique number from the pool. When the pool is exhausted, it will return -1.
The other answer that contained this code has a version that can maintain multiple pools as well if you want to be able to use this function in threaded code.
You will get a segmentation fault when you run out of stack space. Your code is recursive (i.e. generate() calls generate()). So when you run out of unused random numbers, it will call itself forever.
However, I will not recommend a fix for your code, because you really need to write it again from scratch. Follow paxdiablo's example.
If you need a large set of unique random numbers you should consider using LFSR approach. LFSR generates unique random numbers that does not repeat unless the entire pool is exhausted, so a 32-bit LFSR will generate 2^32 - 1 unique random numbers -- It does not generate 0. The coding is straight forward, look it up in google.
The program below stores n unique random numbers i.e, from [1 to n] in an array.
#include<iostream.h>
#include<conio.h>
void main()
{
int i, j, Array[100];
cout<<"Enter value of n : "; //upper limit
cin>>n;
randomize();
int rnd;
Array[1]=rand()%n+1;
for(i=2;i<=n;i++)
{
rnd=rand()%n+1;
for(j=1;j<i;j++)
{
if(rnd==Array[j])
{
i--;
break;
}
}
if(j>=i)
Array[i]=rnd;
}
//for printing from random numbers from 1 to n
for(i=1;i<=n;i++)
cout<<Array[i]<<"\n";
getch();
}

How can I use the rand() function to generate a different number that hasn't been generated before?

// What I mean by this is shown by my example:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int i;
int a;
for (a = 0;a <10;a ++) {
i = (rand()%10)+1; // generates a number from 1-10
printf("%d\n", i);
}
// I would like for the loop to generate a number that gives a number that was not generated before. For example, an output such as:
1,3,6,2,8,9,4,10,5,7
instead of:
3,9,10,3,7,9,2,7,10,1
In other words, I would like no copies.
You obviously don't just want no copies, but you want every number in a given set exactly once. This is, as commented by Robert, similar to shuffling a deck of cards. You don't have "decks" in C, but you can model one as an array:
int deck[] = {1,1,1,1,1,1,1,1,1,1};
This should represent 10 different "cards" (identified by their index in the array), each available one time. Now, just write code that "draws" cards:
int i = 0; // starting point for searching for the next card to draw
for (int n = 10; n > 0; --n) // how many cards are left
{
int skip = rand() % n; // randomly skip 0 .. n cards
while (1)
{
if (deck[i]) // card still available?
{
if (!skip) break; // none more to skip -> done
--skip; // else one less to skip
}
if (++i > 9) i = 0; // advance index, wrapping around to 0
}
deck[i] = 0; // draw the card
printf("%d\n", i+1); // and print it out
}
of course, seed the PRNG (e.g. srand(time(0))) first, so you don't get the same sequence every time.
The idea shown in the question is to print numbers within a range, without repetition. Here is one way to do that, by putting each value into an array and swapping its elements around.
A variation could be that you don't want to use all the possible numbers, in that case just change PICKED.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ARRLEN 10
#define PICKED 10
int main(void) {
int array[ARRLEN];
srand((unsigned)time(NULL)); // seed the PRNG
for(int i = 0; i < ARRLEN; i++) { // generate the numbers
array[i] = i + 1;
}
for(int i = 0; i < ARRLEN; i++) { // shuffle the array
int index = rand() % ARRLEN;
int temp = array[i];
array[i] = array[index]; // by randomly swapping
array[index] = temp;
}
for(int i = 0; i < PICKED; i++) { // output the numbers
printf("%d ", array[i]);
}
printf("\n");
}
Program output:
9 8 4 5 1 10 7 3 6 2
The library's PRNG is not very random, but for many cases that is not important. If it is, better algorithms are available.

What is wrong with my hash function?

I'm trying to create a hash table. Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define N 19
#define c1 3
#define c2 5
#define m 3000
int efort;
int h_table[N];
int h(int k, int i)
{
return (k + i*c1 + i*i*c2) % N;
}
void init()
{
for (int i = 0; i < N; i++)
h_table[i] = -1;
}
void insert(int k)
{
int position, i;
i = 0;
do
{
position = h(k, i);
printf("\n Position %d \n", position);
if (h_table[position] == -1)
{
h_table[position] = k;
printf("Inserted :elem %d at %d \n", h_table[position], position);
break;
}
else
{
i += 1;
}
} while (i != N);
}
void print(int n)
{
printf("\nTable content: \n");
for (int i = 0; i < n; i++)
{
printf("%d ", h_table[i]);
}
}
void test()
{
int a[100];
int b[100];
init();
memset(b, -1, 100);
srand(time(NULL));
for (int i = 0; i < N; i++)
{
a[i] = rand() % (3000 + 1 - 2000) + 2000;
}
for (int i = 0; i < N ; i++)
{
insert(a[i]);
}
print(N);
}
int main()
{
test();
return 0;
}
Hash ("h") function and "insert" function are took from "Introduction to algorithms" book (Cormen).I don't know what is happening with the h function or insert function. Sometimes it fills completely my array, but sometimes it doesn't. That means it doesn't work good. What am I doing wrong?
In short, you are producing repeating values for position often enough to prevent h_table[] from being populated after only N attempts...
The pseudo-random number generator is not guaranteed to produce a set of unique numbers, nor is your h(...) function guaranteed to produce a mutually exclusive set of position values. It is likely that you are generating the same position enough times that you run out of loops before all 19 positions have been generated. The question how many times must h(...) be called on average before you are likely to get the value of an unused position? should be answered. This may help to direct you to the problem.
As an experiment, I increased the looping indexes from N to 100 in all but the h(...) function (so as not to overrun h_table[] ). And as expected the first 5 positions filled immediately. The next one filled after 3 more tries. The next one 10 tries later, and so on, until by the end of 100 tries, there were still some unwritten positions.
On the next run, all table positions were filled.
2 possible solutions:
1) Modify hash to improve probability of unique values.
2) Increase iterations to populate h_table
A good_hash_function() % N may repeat itself in N re-hashes. A good hash looks nearly random in its output even though it is deterministic. So in N tries it might not loop through all the array elements.
After failing to find a free array element after a number of tries, say N/3 tries, recommend a different approach. Just look for the next free element.

Tried to code an integer compare method and it's not working

I have an array of integers and I'm trying to find which one is the highest and set a new integer to the highest ones value. I'm very new to C, I literally just started learning it.
There is probably some kind of logical problem with what I'm doing but I haven't been able to spot it yet. so...
int my_array[4];
int highest_int = 0;
int i;
for (i = 0; i < 4; i++) {
if (my_array[i] > my_array[i++]) {
if (my_array[i] > highest_int) {
highest_int = my_array[i];
}
}
else {
if (my_array[i++] > highest_int) {
highest_int = my_array[i++]
}
}
}
So I loop through my array 4 times (4 elements) and I look at the iteration value and the next one and if the iteration value is highest I check it's also higher than the current value of the current 'highest integer' and if it is I set the current highest integer to the new highest value. If the value after the iteration value is higher I do the same thing but with that value instead.
That's what went through my head when I wrote this but when I enter 4 values it always comes out with the 3rd value in the array. No matter what I set those values to.
Can anyone tell me why?
Thanks a lot.
Why you are incrementing i inside the loop? Why do you need the else part?
Here's a simple way:
int my_array[4];
int highest_int = my_array[0];
int i;
for (i = 1; i < 4; i++) {
if (my_array[i] > highest_int) {
highest_int = my_array[i];
}
}
You're making this way more complicated than it really is :) Furthermore, you're writing i++ in too many places; each time i++ gets executed you're skipping over an array entry, which is probably not what you want.
Also, there's no need to compare to the previous value. Just compare to the highest one you've seen so far.
Here's a fixed version, just by deleting code, nothing changed or added:
int my_array[4];
int highest_int = 0;
int i;
for (i = 0; i < 4; i++) {
if (my_array[i] > highest_int) {
highest_int = my_array[i];
}
}
Note that this incorrectly reports 0 if all numbers in the array are negative. Start off highest_int = INT_MIN in case you need to handle those correctly, or use unsigned int.
If you are trying to find the highest number, here is the code:
int my_array[4];
int highest_int = my_array[0];
//Before entering the loop, assuming the first number to highest
int i;
for (i = 1; i < 4; i++) {
if (my_array[i] > highest_int) { //Compare every number with highest number
highest_int = my_array[i];
}
}
//Now we have the highest number
printf("Highest Number: %d",highest_int);

C programming - A array and a random number combined question?

this is the part of my code I'm having trouble with. I can't understand why its doing it wrong. I have an array where it stores numbers 0 - 25 which are cases. The numbers are to be randomized and overwritten into the array. Only condition is is that no number can be doulbes, there can only be one of that number. I'm not asking you to do my code but do hint me or point me in the write directions. I am trying to learn :)
The problem lies within the second do loop. I can get the numbers to be randomized, but I get doubles. I have created a loop to check and fix this, but it's not working. The code does run, and doubles do still happen and I can't see why. It looks correct to me. Please look, thank you (:
This is what I have done originally (at the very end is where I am at now):
int check_double = 0;
int i = 0;
int counter = 0;
int array_adder = 0;
int random_number = 0;
int cases[] = {
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
};
float money[] = {
0.01,1,5,10,25,50,75,100,200,300,400,500,750,1000,5000,10000,25000,50000,750000,100000,200000,300000,400000,500000,750000,1000000
};
//Randomize all case number and realine them in the array
srand ( time(NULL) );
do
{
cases[counter]= rand() % 26;
counter += 1;
printf("%d\n", cases[counter]);
}
while (counter <= 25);
//make sure there are no doubles in the array, just 0 - 25 and not a single number repeated twice
do
{
check_double = 0;
for (i = 0; i < counter; i++)
{
if (cases[counter] == cases[i])
{
cases[counter] = rand()% 26;
check_double == 1;
}
}
}
while (check_double != 0);
Currently, what I had achived after that was combing both loops and check for doubles as the array goes. This is what I made, it still has doubles and im not sure why, I only posted the cose with both loops combined:
do
{
cases[counter]= rand() % 26;
if (cases[counter]>=1);
for(i=0;i<=counter;i++)
if (cases[counter]==cases[i])
{
cases[counter]=rand()% 26;
}
printf("%d\n",cases[counter]);
counter+=1;
}
Robsta, you could try the following piece of code, I have run this in Dev-C++, any changes that you require can be made from your side. But, I assure you that this code generates what you intend.
int check_double = 0;
int i = 0;
int counter = 0;
int cases[] = {
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
};
//Randomize all case number and realine them in the array
srand ( time(NULL) );
do
{
cases[counter]= rand() % 26;
for(i=0;i<counter;i++)
if (cases[counter]==cases[i]){
while (cases[counter]==cases[i])
{
cases[counter]=rand()% 26;
}
i=0;
}
printf("%d\t%d\n",counter,cases[counter]);
counter+=1;
}while (counter <= 25);
If you have any clarifications required, I would love to discuss with you.
-Sandip
You're only ever writing over the last value in the array:
for(i=0;i<counter;i++)
if (cases[counter]==cases[i])
You need to loop through as you are, then have an inner loop, where you compare all the other entries to the current one.
Even easier would be to do the loop where you set each random number, so when you set cases[3] for example, loop from 0 to 2 and check to see if your new value for 3 clashes, if so, wash - rinse - repeat!
You have this line of code:
check_double==1;
That doesn't change check_double because it's ==, not =. == compares; it doesn't assign. Change that line to this:
check_double=1;
A helpful compiler (clang in this example) will give you a warning about this:
test.c:5:14: warning: expression result unused [-Wunused-value]
check_double==1;
~~~~~~~~~~~~^ ~
You can't check for duplicates with a single loop. You need to at least compare every possible pair of elements to be able to see if there's a duplicate. I'm guessing you forgot to loop over counter somewhere inside the second do...while?
Note that your method is not guaranteed to terminate. (Very, very likely but not certain.) Why don't you simply shuffle the cases array? Shuffling is simple but tricky; see Fisher-Yates (or Knuth) Shuffle for a simple algorithm.
If you are asking how to randomly sequence the number 1-25 then you could do something like this. This is a very brute-force way of generating the sequence, but it does work and might give you a starting point for something more optimized.
#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <conio.h>
const int LastNumber = 25;
bool HasEmpty(int available[LastNumber][2])
{
bool result = false;
for(int i = 0; i < LastNumber; i++)
{
if (available[i][1] == 0)
{
result = true;
break;
}
}
return result;
}
int _tmain(int argc, _TCHAR* argv[])
{
int available[LastNumber][2];
int newSequence[LastNumber];
srand((unsigned int)time(NULL));
for(int i = 0; i < LastNumber; i++)
{
available[i][0]=i;
available[i][1]=0;
}
int usedIndex = 0;
while (HasEmpty(available))
{
int temp = rand() % (LastNumber + 1);
if (available[temp][1] == 0)
{
newSequence[usedIndex++] = available[temp][0];
available[temp][1] = 1;
}
}
for(int i = 0; i < LastNumber; i++)
{
printf("%d\n",newSequence[i]);
}
getch();
return 0;
}

Resources