手动实现java常用的容器-hashmap

手动实现java常用的容器-hashmap

 (方法只是模拟java源码,效率没有底层源码高,纯属学习熟悉底层源码)

节点结构图
手动实现java常用的容器-hashmap
容器结构图
手动实现java常用的容器-hashmap

节点源码

package com.alan.alanhashmap;

/**
 * author Mr.ALan
 * DESCRIPTION 一个自定义的hashmap节点对象
 * create 2019/4/11
 */

public class Node<K, V> {

    // 确定在位桶数组的位置,通过hashcode计算得来
    int hash;

    // 用于存放数据的键
    private K key;

    // 用于存放数据的值
    private V value;

    // 用于指向下一个节点
    private Node next;

    public Node(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public Node(int hash, K key, V value) {
        this.hash = hash;
        this.key = key;
        this.value = value;
    }

    public Node() {
    }

    public int getHash() {
        return hash;
    }

    public void setHash(int hash) {
        this.hash = hash;
    }

    public K getKey() {
        return key;
    }

    public void setKey(K key) {
        this.key = key;
    }

    public V getValue() {
        return value;
    }

    public void setValue(V value) {
        this.value = value;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}

容器源码

package com.alan.alanhashmap;

import java.util.ArrayList;
import java.util.HashSet;

/**
 * author Mr.ALan
 * DESCRIPTION
 * create 2019/4/11
 */
@SuppressWarnings("all")
public class AlanHashMap<K, V> {

    // 位桶数组用于散列存放键值对对象
    Node[] table;

    // 默认的位桶数组容量
    public static final int DEFAULT_SIZE = 16;

    // 记录有效的键值对个数
    private int size;

    public AlanHashMap() {
        table = new Node[DEFAULT_SIZE];
    }

    // 用于创建指定大小的位桶数组
    public AlanHashMap(int size) {
        table = new Node[size];
    }

    // 添加一个元素 重复时更新数据
    public void put(K key, V value) {

        Node newNode = new Node(key, value);
        int index = gethash(newNode);
        if (table[index] == null) {
            table[index] = newNode;
            newNode.setHash(index);
            size++;
        } else {
            Node tempNode = table[index];
            do {
                if (tempNode.getKey().equals(newNode.getKey())) {
                    tempNode.setValue(newNode.getValue());
                    return;
                } else {
                    if (tempNode.getNext() == null) {
                        tempNode.setNext(newNode);
                        size++;
                        return;
                    }
                    tempNode = tempNode.getNext();
                }
            } while (tempNode.getNext() != null);
        }

    }

    // 删除一个元素
    public void remove(K key) {
        Node tempNode;
        Node tempNodeLast;
        for (int i = 0; i < table.length; i++) {
            tempNodeLast = table[i];
            tempNode = table[i];
            while (tempNode != null) {
                if (table[i].getKey().equals(key)) {
                    table[i] = table[i].getNext();
                    size--;
                    return;
                }
                if (tempNode.getKey().equals(key)) {
                    tempNodeLast.setNext(tempNode.getNext());
                    size--;
                    return;
                }
                tempNode = tempNode.getNext();
                if (tempNodeLast.getNext() != tempNode) {
                    tempNodeLast = tempNodeLast.getNext();
                }
            }
        }

    }

    // 清空容器
    public void clear() {
        table = null;
        size = 0;
    }

    // 通过键获取一个值
    public V get(K key) {
        HashSet<Node> set = entrySet();
        for (Node node : set) {
            if (node.getKey().equals(key)) {
                return (V) node.getValue();
            }
        }
        return null;
    }

    // 获取所有的键值对对象
    public HashSet<Node> entrySet() {
        HashSet<Node> set = new HashSet<>();
        Node tempNode;

        for (Node node : table) {
            tempNode = node;
            while (tempNode != null) {
                set.add(tempNode);
                tempNode = tempNode.getNext();
            }
        }

        return set;
    }

    // 获取所有的键对象 不可以有重复的值
    public HashSet<K> keySet() {
        HashSet<K> keySet = new HashSet<>();

        for (Node node : entrySet()) {
            keySet.add((K) node.getKey());
        }
        return keySet;
    }

    // 获取所有的值对象 可以有重复的值
    public ArrayList<V> values() {
        ArrayList<V> values = new ArrayList<>();
        for (Node node : entrySet()) {
            values.add((V) node.getValue());
        }
        return values;
    }

    // 返回有效的键值对对数
    public int size() {
        return size;
    }

    // 判断是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    // 利用节点的key和位桶数组的长度来计算节点的hash值(hash值不是hashcode值,而是由hashcode计算后得来)
    public int gethash(Node node) {
        return node.getKey().hashCode() % table.length;
    }

    // 判断是否包含某个键
    public boolean contains(K key) {
        HashSet<K> ks = keySet();
        for (K k : ks) {
            if (k.equals(key)) {
                return true;
            }
        }
        return false;
    }

    // 打印集合的内容
    @Override
    public String toString() {
        HashSet<Node> set = entrySet();
        StringBuilder sb = new StringBuilder("{");
        if (set.size() == 0) {
            return sb.append('}').toString();
        }
        for (Node node : set) {
            sb.append('[').append(node.getKey()).append(':')
                    .append(node.getValue()).append(']').append((char) 32);
        }
        sb.setCharAt(sb.length() - 1, '}');
        return sb.toString();
    }
}

ps:纯属学习交流,若有错误欢迎纠错

上一篇:Xcode - Apple Mach-O Linker warning


下一篇:Slope Trick 学习笔记