我所理解的JKD集合類(六):手寫HashMap實現Map接口

package cn.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Description : 手寫HashMap的實現
 * @Author : houshuiqiang@163.com, 2016年6月10日 下午2:06:22
 * @Modified :houshuiqiang@163.com, 2017年6月11日
 */
public class MyHashMap<K, V> implements Map<K, V> {

    private int modCount;

    private Node<K, V>[] table;

    private int size;

    private int capacity;

    private static final int DEFAULT_CAPACITY = 16;

    private static final int MAX_CAPACITY = 2^16;

    private float loadFactor;

    private static final float DEFAULT_LOAD_FACTOR = 0.75F;

    private static final int INCREMENT_FACTOR = 2;

    private int capacitySize; // 當前set最多容許存放多少個元素,超過則須要擴容

    public MyHashMap() {
        this(DEFAULT_CAPACITY);
    }

    public MyHashMap(int capacity) {
        this(capacity, DEFAULT_LOAD_FACTOR);
    }

    @SuppressWarnings("unchecked")
    public MyHashMap(int capacity, float loadFactor) {
        vertifyConsturctorCapacity(capacity);
        vertiryConsturctorLoadFactor(loadFactor);
        table = new Node[this.capacity];
        capacitySize =(int) (this.capacity * this.loadFactor);
    }


    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean containsKey(Object key) {
        return keySet().contains(key);
    }

    @Override
    public boolean containsValue(Object value) {
        for (int i = 0; i < table.length; i++) {
            Node<K, V> node = table[i];
            if (node == null) {
                continue;
            }else{
                while(node != null) {
                    if (value == null && node.v == null  || node.v != null && node.v.equals(value)) {
                        return true;
                    }
                    node = node.nextNode;
                }
            }
        }
        return false;
    }

    @Override
    public V get(Object key) {
        for (int i = 0; i < table.length; i++) {
            Node<K, V> node = table[i];
            if (node == null) {
                continue;
            }else{
                while(node != null) {
                    if (key == null && node.k == null || key != null && node.k != null
                            && node.k.hashCode() == key.hashCode() && node.k.equals(key)) {
                        return node.v;
                    }
                    node = node.nextNode;
                }
            }
        }
        return null;
    }

    @Override
    public V put(K key, V value) {
        ifIncrement();
        if (null == key) {
            Node<K, V> node = table[0];
            boolean alreadyHasNull = false;
            while(node != null && !alreadyHasNull) {
                alreadyHasNull = node.k == null;
                node = node.nextNode;
            }
            if (!alreadyHasNull) {
                table[0] = new Node<K, V>(key, value, 0, table[0]);
                size++;
                modCount++;
            }
            return null;
        }

        int hash = hash(key.hashCode());
        int index = indexOfTable(hash);

        Node<K, V> node = table[index];
        boolean alreadyHas = false;
        V returnValue = null;
        while (node != null && !alreadyHas) {
            alreadyHas = node.k != null && hash == node.hash && key.equals(node.k);
            if(alreadyHas){
                returnValue = node.v;
                node.v = value;
            }
            node = node.nextNode;
        }
        if (!alreadyHas) {
            table[index] = new Node<K, V>(key, value, hash, table[index]);
            size++;
            modCount++;
        }

        return returnValue;
    }

    @Override
    public V remove(Object key) {

        Node<K, V> node = removeKey(key);

        return node == null ? null : node.v;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        Set<?> entrySet = m.entrySet();
        for (Object object : entrySet) {
            if (object instanceof java.util.Map.Entry) {
                java.util.Map.Entry entry = (java.util.Map.Entry)object;
                this.put((K)entry.getKey(), (V)entry.getValue());
            }
        }

    }

    @Override
    public void clear() {
        Arrays.fill(table, null);
        size = 0;
        modCount++;
    }

    @Override
    public Set<K> keySet() {
        return new KeySet();
    }

    @Override
    public Collection<V> values() {
        List<V> arrayList = new ArrayList<V>();

        Iterator<java.util.Map.Entry<K, V>> iterator = entrySet().iterator();
        while(iterator.hasNext()){
            arrayList.add(iterator.next().getValue());
        }

        return arrayList;
    }

    @Override
    public Set<java.util.Map.Entry<K, V>> entrySet() {
        return new EntrySet();
    }


    private void vertifyConsturctorCapacity(int capacity){
        if (capacity < 0) {
            throw new IllegalArgumentException("初始容量不合法");
        }
        if (capacity > MAX_CAPACITY) {
            this.capacity = MAX_CAPACITY;
            return;
        }

        // TODO 2的n次方 -- 直接copy的hashMap的代碼,這個有點困難。
        this.capacity = tableSizeFor(capacity);
    }

    // 這個方法有點難實現,直接copy吧。
    /** {@link java.lang.HashMap#tableSizeFor(int)} */
    private int tableSizeFor(int capacity) {
        int n = capacity - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAX_CAPACITY) ? MAX_CAPACITY : n + 1;
    }

    private void vertiryConsturctorLoadFactor(float factor){
        if (factor <= 0 || Float.isNaN(factor)) {
            throw new IllegalArgumentException("增加因子不合法");
        }
        this.loadFactor = factor;
    }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void ifIncrement(){
        if (capacitySize <= size) {
            // 擴容
            Node<K, V>[] newTable = new Node[table.length * INCREMENT_FACTOR];

            // 遍歷數組
            for(Node<K, V> node : table){
                if (node != null) {
                    // 遍歷鏈表
                    for (Node<K, V> tempNode = node; tempNode != null; tempNode = tempNode.nextNode) {
                        int indexOfTable = indexOfTable(tempNode.hash);
                        Node<K, V> firstNode = newTable[indexOfTable];
                        if (firstNode == null ) {
                            newTable[indexOfTable] = tempNode;
                        }else{
                            newTable[indexOfTable] = new Node(tempNode.k, tempNode.v, tempNode.hash, firstNode);
                        }
                    }
                }
            }

            table = newTable;
            capacitySize = (int)(table.length * loadFactor);
        }
    }

    // 得到更好的hash散列
    private int hash(int h){
        // TODO
        return h;
    }

    // hash值對應的數組的位置
    private int indexOfTable(int hash){
        return hash & (table.length -1);
    }

    private Node<K, V> removeKey(Object key){

        for (int i = 0; i < table.length; i++) {
            Node<K, V> node = table[i];
            if (node == null) {
                continue;
            }else{
                // 鏈表的第一個元素
                if (key == null && node.k == null || key != null && node.k != null
                        && key.hashCode() == node.k.hashCode() && key.equals(node.k)) {
                    table[i] = node.nextNode;

                    size--;
                    modCount++;
                    return node;
                }else{ // 鏈表的非第一個元素
                    Node<K, V> preNode = node;
                    Node<K, V> tempNode = node.nextNode;
                    while (tempNode != null) {
                        if (key == null && tempNode.k == null || key != null && tempNode.k != null
                                && key.hashCode() == tempNode.k.hashCode() && key.equals(tempNode.k)) {

                            preNode.nextNode = tempNode.nextNode;

                            size--;
                            modCount++;
                            return tempNode;
                        }
                        preNode = tempNode;
                        tempNode = tempNode.nextNode;
                    }

                }
            }
        }

        return null;
    }

    @SuppressWarnings("hiding")
    private class Node<K, V> {
        K k;
        V v;
        Node<K, V> nextNode;
        int hash;
        public Node(K k, V v, int hash, Node<K, V> nextNode) {
            this.k = k;
            this.v = v;
            this.hash = hash;
            this.nextNode = nextNode;
        }
    }

    private class Entry implements java.util.Map.Entry<K, V> {

        Node<K, V> node;

        public Entry(Node<K, V> node) {
            this.node = node;
        }

        @Override
        public K getKey() {
            return node.k;
        }

        @Override
        public V getValue() {
            return node.v;
        }

        @Override
        public V setValue(V value) {
            return node.v = value;
        }

    }

    private class EntrySet implements Set<java.util.Map.Entry<K, V>> {

        @Override
        public int size() {
            return MyHashMap.this.size();
        }

        @Override
        public boolean isEmpty() {
            return MyHashMap.this.isEmpty();
        }

        @Override
        public boolean contains(Object o) {
            return false;
        }

        @Override
        public Iterator<java.util.Map.Entry<K, V>> iterator() {
            return new MyIterator();
        }

        @Override
        public Object[] toArray() {
            Object[] array = new Object[MyHashMap.this.size];
            int index = 0;

            Iterator<java.util.Map.Entry<K, V>> iterator = this.iterator();
            for (java.util.Map.Entry<K, V> entry = iterator.next(); iterator.hasNext(); ){
                array[index++] = entry;
            }

            return array;
        }

        @SuppressWarnings("unchecked")
        @Override
        public <T> T[] toArray(T[] a) {

            int index = 0;

            Iterator<java.util.Map.Entry<K, V>> iterator = this.iterator();
            for (java.util.Map.Entry<K, V> entry = iterator.next(); iterator.hasNext(); ){
                if (index < a.length) {
                    a[index++] = (T)entry;
                }else{
                    break;
                }
            }

            return a;
        }

        @Override
        public boolean add(java.util.Map.Entry<K, V> e) {
            return false;
        }

        @Override
        public boolean remove(Object o) {
            return false;
        }

        @Override
        public boolean containsAll(Collection<?> c) {
            return false;
        }

        @Override
        public boolean addAll(Collection<? extends java.util.Map.Entry<K, V>> c) {
            return false;
        }

        @Override
        public boolean retainAll(Collection<?> c) {
            return false;
        }

        @Override
        public boolean removeAll(Collection<?> c) {
            return false;
        }

        @Override
        public void clear() {
            MyHashMap.this.clear();
        }

        public class MyIterator implements Iterator<java.util.Map.Entry<K, V>> {

            private int curreantIndexOfTable = 0;

            private Node<K, V> nextReturnNode = table[0];

            private Node<K, V> lastReturnedNode;

            private int itrModCount = modCount;

            @Override
            public boolean hasNext() {
                return linkHasNext(nextReturnNode);
            }


            @Override
            public java.util.Map.Entry<K, V> next() {
                checkModCount();

                lastReturnedNode = nextReturnNode;
                nextReturnNode = nextReturnNode.nextNode;

                compareNext();
                return new Entry(lastReturnedNode);
            }

            @Override
            public void remove(){
                MyHashMap.this.remove(lastReturnedNode.k);
                itrModCount = modCount;
            }

            private boolean linkHasNext(Node<K, V> nextReturnNode){
                return nextReturnNode != null;
            }

            private void checkModCount(){
                if (this.itrModCount != MyHashMap.this.modCount) throw new RuntimeException("遍歷期間不能刪元素,若是須要,請使用iterator.remove()");
            }

            private void compareNext(){
                if (! linkHasNext(nextReturnNode)) {
                    boolean hashNext = false;
                    while (!hashNext && ++curreantIndexOfTable < table.length) {
                        nextReturnNode = table[curreantIndexOfTable];
                        hashNext = linkHasNext(nextReturnNode);
                    }
                }
            }
        }
    }

    private class KeySet implements Set<K>{

        @Override
        public int size() {
            return MyHashMap.this.size();
        }

        @Override
        public boolean isEmpty() {
            return MyHashMap.this.isEmpty();
        }

        @Override
        public boolean contains(Object o) {
            return MyHashMap.this.containsKey(o);
        }

        @Override
        public Iterator<K> iterator() {
            return new MyKeyIterator();
        }

        @Override
        public Object[] toArray() {
            Object[] array = new Object[size];
            int index = 0;

            Iterator<K> iterator = this.iterator();
            for (K k = iterator.next(); iterator.hasNext(); ){
                array[index++] = k;
            }

            return array;
        }

        @SuppressWarnings("unchecked")
        @Override
        public <T> T[] toArray(T[] a) {
            int index = 0;

            Iterator<K> iterator = this.iterator();
            for (K k = iterator.next(); iterator.hasNext(); ){
                if (index < a.length) {
                    a[index++] = (T)k;
                }else{
                    break;
                }
            }

            return a;
        }

        @Override
        public boolean add(K e) {
            return false;
        }

        @Override
        public boolean remove(Object o) {
            return MyHashMap.this.removeKey(o) != null;
        }

        @Override
        public boolean containsAll(Collection<?> c) {
            for (Object object : c.toArray()) {
                if (! this.contains(object)) {
                    return false;
                }
            }
            return true;
        }

        @Override
        public boolean addAll(Collection<? extends K> c) {
            return false;
        }

        @Override
        public boolean retainAll(Collection<?> c) {
            boolean changed = false;

            for (Object obj : c.toArray()) {
                changed |= this.contains(obj) ? this.remove(obj) : false;
            }
            return changed;
        }

        @Override
        public boolean removeAll(Collection<?> c) {
            boolean changed = false;
            for (Object object : c.toArray()) {
                changed |= this.remove(object);
            }

            return changed;
        }

        @Override
        public void clear() {
            MyHashMap.this.clear();
        }

        private class MyKeyIterator implements Iterator<K> {

            Iterator<java.util.Map.Entry<K, V>> iterator = MyHashMap.this.entrySet().iterator();

            @Override
            public boolean hasNext() {
                return iterator.hasNext();
            }

            @Override
            public K next() {
                return iterator.next().getKey();
            }

            @Override
            public void remove(){
                iterator.remove();
            }
        }

    }
}

寫完HashSet再寫HashMap就比較簡單了,HashMap的Node節點無非就是多了一個value來表示鍵值對。JDK中的HashSet的實現就是直接使用的HashMap,value=new Object(),而後把key-value鍵值對存起來。關於HashMap的基本原理,請參考系列文章(一)。關於HashMao的遍歷方式,請參考系列文章(二)java

相關文章
相關標籤/搜索