Java:递归迭代地图

时间:2016-02-18 02:13:07

标签: java algorithm recursion

我们有一个看起来像"递归的对象"数据结构。

假设我们有一个Person对象,其结构类似于

public class Person {
    private String id;

    private Map<String,Person> persons;

    public Person(String id, Map<String,Person> persons){
        this.id = id;
        this.persons = persons;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Map<String, Person> getPersons() {
        return persons;
    }

    public void setPersons(Map<String, Person> persons) {
        this.persons = persons;
    }

    @Override
    public String toString() {
        return "Person [id=" + id + ", persons=" + persons + "]";
    }

}

此对象的示例表示形式为:(样本数据)

  Person p1 = new Person("Jim", ImmutableMap.of("A001",new Person("Mike",ImmutableMap.of("D001",new Person("Jack",ImmutableMap.of("E001",new Person("Kim",null))))),
                                                         "Z001",new Person("Adam",ImmutableMap.of("Y001",new Person("Eve",ImmutableMap.of("X001",new Person("Dave",null)))))));

注1:ImmutableMap来自google guava collection

注意2:让我们假设&#39;键&#39;对象中Person的对象是该人的姓名。

根据此人的姓名,迭代和获取ID的最有效方法是什么。

例如,如果输入是&#39; Eve&#39;,输出应该是&#39; Y001&#39;

3 个答案:

答案 0 :(得分:2)

由于您已经在使用Guava,请考虑向Person类添加这样的方法:

public FluentIterable<Map.Entry<String, Person>> tree() {
    if (persons == null)
        return FluentIterable.from(ImmutableList.of());
    return FluentIterable.from(persons.entrySet())
            .transformAndConcat(
                entry -> Iterables.concat(ImmutableList.of(entry), entry.getValue().tree()));
}

或者如果你不能使用Java-8:

public FluentIterable<Map.Entry<String, Person>> tree() {
    if (persons == null)
        return FluentIterable.from(ImmutableList.of());
    return FluentIterable.from(persons.entrySet())
        .transformAndConcat(
            new Function<Entry<String, Person>, Iterable<Entry<String, Person>>>() {
            @Override
            public Iterable<Map.Entry<String, Person>> apply(
                    Map.Entry<String, Person> entry) {
                return Iterables.concat(ImmutableList.of(entry), entry.getValue().tree());
            }
        });
}

它会将所有人的树拼成单Iterable,这可以很容易地用于for循环:

String name = "Eve";
for(Map.Entry<String, Person> e : p1.tree()) {
    if(e.getValue().getId().equals(name)) {
        System.out.println(e.getKey());
        break;
    }
}

或使用FluentIterable操作:

System.out.println(p1.tree()
                     .firstMatch(e -> e.getValue().getId().equals(name))
                     .get().getKey());

答案 1 :(得分:2)

对于番石榴TreeTraverser来说,这是一个完美的工作:

Iterable<Person> allPersons = new TreeTraverser<Person>() {
  @Override public Iterable<Person> children(Person p) {
     return p.getPersons().values();
  }
}.preOrderTraversal(rootPerson);
for (Person p : allPersons) {
  if (p.getId().equals(id)) {
    return p;
  }
}

答案 2 :(得分:0)

您的结构实际上是一种树。所以你可以使用标准的树木排序方法。如果您的树是二叉树(看起来不是这样),您可以非常有效地实现这一目标。

以下内容可行,但我没有证据证明这是最有效的方法。非二进制树大多只需要插入。

效率取决于您认为递归的叠加程度。如果你认为大多数结构都像样本结构,那就是:非常深,但每个级别只有几个人,这将是非常有效的。特别是如果你的结果将接近底部。

public String iterate(String name) {
        if (persons != null) {
            for (Entry<String, Person> entry : persons.entrySet()) {
                Person value = entry.getValue();
                if (value.getId().equals(name)) {
                    return entry.getKey(); //Since the key of each map is the ID when they return the key
                } else {
                    String ans = value.iterate(name);
                    if (ans != null) {
                        return ans;
                    }
                }
            }
        }
        return null;
    }

它可以快速浏览整个人员列表,而无需返回顶部。

但是,如果你有一个广泛的设置,并且你认为你的价值观大部分都接近顶部,你可以使用类似下面的内容。

public String iterate(String name) {
        if (persons != null) {
            for (Entry<String, Person> entry : persons.entrySet()) {
                Person value = entry.getValue();
                if (value.getId().equals(name)) {
                    return entry.getKey(); //Since the key of each map is the ID when they return the key
                }
            }

            for (Entry<String, Person> entry : persons.entrySet()) {
                String ans = entry.getValue().iterate(name);
                if (ans != null) {
                    return ans;
                }
            }
        }
        return null;
    }

这样可以快速找到结构顶部附近的东西,但在结构底部找到一个人会比较慢。

我猜你会想要上层解决方案,它更标准。但是,我不认为它们之间存在巨大差异。有关它的另一个版本,请参阅this question有关遍历树的信息。