数据结构之哈希表

哈希表(散列表)

出现的原因

在顺序表中查找时,需要从表头开始,依次遍历比较a[i]与key的值是否相等,直到相等才返回索引i;在有序表中查找时,我们经常使用的是二分查找,通过比较key与a[i]的大小来折半查找,直到相等时才返回索引i。最终通过索引找到我们要找的元素。

但是,这两种方法的效率都依赖于查找中比较的次数。我们有一种想法,能不能不经过比较,而是直接通过关键字key一次得到所要的结果呢?这时,就有了散列表查找。

数据结构模型

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。

代码实现

  • HashTable
java 复制代码
package org.example.data.structure.hashtable;

import java.util.Objects;

/**
 * @author xzy
 * @since 2024/9/15 11:03
 */
public class HashTable {

    private LinkedList[] linkedLists;

    public HashTable() {
        linkedLists = new LinkedList[8];
        for (int i = 0; i < linkedLists.length; i++) {
            linkedLists[i] = new LinkedList();
        }
    }

    public HashTable(int size) {
        if (size < 0) {
            throw new RuntimeException("未知异常");
        }
        linkedLists = new LinkedList[size];
        for (int i = 0; i < linkedLists.length; i++) {
            linkedLists[i] = new LinkedList();
        }
    }

    public void add(Person person) {
        int i = hash(person.getId());
        LinkedList linkedList = linkedLists[i];
        PersonNode node = new PersonNode();
        node.setData(person);
        linkedList.add(node);
    }

    public void delete(int id) {
        int i = hash(id);
        LinkedList linkedList = linkedLists[i];
        linkedList.delete(id);
    }

    public void update(Person person) {
        int i = hash(person.getId());
        LinkedList linkedList = linkedLists[i];
        linkedList.update(person);
    }

    public Person getById(int id) {
        int i = hash(id);
        LinkedList linkedList = linkedLists[i];
        return linkedList.getById(id);
    }


    public Person[] list() {
        Person[] personArr = new Person[linkedLists.length * 10];
        int i = 0;
        for (LinkedList linkedList : linkedLists) {
            Person[] list = linkedList.list();
            if (Objects.nonNull(list)) {
                for (Person person : list) {
                    if (Objects.nonNull(person)) {
                        personArr[i] = person;
                        i++;
                    }
                }
            }
        }
        return personArr;
    }

    private int hash(int id) {
        // 计算落到哪个链表中
        return id % linkedLists.length;
    }

}
  • 链表实现
java 复制代码
package org.example.data.structure.hashtable;

import java.util.Objects;

/**
 * @author xzy
 * @since 2024/9/15 10:04
 */
public class LinkedList {

    private PersonNode head;

    public void add(PersonNode node) {
        if (Objects.isNull(head)) {
            // 链表未初始化
            head = node;
            return;
        }
        // 获取最后一个节点
        PersonNode tempNode = head;
        while (Objects.nonNull(tempNode.getNext())) {
            tempNode = tempNode.getNext();
        }
        tempNode.setNext(node);
    }

    public void delete(int id) {
        if (Objects.isNull(head)) {
            System.out.println("链表为空, 忽略删除操作");
            return;
        }
        // 先判断是否只有一个节点
        if (Objects.isNull(head.getNext())) {
            if (head.getData().getId() == id) {
                head = null;
            }
        } else {
            PersonNode tempNode = head;
            // 遍历节点
            while (true) {
                PersonNode next = tempNode.getNext();
                if (Objects.isNull(next)) {
                    System.out.println("未找到对应的节点进行删除");
                    break;
                } else {
                    if (next.getData().getId() == id) {
                        tempNode.setNext(next.getNext());
                        break;
                    } else {
                        tempNode = next;
                    }
                }
            }
        }
    }

    public void update(Person person) {
        if (Objects.isNull(head)) {
            System.out.println("链表为空, 不处理");
            return;
        }

        PersonNode tempNode = head;
        while (true) {
            if (Objects.isNull(tempNode)) {
                System.out.println("未找对需要更新的数据, 不处理");
                break;
            }
            if (tempNode.getData().getId() == person.getId()) {
                Person data = tempNode.getData();
                data.setName(person.getName());
                tempNode.setData(data);
                break;
            } else {
                tempNode = tempNode.getNext();
            }
        }
    }

    public Person getById(int id) {
        PersonNode tempNode = head;
        while (true) {
            if (Objects.isNull(tempNode)) {
                System.out.println("未找对需要更新的数据, 不处理");
                return null;
            }
            if (tempNode.getData().getId() == id) {
                return tempNode.getData();
            } else {
                tempNode = tempNode.getNext();
            }
        }
    }

    public Person[] list() {
        if (Objects.isNull(head)) {
            return new Person[0];
        }
        Person[] personArr = new Person[10];
        int i = 0;
        PersonNode tempNode = head;
        while (true) {
            if (Objects.nonNull(tempNode)) {
                personArr[i] = tempNode.getData();
                i++;
                tempNode = tempNode.getNext();
            } else {
                break;
            }
        }
        return personArr;
    }
}

后续优化

  • 未解决哈希冲突(主要是因为hash()实现过于简单)
  • 链表中未实现有序(可在插入时,在单链表中先排序再插入)

源码与测试案例

gitee地址

相关推荐
沫刃起5 分钟前
Codeforces Round 972 (Div. 2) C. Lazy Narek
数据结构·c++·算法
QXH2000001 小时前
Leetcode—环形链表||
c语言·数据结构·算法·leetcode·链表
小灰灰爱代码2 小时前
C++——判断year是不是闰年。
数据结构·c++·算法
小灰灰爱代码2 小时前
C++——求3个数中最大的数(分别考虑整数、双精度数、长整数数的情况),用函数重载方法。
数据结构·c++·算法
爱coding的橙子4 小时前
CCF-CSP认证考试准备第十七天
数据结构·c++·算法
程序猿阿伟5 小时前
《C++移动语义:解锁复杂数据结构的高效之道》
数据结构·c++·html
594h26 小时前
PAT 甲级 1002题
数据结构·c++·算法
snowful world6 小时前
vs2022链表的创建和打印(c语言版)
c语言·数据结构·链表
shylyly_7 小时前
归并排序
数据结构·算法·归并排序·递归归并排序·非递归归并排序
itoshi rin7 小时前
简单题21 - 合并两个有序链表(Java)20240917
java·数据结构·链表