带有c ++向量的分层数据结构,可以自下而上和自上而下遍历

时间:2013-06-07 07:20:02

标签: c++ data-structures c++11 iterator multimap

我的层次结构很少。我有以下内容:

RawSheet = vector<Country>
Country = vector<City>
City = vector<Building>

除了向量之外的类还包含一些其他有用的东西。问题是 我只能在整个结构中从上到下,即从RawSheet开始 我可以得到它的国家,然后每个国家我可以得到城市和每个城市 我可以得到它的建筑物。但我也需要能够做到这一点:给一座建筑,得到它的城市, 然后为纽约市获得其国家,最后获得该国家的RawSheet。是)我有的 现在基本上是一个上下连接的树,但不是从下到上。你能建议我的方法吗? 这样做,然后我如何管理这些链接?例如,每个城市都可以保留参考 一个国家,它自己的。其他人也一样......保留对父母的引用。

由于

2 个答案:

答案 0 :(得分:1)

我会定义一个基类Layer,它有一个指向父图层的指针和一个可以打印的名称。然后,您可以通过简单地继承此Layer并使用新的C ++ 11继承构造函数来避免代码重复来定义层次结构中的所有层(在C ++ 98中,您必须在每个层中定义构造函数)具体层)。

我不会将子项存储在图层中,而是存储在std::multimap<Layer*, Layer*>中,这样您就可以使用方便的成员函数equal_range来获取应用程序中任何具体图层的所有子项(我称之为这个数据结构Atlas)。

#include <map>
#include <string>
#include <utility>
#include <vector>
#include <iostream>

class Layer
{
public:
    explicit Layer(std::string n, Layer* p = nullptr): name_(n), parent_(p) {}
    std::string name() { return name_; }
    Layer* parent() { return parent_; }
private:
    std::string name_;
    Layer* parent_;
};

// inheriting constructrors (C++11 only, retype constructors for C++98)
class City   : public Layer { using Layer::Layer; };
class Country: public Layer { using Layer::Layer; };
class Planet : public Layer { using Layer::Layer; };

typedef std::multimap<Layer*, Layer*> Atlas;

int main()
{
    Planet Earth("Earth");

    Country USA("United States of America", &Earth);
    Country FRA("France", &Earth);

    std::vector<City> USA_cities = { City("Los Angeles", &USA), City("New York", &USA) };
    std::vector<City> FRA_cities = { City("Bordeaux", &FRA), City("Paris", &FRA) };

    Atlas a;

    a.insert(std::make_pair(&Earth, &USA));
    a.insert(std::make_pair(&Earth, &FRA));

    for (auto& city: USA_cities)
        a.insert(std::make_pair(&USA, &city));

    for (auto& city: FRA_cities)
        a.insert(std::make_pair(&FRA, &city));

    auto countries = a.equal_range(&Earth);
    std::cout << "Countries on planet " << countries.first->first->name() << " :\n";
    for (auto it = countries.first; it != countries.second; ++it) {
         auto country = it->second;
         std::cout << country->name() << " (located on planet " << country->parent()->name() << "), with cities:\n";
         auto cities = a.equal_range(country);
         for (auto jt = cities.first; jt != cities.second; ++jt) { 
              auto city = jt->second;
              std::cout << "     " << city->name() << " (located in country " << city->parent()->name() << ")\n";
         }
         std::cout << "\n";
    }
}

Live Example,输出如下:

Countries on planet Earth :
United States of America (located on planet Earth), with cities:
     Los Angeles (located in country United States of America)
     New York (located in country United States of America)

France (located on planet Earth), with cities:
     Bordeaux (located in country France)
     Paris (located in country France)

如您所见,您可以在此层次结构中上下迭代。

你可以在几个方面批评这个解决方案。类层次结构没有强制执行:Planet可以有Cities列表而没有中间Country层等。您可以通过编译时检查或运行时强制执行此类操作类型信息。这是灵活性和安全性之间的权衡。

基类virtual中也没有Layer析构函数。只要您不尝试通过Layer*删除任何具体的图层对象,就没有问题。也没有智能指针,因为所有Layer*都是非拥有指针。如果您想要移动或复制建筑物(有时会发生),您可以轻松扩展它。

答案 1 :(得分:0)

这个问题有几种方法。我只露出一个。

您可以使用对容器的引用来封装容器的每个元素。类似的东西:

class Country;

class City {
public:
    City(Country& c): country(c) {
    }

private:
    string      name;
    size_t      population;
    Country&    country;
};

class Country {
    string          name;
    vector<City>    cities;
};

当然,您可以使用指针代替对容器的引用。但是,如果您想强制每个城市仅由一个国家拥有,请使用参考。在这种情况下,您必须为City类提供构造函数,如示例中所示。

将此示例扩展到层次结构的其他级别也很容易。