这就是我所拥有的:具有任意数量级别的树。我需要一种方法来对每个级别的每个级别的所有节点进行排名。如果不清楚的话,那就说我的第一个级别就是世界。我的第二级是大陆。我的第三级是国家。我的第四级是城市。每个国家都有一个城市列表,按人口排序。每个大陆都有按人口排名的国家名单。每个大陆也有一份按人口排名的城市名单。等等。
我想象的算法是非常简单的递归,但我不确定跟踪这些列表的最佳数据结构是什么。每个级别都不知道它有多少子级别,所以我不能声明任意数量的列表。
有什么想法吗?
以下是一些示例代码:
public void calcStats()
{
initWorldRanks();//clears ranks for the world
for(Entity continent:theWorld.getChildren())
{
initContinentRanks();//clears ranks for the continent
for(Entity country:continent.getChildren())
{
initCountryRanks();//clears ranks for the country
for(Entity city:country.getChildren())
{
//Assume that add preserves sorted order. Sorting is easy. The tricky part is that each entity needs to be added to its ancestors. I don't want to have fixed data structures
worldCityRanks.add(city);
continentCityRanks.add(city);
countryCityRanks.add(city);
}
worldCountryRanks.add(country);
continentCountryRanks.add(country);
}
worldContinentRanks.add(continent);
}
一切都正确排名,但这限制了我一个明确的4级结构。
答案 0 :(得分:1)
关键是你不想通过遍历整个子树来重新计算每个节点的计数。缓存每个节点的总计数。然后,每个节点只需要从子节点收集值来计算它自己的总数(它也应该缓存)。
您没有说这些节点是否可变。如果它们是不可变的,那么很简单:在构造时添加所有子节点时构建节点的总数。
如果它们是可变的,您可以让每个节点在其计数发生变化时告诉其父节点。父母可以更新自己的计数并告诉其父级,然后在树上。这样可以更新计数O(树的深度)或大致O(logn)(取决于树的平衡程度)。
对于实际排序每个节点的孩子做你通常做的事情:使用ArrayList
并对其进行排序,或者使用某种维护排序顺序的排序集合(例如:TreeSet
,尽管make确定你在具有相同人口的元素之间徘徊。重要的是,在比较时,你只会看到你孩子的直接价值(即:缓存的金额),而不是你的间接后代。
根据您对问题的更新,您的一个问题是您可以获得在不同级别添加内容的单独方法。即:worldCityRanks.add
,continentCityRanks.add
,countryCityRanks.add
等。您应该使用以深度为参数的单个方法替换所有这些。例如:
// Probably in your Entity class
public void addDescendant(int distance, Entity descendant) {
// this replaces worldCityRanks.add, continentCityRanks.add,
// countryCityRanks.add, etc.
}
然后你没有为你的后代集合提供4个字段,而是拥有一个集合(可能是ArrayList
)来保存它们。你可以根据需要进行扩展。
另一个问题是你有这些硬编码的嵌套for循环。要处理任意(在合理范围内)深度,最简单的方法是使用递归。例如:
public void calcStats() {
theWorld.initAllRanks();
List<Entity> ancestors = new ArrayList<Entity>();
theWorld.accumulateAllRanks(ancestors);
}
class Entity ... {
...
void initAllRanks() {
initRanks();
for(Entity child: getChildren()) {
child.initAllRanks();
}
}
void accumulateAllRanks(List<Entity> ancestors) {
int distance = ancestors.size();
for(Entity ancestor: ancestors) {
distance--;
ancestor.addDescendant(distance, this);
}
ancestors.add(this); // push this
for(Entity child: getChildren()) {
child.accumulateAllRanks(ancestors);
}
ancestors.remove(ancestors.size() - 1); // pop this
}
这假设您确实想要存储每个级别的排名(这是您的代码示例所暗示的)。这种方法使查找速度更快,但它可以使更新速度变慢,并且与其他方法相比也会消耗更多内存。特别是,您可以只维护全局排名列表,然后在查询时过滤这些列表。同样,这使得更新更快并且消耗更少的内存,但使查询比您当前使用的方法慢。