哈希表的简单应用

哈希表介绍

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

哈希表的优点

我们先前所学的数组和链表都有优缺点:
数组的特点是:寻址容易,插入和删除困难;
链表的特点是:寻址困难,插入和删除容易。
而哈希表综合两者的特性,是一种寻址容易,插入删除也容易的数据结构。

哈希表图例

简单的理解哈希表就是一个数组中的每个元素都是一个链表,链表中存放着需要存储的信息。
用到散列函数去判断信息该放在数组中的哪个链表即可,散列函数的作用实现请看案例实现。
在这里插入图片描述

哈希表简单实现

简单案例

简单理解之后我们来看一道题目
在这里插入图片描述

题目解析

1 创建一个定义员工信息的类
2 创建一个链表的实现类,实现增删改查功能。
3 创建一个数组类,散列函数的方法实现在该类中定义

代码实现

先创建一个员工信息类,偷懒只定义了id和姓名

class Emp {
	public int id;
	public String name;
	public Emp next; // next 默认为 null

	public Emp(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
}

创建一个链表的实现类,实现增删改查功能


	// 头指针,执行第一个Emp,因此我们这个链表的head 是直接指向第一个Emp
	private Emp head; // 默认null

	// 添加雇员到链表
	public void add(Emp emp) {
		// 如果是添加第一个雇员
		if (head == null) {
			head = emp;
			return;
		}
		// 如果不是第一个雇员,则使用一个辅助的指针,帮助定位到最后
		Emp curEmp = head;
		while (true) {
			if (curEmp.next == null) {// 说明到链表最后
				break;
			}
			curEmp = curEmp.next; // 后移
		}
		// 退出时直接将emp 加入链表
		curEmp.next = emp;
	}

	// 遍历链表的雇员信息
	public void list(int no) {
		if (head == null) { // 说明链表为空
			System.out.println("第 " + (no + 1) + " 链表为空");
			return;
		}
		System.out.print("第 " + (no + 1) + " 链表的信息为");
		Emp curEmp = head; // 辅助指针
		while (true) {
			System.out.printf(" => id=%d name=%s\t", curEmp.id, curEmp.name);
			if (curEmp.next == null) {// 说明curEmp已经是最后结点
				break;
			}
			curEmp = curEmp.next; // 后移,遍历
		}
		System.out.println();
	}

	// 根据id查找雇员
	public Emp findEmpById(int id) {
		// 判断链表是否为空
		if (head == null) {
			System.out.println("链表为空");
			return null;
		}
		// 辅助指针
		Emp curEmp = head;
		while (true) {
			if (curEmp.id == id) {// 找到
				break;// 这时curEmp就指向要查找的雇员
			}
			// 退出
			if (curEmp.next == null) {// 说明遍历当前链表没有找到该雇员
				curEmp = null;
				break;
			}
			curEmp = curEmp.next;// 以后
		}

		return curEmp;
	}

	// 删除雇员信息
	public void delete(int id) {
		Emp curEmp = head;
		boolean flag = false;
		// 刪除链表第一个节点
		if (curEmp.id == id ) {
			System.out.printf("已經删除 id為%d,姓名為%s \n", id,curEmp.name);
			head = curEmp.next;
			return;
		}
		//要删除的节点不是第一个节点
			while (true) {
			// 没有找到要删除的节点
			if (curEmp.next == null) {
				break;
			}
			// 找到删除节点
			else if(curEmp.next.id == id) {
				flag = true;
				break;
			}
			curEmp = curEmp.next;
		}
		
		if (flag) {
			System.out.printf("已經删除 id為%d,姓名為%s \n", id,curEmp.next.name);
			curEmp.next = curEmp.next.next;
		} else {
			System.out.printf("要删除id為 %d 不存在\n", id);
		}
	}

	// 修改雇员信息
	public void update(int id, String name) {
		// 判断链表是否为空
		if (head == null) {
			System.out.println("链表为空");
			return;
		}
		// 辅助指针
		Emp curEmp = head;
		while (true) {
			if (curEmp.id == id) {// 找到
				curEmp.name = name;
				break;// 这时curEmp就指向要查找的雇员
			}
			// 退出
			if (curEmp.next == null) {// 说明遍历当前链表没有找到该雇员
				curEmp = null;
				break;
			}
			curEmp = curEmp.next;// 以后
		}
	}
}

创建一个数组类,散列函数的方法实现在该类中定义

class HashTab {
	private EmpLinkedList[] empLinkedListArray;
	private int size; // 表示有多少条链表

	// 构造器,
	public HashTab(int size) {//数组长度又用户决定
		this.size = size;
		// 初始化empLinkedListArray
		empLinkedListArray = new EmpLinkedList[size];
		for (int i = 0; i < size; i++) {
			empLinkedListArray[i] = new EmpLinkedList();
		}
	}

		// 编写散列函数, 使用一个简单取模法
		/*
		*如果id为2,2取余size后的值就是存放在数组对应值的下标。
		*即id为2应放在数组下标为2的链表处
		*/
		public int hashFun(int id) {
		return id % size;
	}
	
	// 添加雇员
	public void add(Emp emp) {
		// 根据员工的id ,得到该员工应当添加到哪条链表
		int empLinkedListNO = hashFun(emp.id);
		// 将emp 添加到对应的链表中
		empLinkedListArray[empLinkedListNO].add(emp);

	}

	// 遍历所有的链表,遍历hashtab
	public void list() {
		for (int i = 0; i < size; i++) {
			empLinkedListArray[i].list(i);
		}
	}

	// 根据输入的id,查找雇员
	public void findEmpById(int id) {
		// 使用散列函数确定到哪条链表查找
		int empLinkedListNO = hashFun(id);
		Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);
		if (emp != null) {// 找到
			System.out.printf("在第%d条链表中找到 雇员 id = %d\n", (empLinkedListNO + 1), id);
		} else {
			System.out.println("在哈希表中,没有找到该雇员~");
		}
	}

//输入id删除雇员
	public void delete(int id) {
		int empLinkedListNO = hashFun(id);
		empLinkedListArray[empLinkedListNO].delete(id);
	}

//输入id,修改雇员名字
	public void update(int id, String name) {
		int empLinkedListNO = hashFun(id);
		empLinkedListArray[empLinkedListNO].update(id, name);
	}
}

最后在Demo类的主方法中调用即可。

public class HashTabDemo {

	public static void main(String[] args) {

		// 创建哈希表
		HashTab hashTab = new HashTab(7);

		Emp emp1 = new Emp(4, "张三");
		Emp emp2 = new Emp(2, "李四");
		Emp emp3 = new Emp(9, "王五");
		Emp emp4 = new Emp(31, "苏七");
		hashTab.add(emp1);
		hashTab.add(emp2);
		hashTab.add(emp3);
		hashTab.add(emp4);

		hashTab.list();
		System.out.println("______________________________");
	    hashTab.findEmpById(4);
		//hashTab.delete(9);
		//hashTab.update(4, "夫斯基");
		System.out.println("______________________________");
		hashTab.list();
	}

}

这就是我对哈希表的简单理解,如有错误敬请指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值