Java仿写HashMap(可以练习数据结构)

代码是大三无聊写的,可能很粗糙,勿怪勿怪!!!
都知道hashmap采用了数组+链表+红黑树构成,由于红黑树较为复杂,本人做了简化,采用了平衡二叉树代替红黑树,也省略了链表长度大于8时转化为树的过程,直接就是使用了平衡二叉树。
一、创建时会发生什么?
简单来说就是创建了一个长度为16的数组,用来存数据
二、增删改查
增加或修改:增加元素就是先对key进行hash运算,取余找到对应的数组(就是所谓的hash桶),取余有个妙招,因为hashmap每次扩容都是2倍,初始数组容量又是16,所以数组容量肯定是2的指数,对于取余我们可以  hash值 &(数组长度 -1)就是我们要找的余数。找到了就可以开始各种判断了,首先当前数组有没有数据,没有就直接放进去就可以了,有的话就需要开始对比hash值了,小就去左边,大就去右边,然后继续比,一直找到相同的,或者到最后都没有就插入。但是即使找到相同的hash值了,我们也要避免hash冲突,去对比值,本程序采用了链表解决hash冲突,可以当作就是在树的节点后面加尾巴。当值插入完成后,开始判断树是否失衡,失衡就需要旋转来保证平衡,平衡问题解决后又要开始解决扩容问题,这时就有一个所谓的负载因子,就是一个浮点型数据,比如hashmap是0.75,可以自己定义,用来判断什么时候扩容,比如数组长度16,有12个数组有数据就需要扩容了,还有一种情况,就是数组长度小于64,其中有桶里面的元素大于8,也会扩容。修改就是找相同的元素时替换它的值。
删除:删除也是先通过hash值找到桶,去树里面判断并找到元素,但是删除有一些复杂,因为我们要删除某个元素后保证其他所有的元素在树上的位置保持正常,也是左小右大,比如我们要删除的一个元素有左右孩子,我们就不能简单删除,本人是找元素来替代,找被删除的元素的右孩子的左孩子的左孩子。。。。一直找到最后一个,就是我们要的元素。删除后也需要判断是不是失衡,但是不需要考虑扩容问题。
查询:查询和修改类似,经过上面的判断找到元素,或者找不到返回空。
三、代码
import java.util.HashMap;
import java.util.Objects;

public class JavaMap<Key,Value> implements Cloneable{

    public static void main(String[] args) {
        System.out.println(32 & 15);

    }
    private int mapsSize = 16;  //数组的长度
    private int dataSize = 0; //判断是否需要扩容
    private Map[] maps = new Map[mapsSize];
    private int size = 0; //数据的个数
    private String mapString = "";
    private final static float expansion_factor = 0.75F;
    private static boolean is;
    public void put(Key key,Value value){
        int keyHash = Hash(key) & (mapsSize-1);
        //当存放位置为空时 直接存入
        if(maps[keyHash]==null){
            maps[keyHash] = new Map(key,value);
            dataSize++;
            size++;
            expansion(false);
        } else {
            //当存放位置不为空时,创建node结点表示第一个结点
            putNode(maps[keyHash],new Map(key,value));
            //树过高触发扩容机制
            expansion(getLength(maps[keyHash]) >= 3 && mapsSize <= 64);
            //判断是否失衡,失衡后的处理
            rotationTree(maps[keyHash]);
        }
    }
    public Value get(Key key){
        int keyHash = Hash(key) & (mapsSize-1);
        if(maps[keyHash] == null){
            return null;
        }
        if(Objects.equals(maps[keyHash].key, key)){
            return (Value)maps[keyHash].value;
        }
        Map node = getNode(key,maps[keyHash]);
        if(node != null){
            if(node.left != null && Hash(key) == Hash(node.left.key)){
                return (Value) node.left.value;
            }else if(node.right != null && Hash(key) == Hash(node.right.key)){
                return (Value) node.right.value;
            }else if(node.next != null && Hash(key) == Hash(node.next.key)){
                return (Value) node.next.value;
            }
        }
        return null;
    }

    public void remove(Key key){
        int keyHash = Hash(key) & (mapsSize-1);
        if(maps[keyHash] != null){
            Map<Object,Object> newnode = new Map<>(Hash(maps[keyHash].key)+1,null);
            newnode.left = maps[keyHash];
            maps[keyHash] = newnode;
            removeNode(getNode(key,maps[keyHash]),key);
            maps[keyHash] = maps[keyHash].left;
            if(maps[keyHash] == null){
                dataSize--;
            }
        }
        //判断是否失衡,失衡后的处理
        rotationTree(maps[keyHash]);
    }
    public void clear(){
        this.size = 0;
        this.dataSize = 0;
        this.mapsSize = 16;
        this.mapString = "";
        this.maps = new Map[mapsSize];
    }
    public final String toString(){
        mapString = "";
        is = false;
        for (int i = 0; i < mapsSize; i++) {
            if(maps[i]!=null){
                tree(maps[i]);
            }
        }
        if(mapString == ""){
            return "{}";
        }else {
            mapString ="{" + mapString.substring(0,mapString.length()-1) + "}";
            return mapString.replace("'", "\"");
        }
    }
    public Object clone(){
        JavaMap<?,?> result;
        try {
            result = (JavaMap<?,?>)super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }
        return result;
    }
    public int size() {
        return size;
    }
    private void expansion(boolean bool){
        if(dataSize >= mapsSize*expansion_factor || bool){
            //创建存放原数组数据的临时数组
            mapsSize = mapsSize<<1;
            size = 0;
            dataSize = 0;
            Map[] temporaryMaps = maps;
            maps = new Map[mapsSize];
            is = true;
            for (int i = 0; i < temporaryMaps.length; i++) {
                if(temporaryMaps[i]!=null){
                    tree(temporaryMaps[i]);
                }
            }
            return;
        }
    }
    //计算二叉树的高度
    private int getLength(Map root) {
        if(root == null) return 0;
        int left = getLength(root.left);  //左子树的高度
        int right = getLength(root.right); //右子树的高度
        return left>right ? left+1 : right+1;//二叉树的高度为左右子树高度最大值加1
    }
    //树是否平衡
    private boolean isBalance(Map root) {
        //根结点为空,则这个二叉树为平衡二叉树
        if(root == null) return true;
        int left = getLength(root.left);   //左子树的高度
        int right = getLength(root.right); //右子树的高度
        if(Math.abs(left-right)<=1){
            return isBalance(root.left)&&isBalance(root.right);
        }else{
            return false; //只要有一个结点不平衡,则返回false
        }
    }
    //先判断左边最小失衡的节点,左边没有就找右边
    private Map minUnbalanceTerr(Map root) {
        if(root == null) return null;
        if(Math.abs(getLength(root.left)-getLength(root.right)) > 1){
            if(!isBalance(root.left)){
                return minUnbalanceTerr(root.left);
            }else if (!isBalance(root.right)){
                return minUnbalanceTerr(root.right);
            }else {
                return root;
            }
        }
        return null;
    }
    private static final int Hash(Object key) {
        return (key == null) ? 0 : key.hashCode() ^ (key.hashCode() >>> 16);
    }
    private final void tree(Map node){
        concordance(node);
        if(node.left!=null){
            tree(node.left);
        }
        if(node.next!=null){
            tree(node.next);
        }
        if(node.right!=null){
            tree(node.right);
        }
    }
    private void concordance(Map node){
        if(is){
            put((Key) node.key,(Value) node.value);
        } else {
            Object key = node.key;
            Object value = node.value;
            if(node.key instanceof String) key = "'" + node.key + "'";
            if(node.value instanceof String) value = "'" + node.value + "'";
            if(node.value instanceof HashMap) value = InMap((HashMap) node.value);
            if(node.value instanceof char[]) value = InChar((char[]) node.value);
            if(node.value instanceof String[]) value = InString((String[]) node.value);
            mapString = mapString + key + ":" + value + ",";
        }
    }
    private String InMap(HashMap map){
        String str = "";
        for(Object k : map.keySet()){
            Object v = map.get(k);
            if (k instanceof String) k = "'" + k + "'";
            if (v instanceof String) v = "'" + v + "'";
            if (v instanceof char[]) v = InChar((char[]) v);
            if(v instanceof HashMap) v = InMap((HashMap) v);
            str = str + k + ":" + v +",";
        }
        return "{" + str.substring(0,str.length()-1) + "}";
    }
    private String InString(String[] strs){
        String str = "";
        for (String s : strs){
            str = str +"'" + s + "',";
        }
        return "[" + str.substring(0,str.length()-1) + "]";
    }
    private String InChar(char[] chars){
        String str = "";
        for (int i = 0; i < chars.length; i++) {
            str = str + chars[i];
        }
        return "'" + str + "'";
    }
    private Map getNode(Key key,Map headNode){
        while (headNode.left!=null || headNode.right!=null || headNode.next!=null){
            if(headNode.left != null && Objects.equals(headNode.left.key, key)){
                return headNode;
            }
            if(headNode.right != null && Objects.equals(headNode.right.key, key)){
                return headNode;
            }
            if(headNode.next != null && Objects.equals(headNode.next.key, key)){
                return headNode;
            }
            if(headNode.left != null && Hash(key) < Hash(headNode.key)){
                headNode = headNode.left;
            }else if(headNode.right != null && Hash(key) > Hash(headNode.key)){
                headNode = headNode.right;
            }else if(headNode.next != null && Hash(key) == Hash(headNode.key)){
                headNode = headNode.next;
            }else{
                return null;
            }
        }
        return null;
    }
    private void removeNode(Map temp, Key key){
        if(temp == null) return;
        if(temp.left != null && Hash(temp.left.key) == Hash(key)){
            if(temp.left.next != null){
                temp.left.next.left = temp.left.left;
                temp.left.next.right = temp.left.right;
                temp.left = temp.left.next;
            }else if (temp.left.left != null && temp.left.right != null){
                decoupling(temp.left);return;
            }else if(temp.left.left != null && temp.left.right == null){
                temp.left = temp.left.left;
            } else if (temp.left.left == null && temp.left.right != null) {
                temp.left = temp.left.right;
            } else{
                temp.left = null;
            }
        }else if(temp.right != null && Hash(temp.right.key) == Hash(key)){
            if(temp.right.next != null){
                temp.right.next.left = temp.right.left;
                temp.right.next.right = temp.right.right;
                temp.right = temp.right.next;
            }else if(temp.right.left != null && temp.right.right != null){
                decoupling(temp.right);return;
            }else if(temp.right.left != null || temp.right.right == null){
                temp.right = temp.right.left;
            } else if (temp.right.left == null || temp.right.right != null) {
                temp.right = temp.right.right;
            } else{
                temp.right = null;
            }
        }else if(temp.next != null && Hash(temp.next.key) == Hash(key)){
            temp.next = temp.next.next;
        }
        size--;
    }
    private Map getSuccessor(Map temp){
        return temp.left == null ? temp : getSuccessor(temp.left);
    }
    private void putNode(Map node,Map newnode){
        while(node!=null){
            if(Objects.equals(newnode.key, node.key)){
                node.value = newnode.value;
                return;
            }
            //便利分支,判断下一步改往哪走
            if(node.left!=null && Hash(newnode.key)<Hash(node.key)){
                node = node.left;
            }else if(node.next!=null && Hash(newnode.key)==Hash(node.key)){
                node = node.next;
            }else if(node.right!=null && Hash(newnode.key)>Hash(node.key)){
                node = node.right;
            }else {
                //走到这,说明找到目标位置的父结点,继续判断目标位置在父结点哪个方向
                if(node.left==null && Hash(newnode.key)<Hash(node.key)){
                    node.left = newnode;
                }else if(node.next==null && Hash(newnode.key)==Hash(node.key)){
                    node.next = newnode;
                }else{
                    node.right = newnode;
                }
                size++;
                return;
            }
        }
    }
    private void decoupling(Map temp){
        Map successor = getSuccessor(temp.right);
        temp.key = successor.key;
        temp.value = successor.value;
        //删除后继节点
        if(Hash(temp.key) == Hash(temp.right.key)){
            temp.right = temp.right.right;
        }else {
            removeNode(getNode((Key)successor.key,temp.right),(Key)successor.key);
        }
    }
    private void rotationTree(Map node){
        while (true) {
            Map UnbalanceNode = minUnbalanceTerr(node);
            if (UnbalanceNode == null) return;
            if (getLength(UnbalanceNode.left) > getLength(UnbalanceNode.right)) {
                if (getLength(UnbalanceNode.left.left) > getLength(UnbalanceNode.left.right)) {
                    //左左旋
                    Map rightnode = new Map<>(UnbalanceNode.key, UnbalanceNode.value, UnbalanceNode.left.right, UnbalanceNode.right, UnbalanceNode.next);
                    assignment(UnbalanceNode,UnbalanceNode.left,UnbalanceNode.left.left,rightnode);
                } else {
                    //左右旋
                    Map rightnode = new Map<>(UnbalanceNode.key, UnbalanceNode.value, UnbalanceNode.left.right.right, UnbalanceNode.right, UnbalanceNode.next);
                    Map leftnode = new Map<>(UnbalanceNode.left.key, UnbalanceNode.left.value, UnbalanceNode.left.left, UnbalanceNode.left.right.left, UnbalanceNode.left.next);
                    assignment(UnbalanceNode,UnbalanceNode.left.right,leftnode,rightnode);
                }
            } else {
                if (getLength(UnbalanceNode.right.left) > getLength(UnbalanceNode.right.right)) {
                    //右左旋
                    Map leftnode = new Map<>(UnbalanceNode.key, UnbalanceNode.value, UnbalanceNode.left, UnbalanceNode.right.left.left, UnbalanceNode.next);
                    Map rightnode = new Map<>(UnbalanceNode.right.key, UnbalanceNode.right.value, UnbalanceNode.right.left.right, UnbalanceNode.right.right, UnbalanceNode.right.next);
                    assignment(UnbalanceNode,UnbalanceNode.right.left,leftnode,rightnode);
                } else {
                    //右右旋
                    Map leftnode = new Map<>(UnbalanceNode.key, UnbalanceNode.value, UnbalanceNode.left, UnbalanceNode.right.left, UnbalanceNode.next);
                    assignment(UnbalanceNode,UnbalanceNode.right,leftnode,UnbalanceNode.right.right);
                }
            }
        }
    }
    private void assignment(Map Node,Map Node1,Map leftnode,Map rightnode){
        Node.key = Node1.key;
        Node.value = Node1.value;
        Node.next = Node1.next;
        Node.left = leftnode;
        Node.right = rightnode;
    }
    private class Map<Key,Value> {
        Key key;
        Value value;
        Map left;
        Map right;
        Map next;
        public Map(Key key,Value value){
            this.key = key;
            this.value = value;
        }
        public Map(Key key, Value value, Map left, Map right, Map next){
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
            this.next = next;
        }
    }
}
备注:使用方法和hashmap类似 JavaMap<String,Objcet> map = new JavaMap<String,Objcet>; 就可以map.put(key,value)等方法了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值