在图形中添加边缘时占用大量内存

时间:2016-06-04 13:19:49

标签: c++ c++11 memory graph memory-leaks

我有一个结构node和一个类graph他们看起来像这样:

struct node {
    node(const std::string &s) : id(std::hash<std::string>()(s)) { }
    node(node &&) = default;
    node(const node &) = default;

    friend bool operator<(node lhs, node rhs){
        return lhs.id < rhs.id;
    }
    mutable bool visited{false};
    const std::size_t id;
    mutable std::set<node> neighbors;
    mutable std::set<node> back_edges;
};

class graph {
    private:
        std::set<node> node_set;
    public:
        size_t add_edge(node from, node to){

            //auto start = std::chrono::system_clock::now();

            auto iter_from = node_set.insert(from).first;
            auto iter_to = node_set.insert(to).first;


            iter_from->neighbors.insert(*iter_to);
            iter_to->back_edges.insert(*iter_from);

            //auto duration = std::chrono::duration_cast<std::chrono::milliseconds>
            //      (std::chrono::system_clock::now() - start);

            //return duration.count();
            return -1;
        }

        std::size_t size(){
            return node_set.size();
        }

};

现在我想通过生成随机图来测试add_edge方法。为此我有一个函数,它生成长度为SIZE的随机字母串:

constexpr size_t SIZE{2};

graph g1;
for (int i = 0; i < 100000; i++){
    g1.add_edge(random_string(SIZE), random_string(SIZE));

如果我选择SIZE不是太小而不是超过5,那么一切正常,但如果我尝试选择SIZE小到2或甚至1,我会获得巨大的内存占用并且测试需要永远。由于图表应该更小,SIZE更小(SIZE = 1 - > 26 ^ 2),我真的不明白为什么会发生这种情况。

编辑:对于较小的SIZEadd_edge在循环中的每次迭代变得越来越慢。

编辑:这是生成我的随机字符串的函数:

std::string random_string(size_t length) {
    static bool initialized{false};
    if (!initialized) {
        std::srand(std::time(0));
        initialized = true;
    }
    auto randchar = []() -> char {
        static const char charset[] =
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        const size_t max_index = (sizeof(charset) - 1);
        return charset[std::rand() % max_index];
    };
    std::string str(length, 0);
    std::generate_n(str.begin(), length, randchar);
    return str;
}

1 个答案:

答案 0 :(得分:2)

您目前正在neighborsback_edges存储节点的副本。这可能非常昂贵,因为nodeneighbors中的每个back_edges都可以包含自己的neighborsback_edges。您可能希望存储指向节点的指针。

例如,您可以使用:

std::set<node *, Comparator> neighbors;
std::set<node *, Comparator> back_edges;

而不是:

std::set<node> neighbors;
std::set<node> back_edges;

Comparator的位置:

struct Comparator {
  bool operator () (const node * a, const node * b) const {
    return !a || b ? *a < *b : false;
  }
};

更进一步,您可以更新graph类以包含:

std::set<std::shared_ptr<node>, Comparator> node_set;

而不是:

std::set<node> node_set;

Comparator的位置:

struct Comparator {
  bool operator () (
    const std::shared_ptr<const node> & a,
    const std::shared_ptr<const node> & b
  ) const {
    return !a || b ? *a < *b : false;
  }
};

然后node可以更新为包含:

std::set<std::shared_ptr<node>, Comparator> neighbors;
std::set<std::shared_ptr<node>, Comparator> back_edges;

另一种选择是使用邻接矩阵代表图形。