在Java中使用这个问题的好数据结构是什么?

时间:2015-12-21 19:15:49

标签: java dictionary hash structure

所以我有以下问题:

我希望有一些存储一种太空船(太空船ID)的数据存储。每艘宇宙飞船都有一个名字。

情况1

特定类型的宇宙飞船只能在数据存储中存储一次。因此,如果用户尝试存储以下内容,则名称1:太空船类型1和名称2:太空船类型1只有1个宇宙飞船类型1的实例将存储在数据结构中。

情况2

如果用户输入名称1:太空船类型1,然后输入名称1:太空飞船类型2,则数据结构应仅存储名称1:太空飞船类型2.这意味着太空船类型1已被太空飞船类型2替换为他们有相同的名字。

我对此问题的初步处理方法是使用哈希映射,我会对太空船ID进行哈希处理,这样如果两个太空船ID相同,我将只在哈希映射中存储一次太空船ID,并且值我将有一个映射到相同的太空船ID的名称数组。这解决了情况1.

情况2更成问题。哈希映射可能非常大,我认为迭代每个桶中的每个数组都是低效的,以便识别是否已经使用了一个名称,以便从哈希映射中删除该名称和潜在的太空船ID并添加一个条目使用新的太空船ID及其相应的名称。

在这种情况下,哈希映射最好使用,还是可以使用另一种数据结构来解决这两种情况。也许我必须自己创造一个。任何正确方向的指针都会有所帮助。

2 个答案:

答案 0 :(得分:0)

单独的地图将是理想的,但如果您决定绕过任何第三方图书馆(我不同意的决定,除非目的是学习如何创建自己的Map ),那么最容易想到的就是你有两个Maps

Map<String, String> typeToName; //if you could have multiple of the Value, it could be Set<String>
Map<String, String> nameToType;

//put "Type1", "DoubleDouble's Destroyer" in typeToName
//put "DoubleDouble's Destroyer", "Type1" in nameToType

如果您要添加"Type1", "DistractionBoat",则首先要查看"Type1"中是否有typeToName,并从nameToType中删除相应的名称。

然后你反过来检查"DistractionBoat"中是否有nameToType,并从type

中删除任何相应的typeToName

然后添加新的太空船,它将替换同一type name的任何太空船。

可能有许多改进可以在此基础上构建(最明显的是使其更通用和自己的类)。事实上,你为了速度牺牲了记忆。

答案 1 :(得分:0)

您可以使用两个地图实现自己的类,如下所示:

public final class Spaceship {
    private final int    id;
    private final String name;
    public Spaceship(int id, String name) {
        this.id = id;
        this.name = name;
    }
    public int getId() {
        return this.id;
    }
    public String getName() {
        return this.name;
    }
    @Override
    public String toString() {
        return this.id + ":" + this.name;
    }
}

public final class Spacedock {
    private Map<Integer, Spaceship> byId   = new HashMap<>();
    private Map<String, Spaceship>  byName = new TreeMap<>(); // so getSpaceships() lists ordered by name
    public boolean containsSpaceship(Spaceship spaceship) {
        Spaceship shipInDock = this.byId.get(spaceship.getId());
        return (shipInDock != null && shipInDock.getName().equals(spaceship.getName()));
    }
    public void addSpaceship(Spaceship spaceship) {
        if (! containsSpaceship(spaceship)) {
            Spaceship prevShip = this.byId.put(spaceship.getId(), spaceship);
            if (prevShip != null)
                this.byName.remove(prevShip.getName());
            prevShip = this.byName.put(spaceship.getName(), spaceship);
            if (prevShip != null)
                this.byId.remove(prevShip.getId());
        }
    }
    public void removeSpaceship(Spaceship spaceship) {
        if (containsSpaceship(spaceship)) {
            this.byId.remove(spaceship.getId());
            this.byName.remove(spaceship.getName());
        }
    }
    public Collection<Spaceship> getSpaceships() {
        return this.byName.values();
    }
    public Spaceship getById(int id) {
        return this.byId.get(id);
    }
    public Spaceship getName(String name) {
        return this.byName.get(name);
    }
    @Override
    public String toString() {
        return this.byName.values().toString();
    }
}

测试

Spacedock spacedock = new Spacedock();
spacedock.addSpaceship(new Spaceship(1, "Name1"));
System.out.println(spacedock);
spacedock.addSpaceship(new Spaceship(2, "Name2"));
System.out.println(spacedock);
spacedock.addSpaceship(new Spaceship(1, "Name2"));
System.out.println(spacedock);
spacedock.addSpaceship(new Spaceship(2, "Name2"));
System.out.println(spacedock);
spacedock.addSpaceship(new Spaceship(2, "Name1"));
System.out.println(spacedock);

输出

[1:Name1]
[1:Name1, 2:Name2]
[1:Name2]
[2:Name2]
[2:Name1]

如您所见,存储了不同的太空飞船,通过添加一个已存在的ID或名称的新船将删除现有的船只。

如果您使用的是Java 8并且不喜欢空值,请使用新的Optional

public Optional<Spaceship> getById(int id) {
    return Optional.ofNullable(this.byId.get(id));
}
public Optional<Spaceship> getName(String name) {
    return Optional.ofNullable(this.byName.get(name));
}