Say you want to generate 1,000 unique random numbers and present them to some code one at a time. When you exhaust those numbers, you want to present the same numbers again, but in a different sequence.
To generate the numbers, use a hash table. In C#, it would look like this:
const int MaxNumbers = 1000;
HashSet<int> uniqueNumbers = new HashSet<int>();
Random rnd = new Random();
// generate random numbers until there are 1000 in the hash table
while (uniqueNumbers.Count < MaxNumbers)
{
    uniqueNumbers.Add(rnd.Next());
}
// At this point you have 1,000 unique random numbers
// Put them in an array
int[] myNumbers = uniqueNumbers.ToArray();
This works because the HashSet.Add method rejects duplicates. And it's very fast because lookup in the hash table is O(1).
Now, you can serve them by setting a current index at 0 and increment it every time a number is requested. Something like:
int ixCurrent = 0;
int GetNextNumber()
{
    if (ixCurrent < MaxNumbers)
    {
        ++ixCurrent;
        return myNumbers[ixCurrent-1];
    }
But what to do when ixCurrent runs off the end of the array? Enter the Fisher-Yates Shuffle:        
    // out of numbers. Shuffle the array and return the first one.
    for (int i = MaxNumbers-1; i > 0; --i)
    {
        int j = rnd.Next(i+1);
        int temp = myNumbers[i];
        myNumbers[i] = myNumbers[j];
        myNumbers[j] = temp;
    }
    ixCurrent = 1;
    return myNumbers[0];
}
If you know that the numbers you want to return are within a particular range (that is, you want to return the numbers 0-999 in random order), then you just fill an array with the values 0-999 and shuffle it.