hash表(base之后去看看,好像有基本位运算)

最近的有些东西要用到这玩意,于是又重新来复习了。。。。

以下代码按照我自己对于hash表的印象打出来的,代码不多,中间有些小遗忘才翻了翻别人的代码。

底层代码可能需要看看(毕竟我想知道怎么做到超大数据查询优化效果的hh),位运算和泛型都在底层代码里体现了,可我不太熟悉哈哈。。另外不知道有没有迭代器来简化搜索的过程。

一:链地址法:

package hashtable;

import java.util.*;
//拉链法哈希存储,求出一个hash值,后来如果有相同hash值的,在这个拉链下面找是否有相同的值,如果没有相同的值就存储进去。不然就不进行变动。
public class Hash {
	public static int MAX = 5;
	List[] list;
	public Hash() {
		list = new LinkedList[MAX];
		for(int i = 0;i < MAX;i++) {
			list[i] = new LinkedList<Integer>();
		}
	}
	
	public void add(int key) {
		int h = hash(key);
		if(!contains(key)) {
			list[h].add(key);
		}
	}
	
	public int detete(int key) {
		int h = hash(key);
		int temp = -1;
		//直接remove指定下标好像不行,会和直接删除数据混合。。。。
		Iterator<Integer> it = list[h].iterator();
		while(it.hasNext()) {
			Integer cur = it.next();
			if(key==cur) {
				list[h].remove(cur);
				return cur;
			}
		}
		return temp;
	}
	
	public boolean contains(int key) {
		int h = hash(key);
		Iterator<Integer> iterator = list[h].iterator();
		while(iterator.hasNext()) {
			Integer elem = iterator.next();//它刚开始是指向最开始的值的地址的前一个地方。
			if(elem==key) {
				return true;
			}
		}
		return false;
	}
	
	public int hash(int key) {
		return key%MAX;
	}
	
	public void show() {
		for(int i = 0;i < MAX;i++) {
			if(list[i].isEmpty()) {
				System.out.println("--empty--");
			}else {
				System.out.print(list[i].get(0));
				for(int j = 1;j < list[i].size();j++) {
					System.out.print("->"+list[i].get(j));
				}
				System.out.println();
			}
		}
	}
	
	public static void main(String[] args) {
		Hash hash = new Hash();
		System.out.println("请输入数据:");
		Scanner input = new Scanner(System.in);
		for(int i = 0;i < 12;i++) {
			hash.add(input.nextInt());
		}
		System.out.println(hash.contains(12));
		hash.show();
		System.out.println("输入删除数据:");
		hash.detete(input.nextInt());
		hash.show();
	}

}

二:开放寻址法

这里一般会有一个增长因子的概念,也叫作负载因子,简单点说就是已经被占的位置与总位置的一个百分比,比如一共十个位置,现在已经占了七个位置,就触发了扩容机制,因为它的增长因子是0.7,也就是达到了总位置的百分之七十就需要扩容。拿HashMap来说,当它当前的容量占总容量的百分之七十五的时候就需要扩容了。而且这个扩容也不是简单的把数组扩大,而是新创建一个数组是原来的2倍,然后把原数组的所有元素都重新Hash一遍放到新的数组。

我这里就直接粗暴地将旧数组里面的内容拷贝到新数组就完事了,要做到正确的话应该是要将原先的数组全部hash到新数组当中。

package hashtable;

import java.util.Arrays;

public class Hash2<V> {
	//就不删除节点了,直接抹掉原来的value值就行。
	public Node<V>[] arr;
	//默认长度16
	int DEFAULT_LENGTH = 1<<2;
	//拓增因子。
	double INCREASED_RATE = 0.75;
	//当前hash表长度
	int Maxlen;
	//当前有效元素总数
	static int numElem = 0;
	
	public Hash2() {
		Maxlen = DEFAULT_LENGTH;
		arr = new Node[Maxlen];
		for(int i = 0;i < Maxlen;i++) {
			arr[i] = new Node();
		}
	}
	
	//添加时如果key相同就进行冲突处理
	/**
	 * 添加过程中如果出现重复键值,则覆盖原来的数据。
	 * 寻找key不存在的地方添加
	 * hash表中的nkey决定是否存在,我们自己的key决定是否相同。
	 * hash表中的nkey处如果有内容了,就会依次往后推移。如果中途遇到了相同的key,就会覆盖掉。
	 * 如果没遇到相同的key就会最后找到一个空地方停下来。
	 * 
	 * @param key 键(唯一)
	 * @param value 值
	 * @return void
	 * 
	 */
	public void add(int key,V value) {//因为如果删除了,就会有null存在,所以从一开始就直接全为空
		rehash();
		int nkey = hash(key);
		Node temp = new Node(key,value);
		if(contains(key)) {
			while(arr[nkey].key!=key) {
				nkey = (nkey+1)%Maxlen;
			}
			arr[nkey] = temp;
			return;
		}
		while(arr[nkey].value!=null) {//hash表直接定位,找不到再往后推移,推移的时hash表的nkey,
			nkey = (nkey+1)%Maxlen;	//key值作为唯一判别,如果重复就覆盖掉原来的节点返回
//			System.out.println("12793y9823");
		}
		arr[nkey] = temp;
		numElem++;
	} 
	/**
	 * remove在这里根本是依赖于判断key值是否存在然后删除
	 * @param key
	 * @return V(取决于用户决定的类型)
	 */
	public V remove(int key) {
		if(!contains(key)) {
			return null;
		}
		int nkey = hash(key);
		V res = null;
		while(arr[nkey].key!=key) {
			nkey = (nkey+1)%Maxlen;
		}
		res = arr[nkey].value;
		arr[nkey].value = null;
		numElem--;
		return res;
	}
	
	public boolean contains(int key) {//key值不相同才能加,然后如果转换过来的hash值相同就向后推移。
		int nkey = hash(key);
		int temp = nkey;
		if(arr[nkey].value==null) {//为空
			return false;
		}
		while((temp+1)%Maxlen!=nkey) {
			if(arr[temp].key==key) {
				return true;
			}
			temp = (temp+1)%Maxlen;
//			System.out.println("fhfduisf");
		}
		return false;
	}
	
	public V get(int key) {//获取hash表中元素。
		if(!contains(key)) {
			return null;
		}
		int nkey = hash(key);
		while(arr[nkey].key!=key) {
			nkey = (nkey+1)%Maxlen;
		}
		return arr[nkey].value;
	}
	
	public int hash(int key) {
		return key%5;
	}
	
	public void show() {
		System.out.println("展示结果如下:");
		System.out.println("--------------------------------");
		for(int i = 0;i < Maxlen;i++) {
			if(arr[i].value!=null) {
				System.out.println(arr[i].key+": "+arr[i].value);
			}
		}
		System.out.println("--------------------------------");
	}
	/**
	 * 当hash表内存不足时,自动进行扩容。扩容为原来的二倍大小。
	 */
	public void rehash() {
		if(INCREASED_RATE*Maxlen <= numElem) {
			System.out.println("数组已满,进行扩容,当前数组最大长度为:"+Maxlen);
			int temp = Maxlen;
			Maxlen = Maxlen<<1;
			Node<V>[] narr = new Node[Maxlen];
			for(int i = 0;i < Maxlen;i++) {
				narr[i] = new Node<V>();
			}
			for(int i = 0;i < temp;i++) {
				narr[i] = arr[i];
			}
			System.out.println("扩容后数组最大长度为:"+Maxlen);
			arr = narr;
		}
		
	}
	
	public static void main(String[] args) {
		Hash2<Character> hash = new Hash2();
//		for(int i = 0;i < hash.Maxlen;i++) {
//			System.out.print(hash.arr[i].value+" ");
//		}
		hash.add(2, 'c');
		hash.add(5, 'd');
		hash.add(7, 'f');
		hash.add(8, 'c');
		hash.add(9, 'l');
		hash.add(10, 'r');
		hash.add(11, 'y');
		hash.add(12, 'k');
		System.out.println("有效元素个数:"+numElem);
		hash.show();
		System.out.println(hash.get(8));
	}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值