java实现数据结构课设:通讯录管理系统
以下的代码通过java代码实现了一个简单的通讯录管理系统
1.通过java模拟链表来实现
2.实现来简单的增删改查
3.实现了通过文件来保存通讯录的信息
4.实现自定义异常来提示错误(就是想用以下自定义异常)
5.可以通过姓名和电话号码的字串来查找
6.保证了电话号码的唯一性
进行文件保存时删除或者修改通讯录信息文件实现同步的应对策略:使用一个集合作为过渡单位,将结点信息存储到文件时,先将信息添加进集合,然后存储集合
进行信息的增删改查时,直接将信息存储到集合中,然后将集合存储到文件中(主要是文件不支持增删改查)
- Node类
import java.io.Serializable;
//通讯人员类
class Reporter implements Serializable
{
private static final long serialVersionUID = 2l;
//属性
private String name;//姓名
private int age;//年龄
private String number;//电话号码
public Reporter(){};//空参构造
public Reporter(String name,int age,String number){
setAge(age);
setName(name);
setNumber(number);
}
//行为
public void setName(String name){
this.name = name;
}
public void setAge(int age){
if(age>0&&age<=100){
this.age = age;
}else {
throw new AgeOutOfBoundsException(age+"不在0-100之间");
}
}
public void setNumber(String number ){
this.number = number;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
public String getNumber(){
return this.number;
}
}
//结点类
public class Node implements Serializable {//该类可以实现序列化
private static final long serialVersionUID = 1l;//设置序列号
//属性
private Reporter reporter;//通讯人员
private Node next;//下一个结点的地址
public Node(){};//空参构造
public Node(Reporter reporter,Node next){
setNext(next);
setReporter(reporter);
}
//行为
public void setReporter(Reporter reporter) {//设置通讯人员
this.reporter = reporter;
}
public void setNext(Node next){//设置下一个结点的地址
this.next = next;
}
public Reporter getReporter(){
return this.reporter;
}
public Node getNext(){
return this.next;
}
}
- 自定义异常类
//自定义异常类,用于提示输入的年龄错误
public class AgeOutOfBoundsException extends RuntimeException {
//空参构造
public AgeOutOfBoundsException (){}
//有参构造
public AgeOutOfBoundsException(String message){//用户赋值错误信息
super(message);
}
}
- 结点工具类
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
//结点工具类
public class Nodeutil {
//定义序列化流并实例化
public static ArrayList<Node> list = new ArrayList<>();//定义一个集合临时存储结点
public static int count;//记录结点的数量
//私有构造函数
private Nodeutil() {
}
//1.初始化链表
public static void initList(Node head, int n) throws IOException { //p为头节点的地址,n为需要创建的结点数
Scanner sc = new Scanner(System.in);
Node q = head;//用于后面的连接结点
String name;
int age;
String number;
for (int i = 0; i < n; i++) {
System.out.printf("请输入第%d个节点的姓名:\n", i + 1);
name = sc.nextLine();
System.out.printf("请输入第%d个节点的年龄:\n", i + 1);
age = sc.nextInt();
sc.nextLine();//接收多余的回车
String tempNumber;//临时接收电话号码
while (true){
System.out.printf("请输入第%d个节点的电话号码:\n", i + 1);
tempNumber = sc.nextLine();
if(isUniqueNumber(head,tempNumber)){//电话号码有重复
System.out.println("电话号码输入重复,请重新输入!");
}else {
break;
}
}
number = tempNumber;
//创建新结点
Reporter reporter = new Reporter(name, age, number);
Node node = new Node(reporter, null);
list.add(node);//将结点添加到集合中
serializeNode(list);//将该集合写入文件中
//连接结点
Node p = node;
q.setNext(p);//让第一个结点的引用指向第二个结点
q = p;//q移动到下一个结点
count++;//结点的数量+1
}
}
//2.遍历链表
public static void showList(Node head){
System.out.println(" 姓名 年龄 电话号码");
for (Node p = head.getNext(); p != null; p = p.getNext()) {
System.out.printf("%12s",p.getReporter().getName());
System.out.printf("%12d",p.getReporter().getAge());
System.out.printf("%12s",p.getReporter().getNumber());
System.out.println("");
System.out.println("-----------------------------------------------------------------------");
}
}
//3.按照位置删除
public static boolean removeList(Node head,int pos) throws IOException {//传入头节点地址和删除的位置
//进行删除位置合理性的判断
if(pos<=0 ||pos>count){
return false;
}
//1.找到要删除位置结点的前一个结点的地址
Node p = head;//p初始指向头节点
int n =0;//记录已经遍历了的结点个数
while (n<pos-1){
p = p.getNext();//遍历节点
n++;//更新遍历结点的个数
}
//2.进行结点删除
p.setNext(p.getNext().getNext());
list.remove(pos-1);//删除集合中对应的结点
serializeNode(list);//重新将修改后的集合添加到文件中
count--;//结点数量-1(位置不当,可能下标越界)
return true;
}
//3.插入结点
public static boolean insertList(Node head ,int pos) throws IOException {//参数同上
if(pos<=0||pos>count+1){
return false;
}
//1.先找到前一个结点的地址
int n =0;
Node p = head;
while (n<pos-1){
p = p.getNext();
n++;
}
//2.进行结点插入
String name;
int age;
String number;
//2.1结点填充
Scanner st = new Scanner(System.in);
System.out.println("请输入插入的姓名:");
name = st.nextLine();
System.out.println("请输入插入的年龄:");
age = st.nextInt();
st.nextLine();//接收多余的回车
String tempNumber;
while (true) {
System.out.println("请输入插入的电话号码:");
tempNumber = st.nextLine();
if(isUniqueNumber(head,tempNumber)){//电话号码重复
System.out.println("输入的电话号码重复,请重新输入!");
}else {
break;
}
}
number = tempNumber;
Reporter reporter = new Reporter(name,age,number);
Node node = new Node(reporter,null);
//2.2结点连接
node.setNext(p.getNext());
p.setNext(node);
count++;//结点数量+1
list.add(pos-1,node);//将结点添加到集合中
serializeNode(list);//重新将集合写入到文件中
return true;
}
//4.修改结点
public static boolean alterList(Node head,int pos){
if(pos<=0||pos>count){
return false;
}
//1.先找到被修改结点的地址
int n =0;
Node p = head;
while (n<pos){
p = p.getNext();
n++;
}
Scanner sc = new Scanner(System.in);
System.out.println("请输入修改后的姓名:");
p.getReporter().setName(sc.nextLine());
System.out.println("请输入修改后的年龄:");
p.getReporter().setAge(sc.nextInt());
sc.nextLine();//接收多余的回车
String tempNumber ;//临时接收电话号码
while (true) {
System.out.println("请输入修改后的电话号码:");
tempNumber = sc.nextLine();
if (isUniqueNumber(head, tempNumber)){
System.out.println("电话号码重复,请重新输入");
}else {
break;
}
}
p.getReporter().setNumber(tempNumber);
//修改集合中的元素策略:先删除然后添加
list.remove(pos-1);//先将该位置的结点删除
list.add(pos-1,p);//将集合添加大指定位置
return true;
}
//5.查询结点信息
public static void inqureList(Node head,String str){
//1.对链表的信息进行遍历
boolean flag = false;//标记是否查询成功
System.out.println("-------------------------------------------------------------------------------------");
System.out.println(" 姓名 年龄 电话号码");
for (Node p = head.getNext(); p!=null ; p = p.getNext()) {
if(p.getReporter().getName().contains(str)
||p.getReporter().getNumber().contains(str)){
System.out.printf("%10s%10d%10s\n",p.getReporter().getName(),p.getReporter().getAge(),p.getReporter().getNumber());
System.out.println("-------------------------------------------------------------------------------------");
}
}
}
//6.菜单函数
public static void menuList(){
System.out.println("--------------------------------欢迎使用通讯录管理系统------------------------------------------------");
System.out.println(" 1.创建通讯录");
System.out.println(" 2.修改人员信息");
System.out.println(" 3.删除人员信息");
System.out.println(" 4.查询人员信息");
System.out.println(" 5.显示通讯录");
System.out.println(" 6.插入人员信息");
System.out.println(" 0.退出程序");
}
//7.清屏函数
public static void clean(){
for(int i=0;i<100;i++)
System.out.println(" ");
}
//8.判断电话号码是否唯一
private static boolean isUniqueNumber(Node head,String number){
//遍历链表进行电话号码比对
for(Node p = head.getNext();p != null ;p = p.getNext()){
if(p.getReporter().getNumber().equals(number)){
return true;
}
}
return false;
}
//序列化,将Node对象信息写入到文件中
private static void serializeNode(ArrayList<Node> list) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\project\\node.txt"));
oos.writeObject(list);//将集合存储到文件中
}
//反序列化,将Node对象写出到程序中
public static Node unSerializeNode() throws IOException, ClassNotFoundException {
//定义反序列化流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\project\\node.txt"));
list = (ArrayList<Node>)ois.readObject();
Node node;//创建一个空结点
node = new Node();
Node head = node;//头指针指向空结点
Node q = head;//指向头节点
Node p = null;
for (Node o : list) {//遍历集合
p = o;
q.setNext(p);
q=p;//指针后移
count++;//结点的数量+1
}
return head;
}
}
- 测试类
import java.io.IOException;
import java.util.Scanner;
public class NodeTest {
public static void main(String[] args) throws InterruptedException, IOException, ClassNotFoundException {
Node node;//创建一个空结点
node = new Node();
Node head = node;//头指针指向空结点
head = Nodeutil.unSerializeNode();//进行反序列化操作
Scanner sc = new Scanner(System.in);
while (true){
Nodeutil.menuList();
System.out.println("请输入你的选择:");
int choose = sc.nextInt();
switch (choose){
case (1):
System.out.println("请输入你需要创建的通讯录中的人数:");
int n = sc.nextInt();
Nodeutil.initList(head,n);
System.out.println("创建通讯录成功!");
System.out.println("");
System.out.println("");
System.out.println("通讯录信息如下:");
Nodeutil.showList(head);
Thread.sleep(5000);
Nodeutil.clean();//清屏
break;
case (2):
System.out.println("请输入要修改人员的位置:");
int pos = sc.nextInt();
boolean flag = Nodeutil.alterList(head,pos);
if(flag){
System.out.println("修改成功!");
System.out.println("");
System.out.println("");
System.out.println("修改后的通讯录信息如下:");
Nodeutil.showList(head);
Thread.sleep(5000);//停滞5s
Nodeutil.clean();//清屏
}else {
System.out.println("删除位置输入有误,请重新输入!");
Thread.sleep(5000);//停滞5s
Nodeutil.clean();//清屏
}
break;
case 3:
System.out.println("请输入需要删除人员的位置:");
int p = sc.nextInt();
final boolean flag1 = Nodeutil.removeList(head, p);
if(flag1){
System.out.println("删除成功!");
System.out.println("");
System.out.println("");
System.out.println("删除后的通讯录如下:");
Nodeutil.showList(head);
Thread.sleep(5000);
Nodeutil.clean();
}else {
System.out.println("你输入的需要删除人员的位置有误,请重新输入!");
Thread.sleep(5000);
}
break;
case 4:
System.out.println("请输入需要查询的人员的姓名或者电话号码:");
String str = sc.next();
System.out.println("查询到的信息如下:");
Nodeutil.inqureList(head,str);
Thread.sleep(5000);
Nodeutil.clean();
break;
case 5:
System.out.println("通讯录信息如下:");
Nodeutil.showList(head);
Thread.sleep(5000);
break;
case 6:
System.out.println("请输入要插入的位置:");
int p1 = sc.nextInt();
final boolean flag2 = Nodeutil.insertList(head, p1);
if(flag2){
System.out.println("插入成功!");
System.out.println("");
System.out.println("");
System.out.println("通讯录信息如下:");
Nodeutil.showList(head);
Thread.sleep(5000);
Nodeutil.clean();
}else {
System.out.println("输入的插入的位置有误!");
Thread.sleep(5000);
Nodeutil.clean();
}
break;
case 0:
System.exit(1);
}
}
}
}