Java用数组和链表的方式简单实现HashMap的增删改功能

hashMap简单实现

hashMap是我们常用的一种java集合类,在jdk1.8中以数组+链表+红黑树实现。使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket(桶)位置来储存对象。
Java用数组和链表的方式简单实现HashMap的增删改功能_第1张图片
以下解释引自https://www.cnblogs.com/fengli9998/p/12092408.html

put存值的方法,过程如下:

①.判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容;

②.根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③;

③.判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals;

④.判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向⑤;

⑤.遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可;

⑥.插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。

get取值的方法,过程如下:

①.指定key 通过hash函数得到key的hash值
int hash=key.hashCode();

②.调用内部方法 getNode(),得到桶号(一般为hash值对桶数求模)
int index =hash%Entry[].length;
jdk1.6版本后使用位运算替代模运算,int index=hash&( Entry[].length - 1);

③.比较桶的内部元素是否与key相等,若都不相等,则没有找到。相等,则取出相等记录的value。

④.如果得到 key 所在的桶的头结点恰好是红黑树节点,就调用红黑树节点的 getTreeNode() 方法,否则就遍历链表节点。getTreeNode 方法使通过调用树形节点的 find()方法进行查找。由于之前添加时已经保证这个树是有序的,因此查找时基本就是折半查找,效率很高。

⑤.如果对比节点的哈希值和要查找的哈希值相等,就会判断 key 是否相等,相等就直接返回;不相等就从子树中递归查找。

本文用数组和链表的方式实现简单的put(key,value)、get(key)和remove(key),未实现hashMap达到扩容阀值是的resize()与相关红黑树的操作,请见谅


//数据域
class Data{
	private int id;
	private String name;
	public Data(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Data [id=" + id + ", name=" + name + "]";
	}
}

class Node{
	private Integer key;   //存入map的key
	private Data data;  //map中的value
	public Node next;   //下一节点
	
	public Node(Integer key, Data data) {
		super();
		this.key = key;
		this.data = data;
	}
	public Integer getKey() {
		return key;
	}
	public void setKey(Integer key) {
		this.key = key;
	}
	
	public Data getData() {
		return data;
	}
	public void setData(Data data) {
		this.data = data;
	}
	public Node getNext() {
		return next;
	}
	public void setNext(Node next) {
		this.next = next;
	}
}

//管理多条链表
class HashMap{
	private int initNum=8;  //hashMap数组初始长度为8,真实的为16
	private LinkedList[] mapList;
	
	//初始化
	public HashMap() {
		mapList=new LinkedList[initNum];
		//初始化每一条链表
		for(int i=0;i<initNum;i++) {
			mapList[i]=new LinkedList();
		}
	}
	
	//添加课程
	public void put(Integer key,Data data) {
		//先用hash算法计算出,添加到的数组下标;
		Node node=new Node(key,data);
		int i=hash(key);
		LinkedList list=mapList[i];
		list.add(node,key);
	}
	
	public void get(Integer key) {
		int i=hash(key);
		LinkedList list=mapList[i];
		list.get(key);
	}
	
	public void  remove(Integer key) {
		int i=hash(key);
		LinkedList list=mapList[i];
		list.remove(key);
	}
	
	//根据key的hash算法获取存储索引,尽可能实现均匀分布
	public int hash(Integer key) {
		return key.hashCode()%mapList.length;
	}
	
public void show() {
		for(int i=0;i<mapList.length;i++) {
			LinkedList list=mapList[i];
		    list.show(i+1);
		}
	}
}


//创建单链表
class LinkedList{
	
	private Node head;//第一个节点,默认为null
	
	//以前插法
	public void add(Node node,Integer key) {
		//第一个节点把Node覆盖head
		if(head==null) {
			head=node;
			return;
		}
		
		//key和首节点相同,覆盖
		 if(head.getKey().equals(key)){  //如果可以key相同,则覆盖值  
			head.setData(node.getData());
			return;
		 }
		 //不相同则前插
		Node temp=head;
		head=node;
		head.next=temp;
	}
	
	public void remove(Integer key) {
		// TODO Auto-generated method stub
		if(head==null) {
			System.out.println("Map中没有key为"+key+"的值,无法删除");
			return;
		}
	     Node curNode=head;
	     //找到要删除的前一个
	     while(true) { 
	    	 if(curNode.next==null||curNode.next.getKey().equals(key)) {
	    		 break;
	    	 } 
	    	 curNode=curNode.next;
	     }
	     
	     if(curNode.next!=null) {
	    	 curNode.next=curNode.next.next;
		     System.out.println("Map中key为"+key+"已被删除");
		    }else {
		       System.out.println("Map中没有key为"+key+"该值,无法删除");
		     }
		
	}

	//通过key获取value
	public void get(Integer key) {
		if(head==null) {
			System.out.println("Map中没有key为"+key+"的值");
			return;
		}
	     Node curNode=head;
	     while(true) { 
	    	 if(curNode==null||curNode.getKey().equals(key)) {
	    		 break;
	    	 } 
	    	 curNode=curNode.next;
	     }
	     if(curNode!=null) {
	     System.out.println(curNode.getData().toString());
	     }else {
	       System.out.println("Map中没有key为"+key+"该值");
	     }
	}
	
	public void show(int num) {
		if(head==null) {
			System.out.println("第"+num+"条链表为空");
			return;
		}
		Node curNode=head;
		System.out.println("第"+num+"条链表数据:");
		while(true) {
			System.out.println("key:"+curNode.getKey()+"  data:"+curNode.getData());
			if(curNode.next==null) {
				break;
			}
			curNode=curNode.next;
		}
	}
}

public class HashMapDemo {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        //利用数组+链表的节点前插方式简单实现HashMap
		//不涉及扩容与jdk8后中的链表长度为8时转化为红黑树

		HashMap map=new HashMap();
		map.put(1, new Data(1,"Java"));
		map.put(2, new Data(2,"C++"));
		map.put(3, new Data(3,"C"));
		map.put(4, new Data(4,"PHP"));
		map.put(8, new Data(5,"MySql"));
		map.put(9, new Data(6,"SqlServer"));
		map.put(10, new Data(7,"Spring"));
		map.put(16, new Data(8,"SpringMvc"));
		map.put(17, new Data(9,"数据结构"));
		map.show();
		System.out.println();
		map.get(1);
		map.get(18);
		map.remove(9);
		map.remove(20);
		map.show();
	}
}

实例
Java用数组和链表的方式简单实现HashMap的增删改功能_第2张图片
Java用数组和链表的方式简单实现HashMap的增删改功能_第3张图片

你可能感兴趣的:(Java,数据结构,java,hashmap)