我需要构建一个表示文件中存在的类的继承图的数据结构。这是为仅支持单继承的语言编写编译器的一部分。
存在的所有类的名称存储在链表中。我需要遍历该列表并从中构建一个继承图。 然后我需要检查继承中是否存在循环,例如 如果
B inherits A
C inherits B
然后
A cannot inherit C.
语言中不允许这样的循环。
哪种数据结构最适合这种情况?
答案 0 :(得分:1)
鉴于继承通常不经常进行,并且因为层次结构通常不会变得非常深(例如,你通常不会在继承层次结构中拥有10,000多个类,更不用说1,000个),I认为只要您直接的链接结构就可以了。
A<->B<->C<---->A<->B<->C
当尝试将C链接到A时,首先在建立链接之前从A遍历图(树)(递归树搜索应该没问题)。如果您发现A已存在于A图表中,那么您需要建立一个周期并想要拒绝连接(生成编译器错误或其他内容)。
如果您发现这成为一个热点,并且您的特定编程语言实际上鼓励了一种编程方式,其中继承层次结构通常可以在其中包含大量类,那么这是一种简单的方法来优化从线性时间到logarithmic是存储std::shared_ptr<std::set<Node*>>
。
从A链接到B时,首先在A中搜索A中的共享std::set
。如果B在该集合中不存在,那么我们可以自由建立连接( B继承自A)。然后将A中的shared_ptr复制到B。
在取消B与A的关联时(虽然我认为你不需要处理这个案例,因为有一种语言可以让事情变成“未被发现”),删除B从共享集中设置并将B的shared_ptr设置为null(释放引用)。
那就是说,你的语言真的允许在类定义之外进行这种动态继承吗?通常,大多数编程语言都会在定义类时指定继承。因此,除非你有这种&#34;动态继承&#34;,否则A通常不可能尝试从已经从B继承的B继承的C继承。这将试图使A继承在定义之后的很长一段时间内。
答案 1 :(得分:1)
游戏编程宝石8有一个伟大的“快速是一个”实现由我的老老板写,这将很好地适应这一点。我不记得所有的细节,所以你必须检查它,但它使用一些聪明的位模式技巧来快速做事(除了点打包)。 http://www.gameenginegems.net/gemsdb/article.php?id=516
答案 2 :(得分:1)
一个简单的树结构就足够了(在你的单一继承假设下)。
#include <iostream>
#include <cassert>
using namespace std;
class Class {
private:
const string name;
const Class *parent;
public:
Class(const string aName) :
name{aName},
parent(nullptr)
{}
bool setParent(const Class &otherClass) {
// I dont already have a parent class
if (parent)
return false; // no multiple inheritance
// so I am the root of some inheritance tree.
// Now searching for the root ot the otherClass tree
auto root = &otherClass;
while (root->parent != nullptr) {
root = root->parent;
};
// it shouldn't be me !
if (root == this)
return false;
// let's remember the inheritance
parent = &otherClass;
return true;
}
};
// some tests
int main(int argc, char **argv)
{
cout << "Tests :" << endl;
Class a("A");
assert(! a.setParent(a));
Class b("B");
assert(b.setParent(a));
Class c("C");
assert(c.setParent(b));
assert( ! a.setParent(c));
cout << "Success !" << endl;
return 0;
}
使用路径压缩技巧可以加快速度,请参阅http://en.wikipedia.org/wiki/Disjoint-set_data_structure#Disjoint-set_forests