Tutorial :Find the lowest unused number



Question:

I've setup a std map to map some numbers, at this point I know what numbers I'm mapping from an to, eg:

std::map<int, int> myMap;    map[1] = 2;  map[2] = 4;  map[3] = 6;  

Later however, I want to map some numbers to the lowest number possilbe that is not in the map, eg:

map[4] = getLowestFreeNumberToMapTo(map); // I'd like this to return 1  map[5] = getLowestFreeNumberToMapTo(map); // I'd like this to return 3  

Any easy way of doing this?

I considered building an ordered list of numbers as I added them to the map so I could just look for 1, not find it, use it, add it etc.


Solution:1

Something like

typedef std::set<int> SetType;  SetType used;           // The already used numbers  int freeCounter = 1;    // The first available free number    void AddToMap(int i)  {      used.insert(i);      // Actually add the value to map  }    void GetNewNumber()  {      SetType::iterator iter = used.lower_bound(freeCounter);      while (iter != used.end() && *iter == freeCounter)      {          ++iter;          ++freeCounter;      }      return freeCounter++;  }  

If your map is quite big but sparse, this will work like o(log(N)), where N is the number of items in the map - in most cases you won't have to iterate through the set, or just make a few steps. Otherwise, if there are few gaps in the map, then you would better have a set of free items in the range [1..maxValueInTheMap].


Solution:2

Finding the lowest unused number is a very common operation in UNIX kernels, as every open/socket/etc. syscall is supposed to bind to the lowest unused FD number.

On Linux, the algorithm in fs/file.c­#alloc_fd is:

  • keep track of next_fd, a low water mark -- it is not necessarily 100% accurate
  • whenever a FD is freed, next_fd = min(fd, next_fd)
  • to allocate a FD, start searching the bitmap starting from next_fd -- lib/find_next_bit.c­#find_next_zero_bit is linear but still very fast, because it takes BITS_PER_LONG strides at a time
  • after a FD is allocated, next_fd = fd + 1

FreeBSD's sys/kern/kern_descrip.c­#fdalloc follows the same idea: start with int fd_freefile; /* approx. next free file */, and search the bitmap upwards.


However, these are all operating under the assumption that most processes have few FDs open, and very, very few have thousands. If the numbers will go much higher, with sparse holes, the common solution (as far as I've seen) is

#include <algorithm>  #include <functional>  #include <vector>    using namespace std;    int high_water_mark = 0;  vector<int> unused_numbers = vector<int>();    int get_new_number() {      if (used_numbers.empty())          return high_water_mark++;      pop_heap(unused_numbers.begin(), unused_numbers.end(), greater<int>());      return unused_numbers.pop_back();  }    void recycle_number(int number) {      unused_numbers.push_back(number);      push_heap(unused_numbers.begin(), unused_numbers.end(), greater<int>());  }  

(untested code... idea is: keep a high water mark; try to steal from unused below the high water mark, or up the high water mark otherwise; return freed to unused)

and if your assumption is that the used numbers will be sparse, then Dmitry's solution makes more sense.


Solution:3

I'd use a bidirectional map class for this problem. That way you can simply check if value 1 exists etc.

Edit

The benefits of using a bimap is that there already exist robust implementations of it and even if searching for the next free number is O(n) it is only an issue if n is large (or possibly if n is moderate and this is called very frequently). Overall making for a simple implementation that is unlikely to be error prone and easily maintainable.

If n is large or this operation is performed very frequently than investing the effort of implementing a more advanced solution is merited. IMHO.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »