找到最低的未使用数字

时间:2009-06-11 10:26:39

标签: c++ algorithm stl

我已经设置了一个std地图来映射一些数字,此时我知道我从一个数字映射到的数字,例如:

std::map<int, int> myMap;

map[1] = 2;
map[2] = 4;
map[3] = 6;

稍后,我想将一些数字映射到地图中不存在的最低数字,例如:

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

这样做的简单方法是什么?

我考虑建立一个有序的数字列表,因为我将它们添加到地图中,这样我就可以找到1,找不到它,使用它,添加它等等。

3 个答案:

答案 0 :(得分:7)

这样的东西
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++;
}

如果您的地图非常大但很稀疏,这将像o(log(N))一样工作,其中N是地图中的项目数 - 在大多数情况下,您不必遍历该集合,或者只需要几步。 否则,如果地图中的间隙很少,那么您最好在[1..maxValueInTheMap]范围内拥有一组免费项目。

答案 1 :(得分:3)

查找最低的未使用数字是UNIX内核中非常常见的操作,如open / socket /等。系统调用应该绑定到最低的未使用的FD编号。

在Linux上,fs/file.c­#alloc_fd中的算法是:

  • 跟踪next_fd,水位低 - 它不一定是100%准确
  • 每当释放FD时,next_fd = min(fd, next_fd)
  • 要分配FD,从next_fd开始搜索位图 - lib/find_next_bit.c­#find_next_zero_bit是线性的,但仍然非常快,因为一次需要BITS_PER_LONG步幅
  • 分配FD后,
  • next_fd = fd + 1

FreeBSD的sys/kern/kern_descrip.c­#fdalloc遵循相同的想法:从int fd_freefile; /* approx. next free file */开始,向上搜索位图。


然而,这些都是在假设大多数进程开放的FD很少的情况下运行的,并且极少数有数千个。如果数字会更高,有稀疏的漏洞,常见的解决方案(就我所见)是

#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>());
}

(未经测试的代码...想法是:保持高水位;尝试从高水位以下的unused偷窃,否则从高水位上方偷走;返回释放到unused

如果您的假设是使用的数字将是稀疏的,那么Dmitry的解决方案更有意义。

答案 2 :(得分:0)

我会为这个问题使用双向地图类。这样你就可以简单地检查值1是否存在等。

修改

使用bimap的好处是已经存在它的强大实现,即使搜索下一个空闲数字是O(n),如果n很大(或者如果n是中等的,那么这只是一个问题)被称为非常频繁)。总体而言,简化实现不太容易出错并且易于维护。

如果 n 很大或者此操作的执行非常频繁,那么投入实施更高级的解决方案的努力是值得的。 IMHO。