获取地图中的第一个可用密钥

时间:2012-01-02 00:32:55

标签: c++ map

我有一个地图,用于存储指向对象的指针。

typedef std::map<unsigned int, Entity*> entityMap;
entityMap entitymap;

要为实体分配ID,我可以在实体图中取最新值并将其增加1.

Entity *entity = new Entity;
entity->id = /*newest entity+1*/;
entitymap.insert(std::pair<unsigned int,Entity*>(entity->id,entity));

但是这个数字可能会变得不必要地大,因为有时会删除一个实体并将其从地图中移除。

std::map<unsigned int,Entity*>::iterator it;
it = entitymap.find(EntityID);
if(it != entitymap.end())
{
    Entity *entity= it->second;
    entitymap.erase(it);
}
delete entity;

所以我可以有一张包含这些值的地图;

1,2,4,8,10

在这种情况下,我希望下一个实体声明ID 3

4 个答案:

答案 0 :(得分:4)

由于ID是按数字排序的,因此您可以浏览整个地图,直到找到“漏洞”:

unsigned int i = 1; // or whatever your smallest admissable key value is

for (auto it = m.cbegin(), end = m.cend();
                           it != end && i == it->first; ++it, ++i)
{ }

// now i is the next free index

如果地图很大并且第一个洞接近结尾,这可能需要很长时间。在开始此探索之前,您可以先检查最大键值(由m.crbegin()->first给出)是否明显大于m.size()

答案 1 :(得分:1)

假设列表不会增长很多,您至少可以保留已发布的最小标识符。然后,当您重新使用它时,搜索Kerrek SB提到的下一个可用标识符。

class {
...
    static int g_smallest_free_id; // init to 1
...
};

void delete_id()
{
    if(m_id < g_smallest_free_id) {
        m_id = g_smallest_free_id;
    }
}

void new_id()
{
    int id = g_smallest_free_id;
    // the -1 is because it looks like you start your ids at 1
    // since we skip all the known identifiers before id,
    // the loop is reduced from the current id to the next only
    for(interator it = list.begin() + id - 1;
                  it != list.end(); ++it) {
         // find next available id
    }
}

这是伪代码,向您显示最小的空闲标识符必须是您类中的静态变量(对所有实例都是通用的。)

如评论中所述,您可以使用向量代替。虽然它不会被排序,但您仍然无法无限期地增加标识符。矢量的唯一缺点就是你使用了一点内存......(如果你处理很多对象,那么很多,但地图也是如此。)

答案 2 :(得分:1)

您可以保留所有已释放密钥的Heap。每次释放密钥时都会将其添加到堆中,每次使用密钥时都会将其从堆中删除。这两个操作都是O(log n)。您将创建一个堆,以便根节点具有最小的密钥。

如果堆为空,那么您只需像往常一样递增前一个最大的密钥来分配一个新密钥。

答案 3 :(得分:1)

这可能很慢,具体取决于地图的密集程度,但相当容易理解:

typedef std::map<Key, Value> Table;

std::optional<Key> findFirstFreeSlot(const Key& start, const Key& end, const Table& table)
{
  for (Key i = start; i <= end; i++) {
    if (table.find(i) == table.end()) {
        return i;
    }
  }
  return std::none;
}