(数据结构和算法)哈希表的讲解和案例实现

哈希表

一般的数据实现

看一个实际需求,google公司的一个上机题:

有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址…),当输入该员工的id时,要求查找到该员工的 所有信息.

要求: 不使用数据库,尽量节省内存,速度越快越好=>哈希表(散列)

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

散列表,哈希表

实现详解

  • 上述图例为韩顺平老师所制。

  • 题目分析:题目要求其实就是实现对象的增删改查,无论你是用queue还是链表都是可以实现的,但是此处要求就是越快越好,面试的情况下这种题目说最简单的当然不是最优解,那么哈希表(散列表)就能在链表的基础上更加提升性能,减少了遍历的时间,数据量越大分的链表越多那么相对减少的时间是十分可观的。

  • 实现:一个数组中放多个链表,放入哪个由id的hash得到,此处用取模得到位置。

  • 过程:员工对象 -> 链表 -> hash表 -> 实现

  • 链表类

class LinkedListEmp{

    private Emp head;//头结点,每个链表需要头结点来定位
    //添加员工
    public void add(Emp nemp){
        if (head == null){//为空直接添加
            head = nemp;
            return;
        }
        Emp temp = head;//一个临时变量
        while (true){
            if (temp.next==null){//成立时说明遍历到链表最后了
                break;
            }
            temp = temp.next;//没到最后就一直向后遍历
        }
        temp.next = nemp;//新员工添加到最后
    }

    //展示所有的员工
    public void show(int n){
        if (head == null){
            System.out.println("链表"+(n+1)+"为空;");
            return;
        }
        Emp temp = head;
        System.out.print("链表"+(n+1)+":");
        while (true){
            System.out.printf("->> %d :%s\t" , temp.id , temp.name);
            if (temp.next == null){
                break;
            }
            temp=temp.next;
        }
        System.out.println();
    }

    //根据id找员工
    public Emp findEmpByID(int id){
        if (head == null){
            System.out.println("此链表为空!");
        }
        Emp temp = head;
        while (true){
            if (temp.id == id){//找到员工号就退出
                break;
            }
            temp = temp.next;
            if (temp.next==null){
                return null;//没找到返回null
            }
        }
        return temp;//返回这个员工
    }

    public void deleteEmpById(int id){//删除员工
        if (head == null){
            System.out.println("此链表为空!");
        }
        Emp temp = head;
        while (true){//此处与普通单链表有区别,如果头结点就是要找的员工,那么直接换头结点
            if (head.id == id){
                head = temp.next;
                System.out.println("删除员工:"+id);
                break;
            }else if (temp.next.id == id){//如果找到将next域指向下下一个对象,那么中间的对象就抛弃了,也就删除了
                temp.next = temp.next.next;
                System.out.println("删除员工:"+id);
                break;
            }
            if (temp.next == null){
                System.out.println("没有找到此员工!!");
                break;
            }
            temp = temp.next;
        }
    }
}
  • 员工类
//员工类
class Emp{
    int id;
    String name ;
    Emp next = null;

    public Emp(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
  • 哈希表
//哈希表
class HashEmpTable{
    int size;
    LinkedListEmp[] hashEmpTable;//定义一个以链表为数据类型的数组

    public HashEmpTable(int size) {//初始化数组和确认空间大小
        this.size=size;
        hashEmpTable = new LinkedListEmp[size];
        for (int i = 0; i < size; i++) {
            hashEmpTable[i] = new LinkedListEmp();
        }
    }
    //添加
    public void add(Emp emp){//直接利用方法取到这个id号的员工所在的链表,用那个链表调用。
        int funId = hashFunId(emp.id);
        hashEmpTable[funId].add(emp);
    }
    
    //展示
    public void show(){
        for (int i = 0; i < size; i++) {
            hashEmpTable[i].show(i);
        }
    }
    //删除
    public void deleteEmpById(int id){//同样,找到链表再删除对象
        int funId = hashFunId(id);
        hashEmpTable[funId].deleteEmpById(id);
    }
    
    //find员工,
    public void findEmpById(int id){
        int funId = hashFunId(id);
        Emp emp = hashEmpTable[funId].findEmpByID(id);
        if (emp != null){
            System.out.printf("在第 %d 条链表找到员工-> %d,姓名是-> %s" , funId , emp.id , emp.name);
        }
    }
    
    //利用取模实现哈希寻找链表号
    public int hashFunId(int id){
        int hashId = id % size;
        return hashId;
    }

}

//员工类
class Emp{
    int id;
    String name ;
    Emp next = null;

    public Emp(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
  • 实现类
public class HashExercise {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        HashEmpTable hashEmpTable = new HashEmpTable(7);
        String oper = "";
        while (true){
            System.out.println("add");
            System.out.println("show");
            System.out.println("find");
            System.out.println("delete");
            System.out.println("exit");
            oper = sc.next();
            switch (oper){
                case "add":
                    System.out.println("请输入员工id");
                    int id = sc.nextInt();
                    System.out.println("请输入员工姓名");
                    String name = sc.next();
                    Emp emp = new Emp(id, name);
                    hashEmpTable.add(emp);
                    break;
                case "show":
                    hashEmpTable.show();
                    break;
                case "find":
                    System.out.println("请输入需要查找的员工ID");
                    int findId = sc.nextInt();
                    hashEmpTable.findEmpById(findId);
                    break;
                case "delete":
                    System.out.println("请输入需要删除的员工ID");
                    int deleteID = sc.nextInt();
                    hashEmpTable.deleteEmpById(deleteID);
                    break;
                case "exit":
                    return;
            }
        }
    }
}

将此例结合会建立对hash表的一个很好的入门思想。

发布了10 篇原创文章 · 获赞 4 · 访问量 1937

猜你喜欢

转载自blog.csdn.net/Kevin__Durant/article/details/100632931