我已经设置了一个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,找不到它,使用它,添加它等等。
答案 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%准确next_fd = min(fd, next_fd)
next_fd
开始搜索位图 - lib/find_next_bit.c
#find_next_zero_bit
是线性的,但仍然非常快,因为一次需要BITS_PER_LONG
步幅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。