数据结构之哈希表

一、前言

需要代码的可以去gitee 上取,包括java 基础,数据结构,android, java swing ,java web项目(写的很杂,感谢光临):
https://gitee.com/lzhlovelh

在学习数据结构的哈希表时候,先看完视频,过了几天后记录自己手写哈希表,以便增加自己的映像,顺便写下自己理解。
学习hash表的前提需要了解链表和数组

二、什么是hash表

百度百科:
	散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
通俗理解:
	就相当于一张表格,表格里的元素通过一定的规律存放在表中。

三、代码和分析

数据结构:数组+链表
hash表存储学生信息

学生类(Student)

package com.lzh.hash;

/**
 * @author lzh
 * @create 2022-08-07 17:07
 *
 * Student类:每一个Student都有自己的姓名和id(简单点有两个属性)
 */
public class Student {
    private int id;
    private String name;
    private Student next;// 指向下一个节点

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Student getNext() {
        return next;
    }

    public void setNext(Student next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", next=" + next +
                '}';
    }
}

学生类准备好之后,创建链表类
插入方法写了两个,一个是add,没有做任何限制,另外一个是addByOrder,是按照顺序插入

package com.lzh.hash;

/**
 * @author lzh
 * @create 2022-08-07 17:08
 * <p>
 * StudentLinkedList为链表
 */
public class StudentLinkedList {

    private Student head;// 头指针

    /**
     * 添加元素,没有按顺序添加,也可以添加重复的元素
     *
     * @param student 要添加的节点
     */
    public void add(Student student) {
        // 如果链表的头结点为null,就将将要添加的student节点添加到头节点
        if (head == null) {
            head = student;
            return;
        }
        Student currentStu = head; // 辅助指针,用来遍历链表
        while (true) {
            if (currentStu.getNext() == null) { // 如果遍历的节点的下一个节点为null
                currentStu.setNext(student); // 添加到currentStu的下一个节点
                break;
            }
            currentStu = currentStu.getNext(); // 如果当前的节点的下一个节点不为null, 则移动辅助指针
        }
    }

    /**
     * 按id顺序添加元素
     *
     * @param student
     */
    public void addByOrder(Student student) {
        // 如果链表的头结点为null,就将将要添加的student节点添加到头节点
        if (head == null) {
            head = student;
            return;
        }
        Student currentStu = head; // 辅助指针,用来遍历链表
        while (true) {
            // 如果插入的元素大于当前遍历到的元素
                if (student.getId() > currentStu.getId()) {
                    if (currentStu.getNext() != null) {
                        if (currentStu.getNext().getId() > student.getId()) {
                            student.setNext(currentStu.getNext());
                            currentStu.setNext(student);
                            break;
                        }
                    } else {
                        currentStu.setNext(student);
                        break;
                    }
                } else if (student.getId() == currentStu.getId()) {
                    // 更新
                    currentStu.setName(student.getName());
                    break;
                } else {
                    // 头节点比插入的节点大
                    student.setNext(head);
                    head = student;
                    break;
                }
            currentStu = currentStu.getNext(); // 如果当前的节点的下一个节点不为null, 则移动辅助指针
        }
    }

    /**
     * 通过student 的 id 进行删除
     *
     * @param id
     * @param i  第几条链表
     */
    public void del(int id, int i) {
        // 如果链表为空
        if (head == null) {
            System.out.println("第" + i + "链表为空,无法删除");
            return;
        }

        // 考虑如果删除的是头节点
        if (head.getId() == id) {
            head = head.getNext();
            return;
        }
        // 如果删除的不是头节点
        Student currentStu = head;
        Student currentStuNext = currentStu.getNext();// 指向currentStu的下一个节点
        while (true) {
            // 此条链表中如果存在此id
            if (currentStuNext.getId() == id) {
                currentStu.setNext(currentStuNext.getNext());
                break;
            }
            // 如果currentStuNext为null,则表明已经遍历完此链表了,没有找到此id的节点
            if (currentStuNext.getNext() == null) {
                System.out.println("没有此id的学生,删除无效");
                break;
            }
            currentStu = currentStu.getNext();
            currentStuNext = currentStuNext.getNext();
        }
    }

    /**
     * 更新节点的信息
     */
    public void update(int id, String name, int i) {
        if (head == null) {
            System.out.println("第" + i + "链表为空,更改失败");
            return;
        }

        Student currentStu = head;
        while (true) {
            // 找到id
            if (currentStu.getId() == id) {
                // 更改此id学生的姓名
                currentStu.setName(name);
                break;
            }
            if (currentStu.getNext() == null) {
                System.out.println("没有此id学生,更改无效");
                break;
            }
            currentStu = currentStu.getNext();
        }

    }

    /**
     * 用来显示链表的所有节点
     *
     * @param i 传入遍历时的i的值
     */
    public void list(int i) {
        if (head == null) {
            System.out.println("第" + (i + 1) + "链表为空");
            return;
        }
        System.out.printf("第%d条链表", (i + 1));
        Student currentStu = head; // 辅助指针,用来遍历链表
        while (true) {
            System.out.printf("=> id=%d name=%s\t", currentStu.getId(), currentStu.getName());
            if (currentStu.getNext() == null) {
                break;
            }
            currentStu = currentStu.getNext();
        }
        System.out.println();
    }
}

随后就是供外界使用的HashTableSelf类了,因为链表是不直接提供给外界使用的(对链表进行封装),所以提供一个类即HashTableSelf供外界使用。

package com.lzh.hash;

/**
 * @author lzh
 * @create 2022-08-07 17:09
 * <p>
 * 此类供外访问使用
 */
public class HashTableSelf {

    // 定义一个StudentLinkedList的数组,存放每一条链表
    private StudentLinkedList studentLinkedList[];
    // 声明一个数组大小,通过构造器去赋值
    private int size;

    public HashTableSelf(int size) {
        this.size = size;
        this.studentLinkedList = new StudentLinkedList[size];
        // 为每个数组的元素赋值,否则每个数组的每个元素都为null. 会报空指针异常
        for (int i = 0; i < size; i++) {
            studentLinkedList[i] = new StudentLinkedList();
        }
    }

    /**
     * 供外访问的添加方法
     *
     * @param student
     */
    public void add(Student student) {
        // 获取到当前元素应该在哪一条链表
        int hashCode = hashCode(student.getId());
        studentLinkedList[hashCode].add(student);
    }

    /**
     * 根据id删除元素
     *
     * @param id
     */
    public void del(int id) {
        // 获取到当前元素应该在哪一条链表
        int hashCode = hashCode(id);
        studentLinkedList[hashCode].del(id, hashCode);
    }

    public void update(int id, String name) {
        // 获取到当前元素应该在哪一条链表
        int hashCode = hashCode(id);
        studentLinkedList[hashCode].update(id, name, hashCode);
    }

    /**
     * 供外访问的显示链表方法
     */
    public void list() {
        for (int i = 0; i < size; i++) {
            studentLinkedList[i].list(i);
        }
    }

    /**
     * 映射规则
     *
     * @return 返回的值表示在该元素在数组中存放的位置
     */
    public int hashCode(int id) {
        return id % size;
    }

}

最后就是测试代码,main函数:

package com.lzh.hash;

import java.util.Scanner;

/**
 * @author liuzhihao
 * @create 2022-08-07 17:51
 *
 * 控制台用来测试
 */
public class Console {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println("======请输入您的操作======");
            System.out.println("add:    添加学生");
            System.out.println("del:    添加学生");
            System.out.println("update: 添加学生");
            System.out.println("list:   查询所有");
            System.out.println("exit:  退出系统");
            String input = scanner.next();
            switch (input) {
                case "add":
                    System.out.print("请输入添加学生的id:");
                    int inputId = scanner.nextInt();
                    System.out.print("请输入添加学生的name:");
                    String inputName = scanner.next();
                    Student inputStudent = new Student(inputId, inputName);
                    hashTableSelf.add(inputStudent);
                    break;
                case "del":
                    System.out.print("请输入要删除学生的id:");
                    int delId = scanner.nextInt();
                    hashTableSelf.del(delId);
                    break;
                case "update":
                    System.out.print("请输入添加学生的id:");
                    int updateId = scanner.nextInt();
                    System.out.print("请输入添加学生的name:");
                    String updateName = scanner.next();
                    hashTableSelf.update(updateId, updateName);
                    break;
                case "list":
                    hashTableSelf.list();
                    break;
                case "exit":
                    System.out.println("退出系统成功!");
                    scanner.close();
                    System.exit(0);
                default:
                    System.out.println("请正确输入操作");
                    break;
            }

        }

    }

}

四、测试结果

4.1 运行起来
上述数据是测试时手动加入。
在这里插入图片描述

4.2 add
在这里插入图片描述
4.3 del
在这里插入图片描述
4.4 update
在这里插入图片描述
4.5 list
最后list就是显示链表中所有的元素
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值