[vox-tech] shuffling arrays in C?

Peter Jay Salzman vox-tech@lists.lugod.org
Mon, 25 Nov 2002 11:49:29 -0800


begin Alexandra Thorn <amthorn@ucdavis.edu> 
> 
> I've been looking around for a C library function that will shuffle the
> elements of an arbitrarily long array.  I'd been hoping to turn up
> something that would randomly shuffle the elements of an array.  The array
> that I want to shuffle is made up of a class of structs that I've created.
> 
> A few hours of googling and fiddling with the man pages hasn't shed too
> much light on the issue

after a few hours, any solution is better than googling!   (-:

here's some code i quickly whipped up.   it's not the best code you can
write, but i just wanted to show an algorithm.  there are many
permutations you can make on the same algorithm; some better than
others.

i apologize if there's a mistake here.  i ran it once to make sure the
output looked sane.   looked random to me.   (-:


pete


ps- some newlines in case you don't want an answer right away.

















#include <stdio.h>
#include <stdlib.h>
unsigned int SeedRandomGenerator(void);
int Irand(int low, int high);

/* Example of shuffling an integer array.  We are going to take elements of
 * of from[], shuffle them, and place them into to[].   We're also going to
 * use another array, been_there[] to keep track of which elements of to[]
 * are free to accept an element of to[].
 *
 * There are many many ways to optimize this code, but this is simply an
 * example of the algorithm.
 */




int main(void)
{

	int n = 5;
	int i, from[n], to[n], been_there[n], myrand;
	unsigned int seed;


	/* Seed the random number generator */
	seed = SeedRandomGenerator();
	printf("seed is %u\n", seed);
	

	/* initialize from[] and been_there[].   if been_there[j] == 0, then
	 * we haven't put anything in to[j].   if been_there[j] == 1, then
	 * we've already put something in to[j].
	 */
	for (i=0; i<n; ++i) {
		from[i] = i;
		been_there[i] = 0;
	}


	/* Loop over each element of from[]. */
	for (i=0; i<n; ++i)
	{

		// Pick one of the empty slots of to[].
		do {
			myrand = Irand(0, n-1);
		} while (been_there[myrand] == 1);

		// Make a note that this element of to[] has been filled
		been_there[myrand] = 1;
		
		// Switch the elements
		to[myrand] = from[i];
	}

	// Print the results side by side.
	for (i=0; i<n; ++i)
		printf("%d   %d\n", from[i], to[i]);

	return 0;
}



/*  Seed the random number generator
 */
unsigned int SeedRandomGenerator(void)
{  
	FILE *fp;
	unsigned int seed;
	size_t retval;  

	if((fp = fopen("/dev/random", "r")) == NULL) {
		fprintf(stderr, "Can't open /dev/random for reading.");
		exit(0);
	}

	retval = fread(&seed, 1, sizeof(unsigned int), fp);

	if (retval != sizeof(unsigned int)) {
		fprintf(stderr, "SeedRandomGenerator: fread wanted %d but got %d",
			sizeof(unsigned int), retval);
		exit(0);
	}

	fclose(fp);

	srand(seed);
	return(seed);
}



/*  Returns an integer between high and low (inclusive)
 */
int Irand(int low, int high)
{
	return low + (int)( (double)(high-low+1) * rand()/(RAND_MAX + 1.0) );
}