用数组和链表自定义hashmap

本文探讨了哈希表作为一种高效的数据结构是如何结合数组和链表的优势,解决了传统数组和链表在查找与增删操作上的不足。通过具体实例演示了哈希表的基本操作,包括插入、查找等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

在初学数据结构的时候,大家总会对hash函数的理解不那么透彻,只知道它是一种很有优越性的存储结构,而不知其所以然.最近又深入了解了一下hash函数的原理,感到收获颇丰,那么hash函数是怎么应运而生的呢,我来谈谈个人的理解.


在应用数组的时候,我们会发现数组有这样的特性:

1.查找方便,可以通过下标直接查找,速度快,效率高;

2.在增加和删除元素时,需要新建一个数组,在时间和空间上的代价都很大.


考虑到数组存在的缺点,我们会自然地联想到另一种数据结构--链表,链表有如下特点:

1.由于链表是由一个一个结点连接起来而组成的,所以在删除和增加元素时,只需改变指定位置的及前后的两个结点,效率较高。

2.链表在查找时,需遍历链表,时间代价大。


鉴于以上两种数据结构均存在弊端,如果可以即能像数组一样方便的查找,又能像链表一样高效率的存储和删除,那么问题便迎刃而解,由此我们引入了Hashmap这种数据结构,它可以理解为是链表和数组的结合体,我们可以利用数组和链表,自定义一个hash结构。步骤如下:

1.创建一个合适长度的数组;

2.定义一个结点类,里面封装所要存储的信息的属性,以及指向下一个结点的“指针”;

3.每当要加入数据时,根据新结点中的一个序号属性,对该属性取模(例如:num%arr.length),取模后得到数字,及是该新结点对应的数组坐标。如果数组中该坐标对应的位置已经有一个结点或者一条结点链,那么将新数组加到末尾。

    4.当数组中某个下标对应的链表的长度达到一个规定的值(称为 阀值),则扩充数组容量,重新按照3中 的方法进行排列。 

 

 

 

 

package netjava.cn;
/**
 * 结点类
 * @author Administrator
 *
 */
public class Node {
	
	private int num;
	private String name;
	private String pwd;
	private Node next;
	
	public Node(int num,String name,String pwd){
		this.num = num;
		this.name = name;
		this.pwd = pwd;
	}
	public void setNext(Node next){
		this.next = next;
	}
	public Node getNext(){
		return this.next;
	}
	public int getNum() {
		return num;
	}
	public String getName() {
		return name;
	}
	public String getPwd() {
		return pwd;
	}
	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return "序号:"+num+">姓名:"+name+">密码:"+pwd;
	}
}

 

package netjava.cn;
/**
 * 头结点的定义
 * @author Administrator
 *
 */
public class Combine {

	public Combine(Node node) {
		this.node = node;
	}
    
	//链表首结点
	private Node node;
    //链表长度
	private int length = 1;
	
	/**得到链表中最一个结点*/
    public Node lastNode(){
    	Node n = node;
    	while(n.getNext() != null){
    		n = n.getNext();
    	}
    	return n;
    }
    
   /**打印一条链上的所有结点*/
    public void printNode(){
    	Node n = node;
    	System.out.println(n);
    	while(n.getNext() != null){
    		n = n.getNext();
    		System.out.println(n);
    	}
    }
    /**增加链表的长度*/
    public int addLength(){
    	return length++;
    }
    
    
    /*得到首结点*/
	public Node getNode() {
		return node;
	}
	
	public int getLength() {
		return length;
	}
	public void setLength(int length) {
		this.length = length;
	}
}

 

package netjava.cn;

import java.util.Random;

public class DefineHash {

	private int length = 10;
	private int limit = 10;
	private Combine[] arr = new Combine[length];// 存放头结点的数组

	public static void main(String[] args) {
		DefineHash hash = new DefineHash();
		Combine[] arr = hash.buildArr();
		hash.print(arr);
		Node n0 = new Node(23, "后来的", "密码@!!");
		hash.add(n0);
		Node n1= new Node(24, "后来的", "密码@!!");
		hash.add(n1);
		for (int i = 0; i < 100; i++) {
			Node n = new Node(25+i, "后来的", "密码@!!");
			hash.add(n);
		}
	}

	/** 初始化数组 */
	public Combine[] buildArr() {

		// 创建初始容量为length的数组
		arr = new Combine[length];
		// 随机得到50条需要存储的信息
		Random random = new Random();
		for (int i = 0; i < 4; i++) {
			// 随机生成num
			int next = random.nextInt(50);
			// 创建结点
			Node node = new Node(next, "poppy", "12345678");
			// 根据num取模,得到数组中的位置
			int index = next % length;
			// index位置已有元素时
			if (arr[index] != null) {
				Combine com = arr[index];
				// 使链表的长度+1
				com.addLength();
				// 将结点加到末尾
				Node pre = com.lastNode();
				pre.setNext(node);
			} else { // index位置无元素时,赋初始值
				arr[index] = new Combine(node);
			}
		}
		return arr;
	}

	/** 加入数据 */
	public Combine[] add(Node node) {
		// 得到帐号
		int num = node.getNum();
		// 根据num取模,得到数组中的位置
		int index = num % length;
		// index位置已有元素时,将结点加到末尾
		if (arr[index] != null) {
			Combine com = arr[index];
			// 链表长度未达到阀值
			if (com.getLength() < limit) {
				System.out.println("未阀值");
				Node pre = com.lastNode();
				pre.setNext(node);
				com.addLength();
			} else { // 链表长度得到阀值,重新排序
				System.out.println("阀值");
				Combine[] c = reSort(arr);
				arr =c;
			}
		} else { // index位置无元素时,赋初始值
			arr[index] = new Combine(node);
		}
		return arr;
	}

	/** 删除数据 */
	public void delete(Node node) {

	}

	/** 查找数据 */
	public void find(Node node) {

	}

	/** 重新排列 */
	public Combine[] reSort(Combine[] arr) {
		System.out.println("开始重拍!!!");
		length *= 2;// 数组容量扩大到2倍
		limit *= 2;// 将上限扩大2倍
		Combine[] larr = new Combine[length];
		// 遍历数组,得到每个跟结点
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] != null) {
				Combine combine = arr[i];
				// 得到原根结点
				Node n = combine.getNode();
				int num = n.getNum();
				int index = num % length;
				//新数组上index已有结点
				if(larr[index] != null){
					Combine com = larr[index];
					com.addLength();//长度+1
					com.lastNode().setNext(n);
				}else{//新数组上Index没有结点
					larr[index] = combine;
				}
				
			}
		}
		this.print(larr);
		System.out.println("last");
		System.out.println(larr.length+"新书组长度");
		return larr;
	}

	/** 打印hash表 */
	public void print(Combine[] arr) {
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] != null) {
				System.out.println(i + ">>>>>");
				arr[i].printNode();

			}
		}
	}
}

 

<!--EndFragment-->
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值