-5

I would like to have a combination between a Perfect Hash Function and a random number generator.

It would be used to map an integer between 1 and 5000 to an integer between 1 and 5000 and it must be injective (no two inputs can have the same output and vice versa).

For example:

INPUT    OUTPUT
1        1542
2        73
3        4600
1000     201
2        73
1        1542

Thanks in advance.

EDIT:

I first tried to use several of the hashing functions from wikipedia, but they all have problems.

  • 3
    An interesting thing to try and do, but are you hoping there is a class out there that magically does this? Are you trying to get us to do your homework for you? This doesn't show any effort (research or otherwise). – BradleyDotNET May 29 '14 at 21:34
  • @BradleyDotNET definitely sounds like a homework question to me – Chancho May 29 '14 at 21:37
  • I'm sorry. No this is not homework. I'm not hoping to get a class that magically does this, I was just wondering if there was an easy way to do this, or maybe a hint in the right direction. I will update with more research. – user2642253 May 29 '14 at 21:39
  • 4
    Populate an array with sequential values and than shuffle or [derange](http://stackoverflow.com/q/7279895/10077) it. – Fred Larson May 29 '14 at 21:42
  • @FredLarson No, this would not work because I do not have all numbers beforehand. (And to generate 5000 numbers when I only need 10 or 20 of them would be too inefficiënt.) – user2642253 May 29 '14 at 21:58

1 Answers1

1

Try something like this:

public class RandomHash
{
    private readonly Dictionary<int, int> _mydictionary;
    private List<int> _usedNumbers;
    private readonly Random _rnd;
    private readonly int _size;

    public RandomHash(int size)
    {
        _mydictionary = new Dictionary<int, int>();
        _usedNumbers = new List<int>();
        _rnd = new Random(100); // magic seed
        _size = size;
    }

    public int HashNumber(int num)
    {
        if (_mydictionary.ContainsKey(num))
            return _mydictionary[num];

        int n = _rnd.Next(1, _size);
        while (n == num || _mydictionary.ContainsKey(n))
        {
            n = _rnd.Next(1, _size);
        }
        _mydictionary.Add(num, n);

        return n;
    }
}

The magic here is that I'm seeding the Random class with a constant number, 100. This guarantees that the same numbers will hash to the same "random" number. Use it like this:

   static void Main(string[] args)
    {
        var rh = new RandomHash(5000);

        Console.WriteLine(rh.HashNumber(1));
        Console.WriteLine(rh.HashNumber(2));
        Console.WriteLine(rh.HashNumber(3));
        Console.WriteLine(rh.HashNumber(1000));
        Console.WriteLine(rh.HashNumber(2));
        Console.WriteLine(rh.HashNumber(1));
        Console.WriteLine();            
    }
Icemanind
  • 47,519
  • 50
  • 171
  • 296
  • So it is not possible to use a direct mapping? This would definitly work, but it seems like this is a very costly way of doing it, since it has to check what numbers already have been generated. – user2642253 May 29 '14 at 21:56
  • 1
    No there isn't. But .NET's `Dictionary<>`'s `ContainsKey` search is very quick! For 5000 numbers, we are talking milliseconds, if that. – Icemanind May 29 '14 at 22:01