std::map的查找失败,但手动扫描地图中的元素
std::map's find fails to find, but element in map with manual scan
我正在使用 std::map 和一个列表来跟踪 window 元素和相关分数。当 window 已满时,我想从 windows 队列中弹出一个元素并将其从地图中删除。因为可能存在重复项,所以地图会跟踪遇到 window 中的每个元素的次数。我也在使用有序地图,这样我就可以在给定的 window.
中不断获得最小值
我的问题是 find() 在不希望返回 end() 的情况下返回。
当我遍历地图时,我发现该元素存在。我不想牺牲使用 map 的对数复杂度。
tl;dr:std::map 表示某个元素不在地图中。手动扫描说是。
[编辑:Bryan Chen 的建议修复了地图。谢谢!]
#include <cstdint>
#include <cstdio>
#include <cinttypes>
#include <map>
#include <list>
#include <vector>
#include "util.h"
#include "kmerutil.h"
namespace kpg {
struct elscore_t {
uint64_t el_, score_;
INLINE elscore_t(uint64_t el, uint64_t score): el_(el), score_(score) {
LOG_ASSERT(el == el_);
LOG_ASSERT(score == score_);
}
INLINE elscore_t(): el_(0), score_(0) {}
inline bool operator <(const elscore_t &other) const {
return score_ < other.score_ || el_ < other.el_; // Lexicographic is tie-breaker.
}
inline bool operator ==(const elscore_t &other) const {
return score_ == other.score_ && el_ == other.el_; // Lexicographic is tie-breaker.
}
std::string to_string() const {
return std::to_string(el_) + "," + std::to_string(score_);
}
};
struct esq_t: public std::list<elscore_t> {
};
typedef std::map<elscore_t, unsigned> esmap_t;
class qmap_t {
// I could make this more efficient by using pointers instead of
// elscore_t structs.
// *maybe* TODO
// Could also easily templatify this module for other windowing tasks.
esq_t list_;
#if !NDEBUG
public:
esmap_t map_;
private:
#else
esmap_t map_;
#endif
const size_t wsz_; // window size to keep
public:
void add(const elscore_t &el) {
auto it(map_.upper_bound(el));
if(it->first == el) ++it->second;
else map_.emplace(el, 1);
}
void del(const elscore_t &el) {
auto f(map_.find(el));
if(f == map_.end()) {
LOG_DEBUG("map failed :(\n");
for(f = map_.begin(); f != map_.end(); ++f)
if(f->first == el)
break;
}
LOG_ASSERT(f != map_.end());
if(--f->second <= 0)
map_.erase(f);
}
uint64_t next_value(const uint64_t el, const uint64_t score) {
list_.emplace_back(el, score);
LOG_ASSERT(list_.back().el_ == el);
LOG_ASSERT(list_.back().score_ == score);
add(list_.back());
if(list_.size() > wsz_) {
//fprintf(stderr, "list size: %zu. wsz: %zu\n", list_.size(), wsz_);
//map_.del(list_.front());
del(list_.front());
list_.pop_front();
}
LOG_ASSERT(list_.size() <= wsz_);
return list_.size() == wsz_ ? map_.begin()->first.el_: BF;
// Signal a window that is not filled by 0xFFFFFFFFFFFFFFFF
}
qmap_t(size_t wsz): wsz_(wsz) {
}
void reset() {
list_.clear();
map_.clear();
}
};
}
这不是有效的严格弱排序:
return score_ < other.score_ || el_ < other.el_;
您有 elscore_t(0, 1) < elscore_t(1, 0)
和 elscore_t(1, 0) < elscore_t(0, 1)
。
作为T.C。在他的回答中指出,你的 operator<
不正确。
可以使用std::tie进行字典序比较
return std::tie(score_, el_) < std::tie(other.score_, other.el_);
否则你可以
if (score_ == other.score_) {
return el_ < other.el_; // use el_ to compare only if score_ are same
}
return score_ < other.score_;
我正在使用 std::map 和一个列表来跟踪 window 元素和相关分数。当 window 已满时,我想从 windows 队列中弹出一个元素并将其从地图中删除。因为可能存在重复项,所以地图会跟踪遇到 window 中的每个元素的次数。我也在使用有序地图,这样我就可以在给定的 window.
中不断获得最小值我的问题是 find() 在不希望返回 end() 的情况下返回。 当我遍历地图时,我发现该元素存在。我不想牺牲使用 map 的对数复杂度。
tl;dr:std::map 表示某个元素不在地图中。手动扫描说是。
[编辑:Bryan Chen 的建议修复了地图。谢谢!]
#include <cstdint>
#include <cstdio>
#include <cinttypes>
#include <map>
#include <list>
#include <vector>
#include "util.h"
#include "kmerutil.h"
namespace kpg {
struct elscore_t {
uint64_t el_, score_;
INLINE elscore_t(uint64_t el, uint64_t score): el_(el), score_(score) {
LOG_ASSERT(el == el_);
LOG_ASSERT(score == score_);
}
INLINE elscore_t(): el_(0), score_(0) {}
inline bool operator <(const elscore_t &other) const {
return score_ < other.score_ || el_ < other.el_; // Lexicographic is tie-breaker.
}
inline bool operator ==(const elscore_t &other) const {
return score_ == other.score_ && el_ == other.el_; // Lexicographic is tie-breaker.
}
std::string to_string() const {
return std::to_string(el_) + "," + std::to_string(score_);
}
};
struct esq_t: public std::list<elscore_t> {
};
typedef std::map<elscore_t, unsigned> esmap_t;
class qmap_t {
// I could make this more efficient by using pointers instead of
// elscore_t structs.
// *maybe* TODO
// Could also easily templatify this module for other windowing tasks.
esq_t list_;
#if !NDEBUG
public:
esmap_t map_;
private:
#else
esmap_t map_;
#endif
const size_t wsz_; // window size to keep
public:
void add(const elscore_t &el) {
auto it(map_.upper_bound(el));
if(it->first == el) ++it->second;
else map_.emplace(el, 1);
}
void del(const elscore_t &el) {
auto f(map_.find(el));
if(f == map_.end()) {
LOG_DEBUG("map failed :(\n");
for(f = map_.begin(); f != map_.end(); ++f)
if(f->first == el)
break;
}
LOG_ASSERT(f != map_.end());
if(--f->second <= 0)
map_.erase(f);
}
uint64_t next_value(const uint64_t el, const uint64_t score) {
list_.emplace_back(el, score);
LOG_ASSERT(list_.back().el_ == el);
LOG_ASSERT(list_.back().score_ == score);
add(list_.back());
if(list_.size() > wsz_) {
//fprintf(stderr, "list size: %zu. wsz: %zu\n", list_.size(), wsz_);
//map_.del(list_.front());
del(list_.front());
list_.pop_front();
}
LOG_ASSERT(list_.size() <= wsz_);
return list_.size() == wsz_ ? map_.begin()->first.el_: BF;
// Signal a window that is not filled by 0xFFFFFFFFFFFFFFFF
}
qmap_t(size_t wsz): wsz_(wsz) {
}
void reset() {
list_.clear();
map_.clear();
}
};
}
这不是有效的严格弱排序:
return score_ < other.score_ || el_ < other.el_;
您有 elscore_t(0, 1) < elscore_t(1, 0)
和 elscore_t(1, 0) < elscore_t(0, 1)
。
作为T.C。在他的回答中指出,你的 operator<
不正确。
可以使用std::tie进行字典序比较
return std::tie(score_, el_) < std::tie(other.score_, other.el_);
否则你可以
if (score_ == other.score_) {
return el_ < other.el_; // use el_ to compare only if score_ are same
}
return score_ < other.score_;