【问题标题】:remove() not functioning correctlyremove() 无法正常工作
【发布时间】:2021-05-21 03:05:21
【问题描述】:

在下面的Main 方法中,为什么最后一个字(clapping)没有被删除?

public class Main {
    public static void main(String[] args) {
        HT ht = new HT();

        ht.insert("airplane");
        ht.insert("distilling");
        ht.insert("speaks");
        ht.insert("knit");
        ht.insert("digitize");
        ht.insert("Media");
        ht.insert("canonicalized");
        ht.insert("libraries");
        ht.insert("clapping");
        ht.insert("residues");
        ht.insert("spoilers");
        System.out.println(Arrays.toString(ht.set));

        ht.remove("distilling");
        ht.remove("knit");
        ht.remove("canonicalized");
        ht.remove("libraries");
        ht.remove("clapping");
        System.out.println(Arrays.toString(ht.set));
    }
}

输出是

[Media, digitize, airplane, canonicalized, spoilers, distilling, clapping, knit, libraries, speaks, residues]
[Media, digitize, airplane, null, spoilers, null, clapping, null, null, speaks, residues]

clapping 不会被删除。为什么?

HT.java

public class HT {
    public String[] set;
    public int size;

    public HT() {
        this.set = new String[11];
        this.size = 0;
    }

    public void insert(String word) {
        int hash1 = giveHash1( word );
        int hash2 = giveHash2( word );
        while (set[hash1] != null) {
            hash1 += hash2;
            hash1 %= set.length;
        }
        set[hash1] = word;
        size++;
    }

    public void remove(String word) {
        int hash1 = giveHash1(word);
        int hash2 = giveHash2(word);
        while (set[hash1] != null && !set[hash1].equals(word)) {
            hash1 += hash2;
            hash1 %= set.length;
        }
        set[hash1] = null;
        size--;
    }

    public int giveHashCode(String s) {
        int hash = 0, x = 31;
        for(int i=0;i<s.length();i++) {
            hash = x * hash + s.charAt(i);
        }
        return hash;
    }
    private int giveHash1(String s) {
        return  (giveHashCode(s) % set.length < 0)
                ? (giveHashCode(s) % set.length) + set.length
                : giveHashCode(s) % set.length;
    }
    private int giveHash2(String s) {
        return  3 - (((giveHashCode(s) % set.length < 0)
                ? (giveHashCode(s) % set.length) + set.length
                : giveHashCode(s) % set.length) % 3);
    }
}

除了修饰符之外,代码有什么问题吗?可能使用哈希函数,或者可能使用insert()remove()

【问题讨论】:

  • 只是好奇,但是你从哪里得到这个奇怪的双重哈希算法?
  • 您可能希望使用调试器单步执行代码并查看值。由于您在尝试消除我的猜测时更改了hash1,因此生成的哈希与用于插入的哈希不同,因此错误的存储桶设置为空。我对 Shadab 表示赞同,因为这是一个非常奇怪的哈希算法。
  • 附加说明:因为您的insert() 似乎试图通过更改哈希来避免冲突,直到您找到一个可能会运行一段时间的空点,尤其是在搜索最后一个可用存储桶时。这也会根据插入顺序导致不同的哈希,这不仅会导致很多问题,而且不仅会导致删除,还会导致任何其他需要查找给定单词的操作 - 您不能只通过哈希或搜索来访问单词单个存储桶,但可能必须搜索整个哈希表。
  • 您的删除函数会删除第一个非空条目,即使它不匹配。
  • 我明白了,那么有哪些好的散列函数呢?这些 r 是我在大学和互联网上所学的混合体。顺便说一句,giveHash2() 在现实中应该使用 7,但我将其更改为 3,因为它造成的碰撞更少。如果能提到一些好的散列函数就好了。我试图不使用内置的哈希类,而是自己实现它。

标签: java arrays hash hashtable double-hashing


【解决方案1】:

问题很可能是remove() 方法中循环的终止条件。

while (set[hash1] != null && !set[hash1].equals(word)) {

在它找到的第一个 null 值处终止。

插入时,如果位置已被占用,则更新hash1,因此单词的最终位置取决于现有插入的单词,即占用的位置。

但是,当您已经删除了一些值时,remove() 中的循环可能会更快找到空位置(null 值),并在实际到达 word 最初插入的位置之前终止.

【讨论】:

  • 哦,我明白了,那么可能的解决方法是什么?从while 条件中删除null 检查会导致NullPointerException
  • 在进行开放式寻址时,通常最好区分“此位置始终为空”和“此位置已删除它的值”。如果您可以将位置标记为“此位置已删除它的值”,那么您可以在插入和搜索时将其视为空,但在调用 remove 时对其进行迭代
  • 谢谢!我刚刚实现了它,它现在可以工作了
  • 顺便说一句,因为你说我的散列函数很奇怪,你能否修改你的答案以包括一些可能会减少冲突的好答案
猜你喜欢
  • 1970-01-01
  • 2014-03-24
  • 2017-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-01
相关资源
最近更新 更多