java数据结构基于哈希表的学生通讯录程序设计

简介: 利用哈希表的思想设计一个能快速查询的学生通讯录程序。每个学生的信息至少包括:学号(10个数字)、姓名(不超过20字符)、手机号码(11个数字)。程序主要功能:从键盘输入学生通讯录,以学号为关键字建立哈希表,酌情设计哈希函数和处理冲突的策略;采用哈希表方法根据输入的学号显示该学生的通讯录信息;能够修改学生的手机号码;能够添加和删除某个学生的通讯录信息。

仅供参考

利用哈希表的思想设计一个能快速查询的学生通讯录程序。每个学生的信息至少包括:学号(10个数字)、姓名(不超过20字符)、手机号码(11个数字)。程序主要功能:从键盘输入学生通讯录,以学号为关键字建立哈希表,酌情设计哈希函数和处理冲突的策略;采用哈希表方法根据输入的学号显示该学生的通讯录信息;能够修改学生的手机号码;能够添加和删除某个学生的通讯录信息。

要求:

(1) 请查阅参考文献了解哈希表的发展历史和应用背景,了解其优缺点和适用场合。

(2) 详细阐述哈希函数和处理冲突的设计思路和内容。

(3) 详细阐述程序主要数据的逻辑结构和存储结构,并说明其理由。

(4) 给出带有适当注释的源程序。

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

哈希表的优点:不论哈希表中有多少数据,在进行查找、插入、删除的操作时运算得非常快,因为它的时间复杂度为O(1)。

哈希表的缺点:哈希表是基于数组的,数组创建后难于扩展,某些哈希表被基本填满时,性能下降得非常严重。

哈希表的适用场合:适用于加密,解决冲突问题;适用于那种查找性能要求高,数据元素之间无逻辑关系要求的情况,在计算机程序中,如果需要在一秒种内查找上千条记录通常使用哈希表(例如拼写检查器)哈希表的速度明显比树快,树的操作通常需要O(N)的时间级。哈希表不仅速度快,编程实现也相对容易。

(2)哈希函数设计思路就是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应,它依赖于键的类型,对于每一种可能使用的键我们需要不同的函数。为了高效,通常避免使用显示类型转换,尽力代之以将键视为机器字的二进制正数表示的思想,这样有利于对其使用算术运算。一个优秀的哈希函数应该考虑到键的所有位,尤其对于由字符组成的键。要计算出长键的取模哈希函数,可以将键分块转换。或者用两个或三个不同的hash函数,进行多次hash以减少键的冲突。

无论哈希函数设计有多么精细,都会产生冲突现象,也就是2个关键字处理函数的结果映射在了同一位置上,因此,有一些方法可以避免冲突。拉链法,拉出一个动态链表代替静态顺序存储结构,可以避免哈希函数的冲突,不过缺点就是链表的设计过于麻烦,增加了编程复杂度。此法可以完全避免哈希函数的冲突。多哈希法,设计二种甚至多种哈希函数,可以避免冲突,但是冲突几率还是有的,函数设计的越好或越多都可以将几率降到最低。开放定址法,从发生冲突的那个单元起,按照一定的次序,从哈希表中找到一个空闲的单元。然后把发生冲突的元素存入到该单元的一种方法。开放定址法需要的表长度要大于等于所需要存放的元素。在开放定址法中解决冲突的方法有:线行探查法、平方探查法、双散列函数探查法。开放定址法的缺点在于删除元素的时候不能真的删除,否则会引起查找错误,只能做一个特殊标记。只到有下个元素插入才能真正删除该元素。线行探查法,线行探查法是开放定址法中最简单的冲突处理方法,它从发生冲突的单元起,依次判断下一个单元是否为空,当达到最后一个单元时,再从表首依次判断。直到碰到空闲的单元或者探查完全部单元为止。

(3)该程序的数据集合采用的是HashMap进行存储的,在jdk1.8之前HashMap采用的是数组加链表来进行存储的,在jdk1.8之后采用了数组加链表加红黑树来进行存储,当HashMap数组元素为链表的时候,插入直接使用头插,插入复杂度O(1);当链表长度达到了八个时,就会转换为红黑树,复杂度为O(logn),这样虽然提高了查找的性能,但每次插入新的数据,都要维护红黑树的结构,这样算是对查找和插入元素时性能的一个权衡。

使用HashMap的理由就是这样的结构结合了链表在增删方面的高效和数组在寻址上的优势,使得程序运行效率提高。

(4)首先需要定义一个Student类用于存储学生信息,该类包含了学生的学号、姓名、手机号码三个属性,然后需要定义一个Map集合用于存储学生集合,因为学生的学号是唯一的,所以key值采用学生学号,value值就是学生对象,然后该系统需要多次交互,所以需要使用while(true)来保证程序一直运行,为了方便操作,每次程序开始和操作完成后系统都会显示菜单,匹配用户输入的菜单编号,即可执行对应的方法,如果输入的编号不对,则提示不支持该操作!当选择查询时,提示输入学号,然后读取输入的学号,调用map的get方法,判断结果是否为空即可,也可以调用map的containsKey方法判断是否为true,如果没有查询到则输出没有查询到该学生!否则输入学生信息;在新增、删除、修改手机号这几个操作时,同样使用get或containsKey方法进行查询,新增时还需使用put方法,删除时需要使用remove方法,修改手机号时也是使用的put方法,调用该方法时,如果key值不存在则新增,如果key值存在则会修改value值做到数据的更新。程序在编码过程中均考虑了用户输入信息的合法性,如果信息不合法时,会抓住异常给予用户提示,提高了程序的健壮性。

程序添加的实现效果如图4.1所示,修改功能如图4.2所示,删除功能如图4.3所,程序的查询功能图上均有用到,不再单独列出。


图片涉及个人隐私无法查看


该程序的实现代码如下:

import java.util.HashMap;
import java.util.Scanner;
/**
 * @author baikunlong
 * @date 2020/6/23 22:33
 */
public class Main {
    private static Scanner scanner;
    /**
     * 学生信息集合
     */
    private static HashMap<String, Student> map;
    public static void main(String[] args) {
        System.out.println("欢迎使用本系统~");
        scanner = new Scanner(System.in);
        String line = "";
        map = new HashMap<>();
        while (true) {
            System.out.println();
            System.out.println("菜单(输入对应序号即可进入操作)");
            System.out.println("1、根据学号查询");
            System.out.println("2、根据学号修改手机号");
            System.out.println("3、添加");
            System.out.println("4、删除");
            System.out.println("5、退出");
            line = scanner.nextLine().trim();
            switch (line) {
                case "1":
                    select();
                    break;
                case "2":
                    update();
                    break;
                case "3":
                    add();
                    break;
                case "4":
                    del();
                    break;
                case "5":
                    System.out.println("再见,欢迎下次使用~");
                    return;
                default:
                    System.out.println("不支持该操作!");
                    break;
            }
        }
    }
    /**
     * 修改学生手机号
     */
    private static void update() {
        try {
            System.out.println("请输入要修改手机号学生的学号和手机号,分别用空格隔开,输入完成后按回车:");
            String s = scanner.nextLine();
            String[] strings = s.split(" ");
            //如果包含该key,则存在该学生
            if (map.containsKey(strings[0])) {
                //取出该学生
                Student student = map.get(strings[0]);
                //修改手机号
                student.setPhone(strings[1]);
                //重新设置该key值的学生对象
                map.put(student.sno, student);
                System.out.println("修改成功!");
            } else {
                System.out.println("该学生不存在!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("输入信息有误!操作失败!");
        }
    }
    /**
     * 删除学生
     */
    private static void del() {
        System.out.println("请输入要删除的学生的学号:");
        String s = scanner.nextLine();
        //如果包含该key
        if (map.containsKey(s)) {
            //移除该key
            map.remove(s);
            System.out.println("删除成功!");
        } else {
            System.out.println("该学生不存在!");
        }
    }
    /**
     * 新增学生
     */
    private static void add() {
        try {
            System.out.println("请输入学号、姓名、手机号,分别用空格隔开,输入完成后按回车");
            String s = scanner.nextLine();
            String[] strings = s.split(" ");
            //如果已存在该key值,则不能插入了
            if (map.containsKey(strings[0])) System.out.println("该学生已存在!");
            else {
                //新增学生信息
                map.put(strings[0], new Student(strings[0], strings[1], strings[2]));
                System.out.println("添加成功!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("输入信息有误!操作失败!");
        }
    }
    /**
     * 查询学生
     */
    private static void select() {
        System.out.println("请输入学号:");
        String s = scanner.nextLine();
        //根据key值获取value值
        Student student = map.get(s);
        if (student == null) System.out.println("没有查询到该学生!");
        else System.out.println(student.toString());
    }
    /**
     * 学生类
     */
    static class Student {
        /**
         * 学号
         */
        private String sno;
        /**
         * 姓名
         */
        private String name;
        /**
         * 手机号
         */
        private String phone;
        @Override
        public String toString() {
            return "学生信息{" +
                    "学号='" + sno + '\'' +
                    ", 姓名='" + name + '\'' +
                    ", 手机号='" + phone + '\'' +
                    '}';
        }
        public String getSno() {
            return sno;
        }
        public void setSno(String sno) {
            this.sno = sno;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getPhone() {
            return phone;
        }
        public void setPhone(String phone) {
            this.phone = phone;
        }
        public Student(String sno, String name, String phone) {
            this.sno = sno;
            this.name = name;
            this.phone = phone;
        }
    }
}

目录
相关文章
|
2月前
|
Java
【Java集合类面试二十六】、介绍一下ArrayList的数据结构?
ArrayList是基于可动态扩展的数组实现的,支持快速随机访问,但在插入和删除操作时可能需要数组复制而性能较差。
|
2月前
|
存储 设计模式 算法
JAVA中的常见数据结构
JAVA中的常见数据结构
|
8天前
|
Java
java数据结构,双向链表的实现
文章介绍了双向链表的实现,包括数据结构定义、插入和删除操作的代码实现,以及双向链表的其他操作方法,并提供了完整的Java代码实现。
java数据结构,双向链表的实现
|
8天前
|
存储 Java
java数据结构,线性表链式存储(单链表)的实现
文章讲解了单链表的基本概念和Java实现,包括头指针、尾节点和节点结构。提供了实现代码,包括数据结构、接口定义和具体实现类。通过测试代码演示了单链表的基本操作,如添加、删除、更新和查找元素,并总结了操作的时间复杂度。
java数据结构,线性表链式存储(单链表)的实现
|
16天前
|
存储 Java Serverless
【数据结构】哈希表&二叉搜索树详解
本文详细介绍了二叉搜索树和哈希表这两种数据结构。二叉搜索树是一种特殊二叉树,具有左子树节点值小于根节点、右子树节点值大于根节点的特点,并且不允许键值重复。文章给出了插入、删除和搜索等方法的具体实现。哈希表则通过哈希函数将键名映射为数组下标,实现快速查找,其插入、删除和查找操作时间复杂度理想情况下为O(1)。文中还讨论了哈希函数的设计原则、哈希冲突的解决方法及哈希表的实现细节。
23 8
【数据结构】哈希表&二叉搜索树详解
|
3天前
|
存储 安全 Java
Java 数据结构类型总结
在 Java 中,常用的数据结构包括基础数据结构(如数组和字符串)、集合框架(如 Set、List 和 Map 接口的多种实现)、特殊数据结构(如栈、队列和双端队列)、链表(单链表、双链表和循环链表)以及图和树等。这些数据结构各有特点和适用场景,选择时需考虑性能、内存和操作需求。集合框架提供了丰富的接口和类,便于处理对象集合。
|
8天前
|
存储 Java
java数据结构,线性表顺序存储(数组)的实现
文章介绍了Java中线性表顺序存储(数组)的实现。线性表是数据结构的一种,它使用数组来实现。文章详细描述了线性表的基本操作,如增加、查找、删除、修改元素,以及其他操作如遍历、清空、求长度等。同时,提供了完整的Java代码实现,包括MyList接口和MyLinearList实现类。通过main函数的测试代码,展示了如何使用这些方法操作线性表。
|
2月前
|
存储 Java
数据结构中的哈希表(java实现)利用哈希表实现学生信息的存储
这篇文章通过Java代码示例展示了如何实现哈希表,包括定义结点类、链表类、数组存储多条链表,并使用简单的散列函数处理冲突,以及如何利用哈希表存储和查询学生信息。
数据结构中的哈希表(java实现)利用哈希表实现学生信息的存储
|
2月前
|
存储 算法 Java
"解锁Java对象数据结构的奥秘:从基础到实战,与热点技术共舞,让你的编程之路更激情四溢!"
【8月更文挑战第21天】Java以对象为核心,它是程序的基本单元与数据处理的基础。对象源自类,拥有属性(字段)和方法。对象在内存中分为对象头(含哈希码、GC信息等)和实例数据区(存储属性值)。例如,`Student`类定义了姓名、年龄等属性及相应的方法。通过`new`关键字实例化对象并调用其方法进行数据操作,是Java编程的关键技能。
29 0
|
3月前
|
缓存 算法 安全
Java中的数据结构与算法优化策略
Java中的数据结构与算法优化策略
下一篇
无影云桌面