哈希表
哈希表的基本介绍
散列表(Hash table ,也叫哈希表),是根据关键码值(Key Value)而直接进行访问的数据结构,也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度,这个映射函数就叫做散列函数,存放记录的数组叫做散列表
示例如下图所示
该图是链表和数组的组合
实例
该实例的作用类似于缓存中间间redis之类的,当然没那么精细,理解个原理,图一乐就行了。
要求
哈希表(散列)-google上机题
看一个实际需求,google公司的一个上机题:
有一个公司,当所有新的员工来报道时,要求将该员工的信息加入{id,性别,年龄,住址…},当输入该员工的id时,要求查到该员工的所有信息
要求:不使用数据库,尽量节省内存,速度越快越好》哈希表
添加时,保证按照id从低到高插入【课后思考:如果id不是从低到高插入,但是要求各条链表仍是从低到高,怎么解决?】
1.使用链表来实现哈希表,该链表不带表头
即链表的第一个节点就开始存放雇员的信息
2.思路分析并画出示意图
3.代码实现CRUD
大概思路如图
代码就放下边了
属性没整那么多,基本的crud都有了,id这块的默认是自增的,没有在链表中去加顺序添加,哈哈哈哈嗝,太晚了困了
package com.zrx.test.hashtable;
import java.util.Scanner;
public class hashTableDemo {
public static void main(String[] args) {
HashTable hashTable = new HashTable(7);
String key="";
Scanner scanner = new Scanner(System.in);
while(true){
System.out.println("add:添加雇员");
System.out.println("list:显示雇员");
System.out.println("query:查找雇员");
System.out.println("delete:删除雇员");
System.out.println("exit:退出程序");
System.out.println("modify:修改雇员姓名");
key=scanner.next();
switch (key) {
case "add":
System.out.println("输入id");
int id=scanner.nextInt();
System.out.println("输入名字");
String name=scanner.next();
//创建雇员
Emp emp = new Emp(id, name);
hashTable.add(emp);
break;
case "list":
hashTable.list();
break;
case "query":
System.out.println("请输入id");
int i = scanner.nextInt();
Emp byId = hashTable.findById(i);
System.out.println(byId);
break;
case "delete":
System.out.println("请输入id");
int i1 = scanner.nextInt();
hashTable.deleteById(i1);
break;
case "modify":
System.out.println("请输入id");
int i2 = scanner.nextInt();
System.out.println("请输入姓名");
String next = scanner.next();
hashTable.modifyById(i2,next);
break;
case "exit":
scanner.close();
System.exit(0);
}
}
}
}
//创建hashtable 管理多条链表
class HashTable{
private EmpLinkList[] empLinkedListArr;
private int size;//表示共有多少条链表
public HashTable(int size){
this.size=size;
//初始化empLinkedListArr
empLinkedListArr=new EmpLinkList[size];
//分别初始化每个链表
for (int i = 0; i <size ; i++) {
empLinkedListArr[i]=new EmpLinkList();
}
}
//添加雇员
public void add(Emp emp){
//根据员工的id,得到该员工应该添加进哪条链表
int empLinkedListNum=hashFun(emp.id);
//将emp添加到对应的链表中
empLinkedListArr[empLinkedListNum].add(emp);
}
//遍历所有链表,即遍历哈希表
public void list( ){
for (int i = 0; i <size ; i++) {
empLinkedListArr[i].list(i);
}
}
//根据id查找雇员
public Emp findById(int id){
int test=hashFun(id);
if(empLinkedListArr[test].getHead()==null){
System.out.println("链表为空");
return null;
}
//辅助指针
Emp temp=empLinkedListArr[test].getHead();
while(true){
if(temp.id==id){
break;
}
if(temp.next==null){
break;
}
temp=temp.next;
}
if(temp.id==id){
System.out.println("在"+test+"链表中找到该雇员");
return temp;
}else{
System.out.println("未找到对应雇员信息");
return null;
}
}
//根据id删除雇员
public void deleteById(int id){
int test=hashFun(id);
if(empLinkedListArr[test]==null){
System.out.println("不存在无法删除");
}
Emp temp=empLinkedListArr[test].getHead();
if(temp.id==id){
empLinkedListArr[test].setHead(temp.next);
}else{
while(true){
if(temp.next==null){
System.out.println("不存在无法删除");
break;
}
if(temp.next.id==id){
temp.next=temp.next.next;
return;
}
temp=temp.next;
}
}
}
//根据id修改雇员信息
public void modifyById(int id,String name){
int test=id%size;
if(empLinkedListArr[test]==null){
System.out.println("链表为空无法修改");
}
Emp temp=empLinkedListArr[test].getHead();
while(true){
if(temp.id==id){
temp.setName(name);
break;
}
if(temp.next==null){
System.out.println("链表中无该id");
break;
}
temp=temp.next;
}
}
//编写散列函数,用一个简单的取模法
public int hashFun(int id){
return id % size;
}
}
//表示一个雇员
class Emp{
public int id;
public String name;
public Emp next;//默认为null
public Emp(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
class EmpLinkList{
//头指针指向第一个雇员
private Emp head=null;
public Emp getHead() {
return head;
}
public void setHead(Emp head) {
this.head = head;
}
//添加员工到链表
//说明
//1.假定添加雇员时,id是自增长的,即id的分配总是从小到大
//因此我们将该雇员直接添加到本链表的最后一个即可
public void add(Emp emp){
if(head==null){
head=emp;
return;
}
Emp temp=head;
while(true){
if(temp.next==null){//说明到链表最后
break;
}
temp=temp.next;
}
//退出时直接将emp加入最后即可
temp.next=emp;
}
//遍历链表的雇员信息
public void list(int num){
if(head==null){
System.out.println("当前"+(num+1)+"链表为空");
return;
}
Emp temp=head;
while(true){
System.out.println(temp);
if(temp.next==null){
break;
}
temp=temp.next;//后移遍历
}
}
}