《数据结构与算法分析-java语言描述》 - (自制)散列表 - 分离链接法(separate chaining)

类架构

分离链接散列表的类结构

package cn.edut.hash;

import java.util.List;

public class SeparateChainingHashTable <T>{
	/** * 构造 * 使用默认大小 */
	public SeparateChainingHashTable() {
		// TODO Auto-generated constructor stub
	}
	/** * 构造 * 设定大小, * @param size */
	public SeparateChainingHashTable(int size) {
		// TODO Auto-generated constructor stub
	}
	/** * 添加 元素 * @param e */
	public void insert(T e) {
		// TODO Auto-generated method stub
	}
	/** * 删除 元素 * @param e */
	public  void remove(T e) {
		// TODO Auto-generated method stub
	}
	/** * 判断是否包含元素 * @return */
	public boolean contains() {
		// TODO Auto-generated method stub
		return false ;
	}
	/** * 清空散列 */
	public void makeEmpty() {
		// TODO Auto-generated method stub
	}
	/** * 需要是一个素数 */
	private static final int DEFAULT_TABLE_SIZE = 101 ;
	/** * list里面放链表,根据hashcode判断放在哪个链表里面 */
	private List<T>[] keyList ;
	/** * 存量多少个数据 */
	private int currentSize ;  
	
	/** * 扩容 */
	private void rehash() {
		// TODO Auto-generated method stub
	}
	/** * 计算元素hashcode * @return */
	private int myhash(T e) {
		// TODO Auto-generated method stub
		return 0 ; 
	}
	/** * 生产下一个素数 * 是否要静态? */
	private long nextPrime(int n) {
		// TODO Auto-generated method stub
		return 0 ; 
	}
	/** * 判断素数 * 是否要静态? */
	private boolean isPrime(int n ) {
		// TODO Auto-generated method stub
		return false ;
	}
}

上面架构的实现

package cn.edut.algorithm;

import static org.junit.Assume.assumeNotNull;

public class SeparateChainingHashTable<K , V> {
	/** * 构造 使用默认大小 */
	public SeparateChainingHashTable() {
		this(DEFAULT_TABLE_SIZE);
	}

	/** * 构造 设定大小, * * @param size */
	@SuppressWarnings("unchecked")
	public SeparateChainingHashTable(int size) {
		table = new Entry[size];
	}
	
	public int size() {
		return size ; 
	}
	
	/** * 删除 元素 * * @param e */
	public void remove(K key) {
		int hash = hash(key);
		int index = indexFor(hash , table.length);
		Entry<K, V> preEntry =null;
		for(Entry<K, V> e=table[index] ; e!=null ; e=e.next) {
			if((e.key.equals(key) || e.key == key) && hash==e.hash) {
				if(preEntry!= null) {
					preEntry.next = e.next ; 
				}else {
					//只有一个节点
					table[index] = null;
				}
				size--;
			}
			preEntry = e; 
		}
	}

	
	/** * 判断是否包含元素 * * @return */
	public boolean contains(K key) {
		Entry<K, V> entry = getEntry(key);
		return entry!=null;
	}

	/** * 清空散列 */
	public void makeEmpty() {
		for (int i = 0; i < table.length; i++) {
			Entry<K, V> t = table[i] ; 
			table[i] = null ;
			while(t!=null) {
				Entry<K, V> next = t.next ; 
				t.clear();
				t = next ; 
			}
		}
		this.size = 0 ;
	}
	
	public V get(K key) {
		Entry<K, V> entry = getEntry(key);
		
		return entry!=null?entry.value : null ; 
	}

	
	/* ---------------- Fields -------------- */
	
	/** * 需要是一个素数 */
	private static final int DEFAULT_TABLE_SIZE = 3;
	
	/** * list里面放链表,根据hashcode判断放在哪个链表里面 */
	private Entry<K, V>[] table;
	
	/** * 存量多少个数据 */
	private int size;

	/** * 扩容 */
	private void rehash() {
		// TODO Auto-generated method stub
	}
	private Entry<K, V> getEntry(K key) {
		 
		int hash = key==null?0 : hash(key);
		int index = indexFor(hash , table.length);
		for(Entry<K, V> e=table[index] ; e!=null ; e= e.next) {
			K k  = e.key; 
			if(k==key || (k!=null &&  k.equals(key))) {
				return e; 
			}
		}
		return null; 
	}

	/** * 计算元素hashcode * * @return */
	private int hash(K e) {
		int h = e.hashCode() ;
		
		h ^= (h >> 20 )^(h >>12) ;  
		return h^(h >> 8) ^ (h >> 4 );
	}

	private int indexFor(int h , int size) {
		return h%size;
	}
	/** * 生产下一个素数 是否要静态? */
	private long nextPrime(long n) {
		while(isPrime(++n)) {}
		return n;
	}
	/** * 判断素数 是否要静态? */
	private boolean isPrime(long n) {
		if (n < 2) {
			return false;
		} else if (n > 2) {
			if(n%2==0) {
				return false ;
			}else {
				long len = (long) Math.sqrt(n);
				for(long i=3 ; i < len ;i++) {
					if(n%i==0) {
						return false; 
					}
				}
			}
		}	
		return true;
	}
	
	private void addEntry(K key, V value, int hash, int index) {
		if(size>=table.length/2 && table[index]!=null ) {
			resize((int) nextPrime(table.length*2));
			index= indexFor(hash, table.length);
		}
		
		
		Entry<K, V> entry = new Entry<>(table[index], hash, value, key); 
		table[index] = entry ;
		size++;
	}

	private void resize(int newSize) {
		Entry<K, V>[] oldTable = table;
		
		Entry[] newTable = new Entry[newSize];
		transfer(newTable);
		table = newTable;

		
	}

	private void transfer(Entry[] newTable) {
		for (Entry<K,V> e : table) {
			while(e!=null) {
				Entry<K, V> next = e.next;
				int index = indexFor(e.hash , newTable.length);
				e.next = newTable[index];
				newTable[index] = e ; 
				e = next;
			}
		}
	}

	/** * 添加 元素 * * @param e */
	public V insert(K key , V value) {
		
		int hash = key==null?0:hash(key);
		int index = indexFor(hash , table.length);
		Entry<K, V> e = table[index];
		
		//桶上有元素,覆盖
		while (e!=null) {
			if( e.hash == hash && (e.key==key || e.key.equals(key))) {
				V oldValue = e.value ;
				e.value = value ;
				return oldValue ; 
			}
			e = e.next ;
		}
		
		//添加节点
		addEntry(key,value,hash,index);
		return null; 
	}

	private static class Entry<K,V> {
		private Entry<K, V> next ; 
		private int hash ; 
		private V value ; 
		private K key ;
		
		public Entry(Entry<K, V> next, int hash, V value, K key) {
			super();
			this.next = next;
			this.hash = hash;
			this.value = value;
			this.key = key;
		} 
		
		public void clear() {
			next = null; 
			hash = 0 ;
			value = null; 
			key = null; 
		}
		
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("[ ") ; 
		for (Entry<K, V> e : table) {
			while (e!=null) {
				sb.append(e.key) ; 
				sb.append(":");
				sb.append(e.value);
				sb.append(", ");
				e = e.next ;
			}
		}
		sb.delete(sb.length()-", ".length(), sb.length());
		sb.append("]") ; 
		return sb.toString();
	}

}



全部评论

相关推荐

06-13 17:33
门头沟学院 Java
顺序不记了,大致顺序是这样的,有的相同知识点写分开了1.基本数据类型2.基本数据类型和包装类型的区别3.==和equals区别4.ArrayList与LinkedList区别5.hashmap底层原理,put操作时会发生什么6.说出几种树型数据结构7.B树和B+树区别8.jvm加载类机制9.线程池核心参数10.创建线程池的几种方式11.callable与runnable区别12.线程池怎么回收线程13.redis三剑客14.布隆过滤器原理,不要背八股,说说真正使用时遇到了问题没有(我说没有,不知道该怎么回答了)15.堆的内存结构16.自己在写项目时有没有遇见过oom,如何处理,不要背八股,根据真实经验,我说不会17.redis死锁怎么办,watchdog机制如何发现是否锁过期18.如何避免redis红锁19.一个表性别与年龄如何加索引20.自己的项目的QPS怎么测的,有没有真正遇到大数量表21.说一说泛型22.springboot自动装配原理23.springmvc与springboot区别24.aop使用过嘛?动态代理与静态代理区别25.spring循环依赖怎么解决26.你说用过es,es如何分片,怎么存的数据,1000万条数据怎么写入库中27.你说用limit,那么在数据量大之后,如何优化28.rabbitmq如何批次发送,批量读取,答了延迟队列和线程池,都不对29.计网知不知道smtp协议,不知道写了对不对,完全听懵了30.springcloud知道嘛?只是了解反问1.做什么的?短信服务,信息量能到千万级2.对我的建议,基础不错,但是不要只背八股,多去实际开发中理解。面试官人不错,虽然没露脸,但是中间会引导我回答问题,不会的也只是说对我要求没那么高。面完问我在济宁生活有没有困难,最快什么时候到,让人事给我聊薪资了。下午人事打电话,问我27届的会不会跑路,还在想办法如何使我不跑路,不想扣我薪资等。之后我再联系吧,还挺想去的😭,我真不跑路哥😢附一张河科大幽默大专图,科大就是大专罢了
查看30道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务