哈希表再哈希和迭代器的实现

1、再哈希

实现resize()和rehash()方法

2、迭代器

实现迭代器的三个方法(hasNext()、next()、remove())
1、再哈希->为什么?

在简单的哈希表的实现中,用的是数组+链表的方式去减少哈希碰撞,既然牵扯到数组,就不可避免地产生扩容操作。
我们的哈希函数是基于数组的长度所做的运算,既然数组的长度有所改变,那么就应该对原来数组+链表中的每个结点重新计算哈希值,以确保重置每个通过哈希算法得到的 index 。
1)resize,扩容
逻辑:
简单,对数组二倍扩容,再扩容后,对每一个结点再哈希
代码:

public void resize(){
     
        Node<K, V>[] newTable = new Node[this.table.length * 2];
        for (int i = 0; i < this.table.length; i++) {
     
            //对oldTable中每一个结点rehash()
            rehash(i, newTable);
        }
        this.table = newTable;
    }

2)rehash,对每一个结点再哈希,以确保将其放到正确的位置。
逻辑:
对于旧、新两个哈希表来说,将值重新哈希到新的表,对于数组下标上的结点,仍然映射到新表对应的下标上;对于链表上除去第一个结点的其它结点来说,是哈希到通过哈希算法得到的index + oldTable.length。
既然有了这样的规律,这里采用的是将本在 oldTable 下标的结点链成一个链表(LowList),将不在 oldTable 下标上的结点也链成一个链表(HighList),按照规矩办事,即可完成 rehash()。
代码:

public void rehash(int index, Node<K, V>[] newTable) {
     

        //获取当前位置下的节点
        Node<K, V> curNode = table[index];
        if (curNode == null) {
     
            return;
        }

        Node<K, V> lowListHead = null;//低位的头
        Node<K, V> lowListTail = null;//低位的尾

        Node<K, V> highListHead = null;//高位的头
        Node<K, V> highListTail = null;//高位的尾

        //currentNode是oldtable下index位置的第一个节点
        while (curNode != null) {
     
            //得到当前节点在新table中的位置
            int newIndex = hash(curNode.key) & (newTable.length - 1);
            //int newIndex = getIndex(currentNode.key, newTable);
            //如果和index相等,则直接放
            if (newIndex == index) {
     
                //把该位置所有节点链成一个链表,最后统一放
                if (lowListHead == null) {
     
                    lowListHead = curNode;
                    lowListTail = curNode;
                } else {
     
                    lowListTail.next = curNode;
                    lowListTail = lowListTail.next;
                }
            } else {
     
                //newIndex和index不等
                if (highListHead == null) {
     
                    highListHead = curNode;
                    highListTail = curNode;
                } else {
     
                    highListTail.next = curNode;
                    highListTail = highListTail.next;
                }
            }
            curNode = curNode.next;
        }

        //将index位置连上当前lowList
        if (lowListTail != null) {
     
            lowListHead.next = null;
            newTable[index] = lowListHead;
        }

        //将index+table.length位置连上当前highList
        if (highListTail != null) {
     
            highListTail.next = null;
            newTable[index + this.table.length] = highListHead;
        }

    }

这个也是JDK源码中rehash的方法。

2、迭代器

迭代器,是一种遍历集合的方式。这种方式比for循环和其它循环更加的安全。
在Java,推荐使用的foreach也是基于迭代器实现。
比如:

ArrayList<Integer> list = new ArrayList<>();
        list.add(2);
        list.add(3);
        list.add(1);
        System.out.println(list);//list.toString()
        for (Integer e : list) {
     
            System.out.print(e + " ");
        }

基于迭代器实现,遍历集合元素
在某个自实现的集合中,要实现它的迭代器,就要实现Iterator接口,并重写hasNext()、next(),remove()不是必须要重写。
在这个自实现的类中,迭代器应该作为一个内部类或者一个匿名内部类实现,这样比较好操作。
1)构造器
首先,我们需要得到第一个不为空的结点,我们需要一个方法去get,不如使用构造器。
代码:

        public Itr() {
     
            //哈希表中没得结点
            if (HashMap.this.size == 0) {
     
                return;
            }
            //得到第一个不为空的结点
            for (int i = 0; i < HashMap.this.table.length; i++) {
     
                if (table[i] != null) {
     
                    this.nextNode = table[i];
                    this.curIndex = i;
                    return;
                }
            }
        }

2) hasNext(), 被迭代的集合元素是否已被遍历完
代码:

        public boolean hasNext() {
     
            return nextNode != null;
        }

3)next(),返回集合中的下一个元素

        public Node<K, V> next() {
     
            this.curNode = nextNode;
            //遍历到当前链表的下一个
            this.nextNode = nextNode.next;
            //如果不为空,相等于一直遍历的是当前链表
            //下一次调用next()方法返回下一个结点
            //为空,当前链表最后一个一个结点已经遍历完
            if (this.nextNode == null) {
     
                //在数组上寻找下一个不为空的结点
                for (int i = curIndex + 1; i < HashMap.this.table.length; i++) {
     
                    if (table[i] != null) {
     
                        this.nextNode = table[i];
                        this.curIndex = i;
                        break;
                    }
                }
            }
            return curNode;
        }

4)remove(),删除集合上一次调用next方法返回的元素
代码:

        public void remove() {
     
            if(this.curNode == null){
     
                return;
            }
            K currentKey = this.curNode.key;
            HashMap.this.remove(currentKey);
            this.curNode = null;
        }

注:
完整的哈希表代码

你可能感兴趣的:(Java,基础知识)