我大二上学期的实训项目,当时只要求写控制台程序,写成了Web项目,当时水平一般,用的技术也是比较老的了,可以做个参考。
系统设计
本项目采用B/S架构进行开发,通过分析需求得知,本项目的目的就是为了设计出一款在线餐馆预订系统来为用户提供提前预约功能。通过提供的文档文件来进行数据的读取和修改等操作,数据结构使用了哈希表,链表,邻接矩阵等,算法采用了KMP, Dijkstra等。
系统功能模块划分
本项目的后端内容使用了MVC架构,采用Maven项目进行建立,配置tomcat服务器,使用了JSTL容器和EL表达式来简化JSP文件中Java代码的开发。
数据结构设计
本项目一共提供了4个文档,其中,对ser.txt,shop.txt内容需要建立哈希表提供查找功能,分别为其建立了两个哈希表并提供两个链表进行处理存储。
哈希表采用拉链法处理冲突,定位方法使用取留余数法。
-
对文档建立的链表
首先建立对应的封装类,进行数据封装,然后再建立User的链表,在链表中定义一个头指针。
定义add插入方法:先判断链表是否为空,然后定义一个查找指针,遍历到链表最后插入目标点即可。
定义遍历方法:先判断链表是否为空,接着从头开始遍历即可。
定义查找方法:遍历链表然后匹配即可。
定义删除方法:使用常规的链表结点删除操作即可。 -
对文档建立的哈希表
首先定义一个链表用来处理冲突,在构造器中确定链表长度和初始化链表结点,使用取留余数法进行定位。在以商家名为关键字建立哈希表的过程中,这里在求哈希值的时候遍历了整个商家名,然后每一次调用依次取留余数法,最后再把得到的哈希值再除以一定的数即可实现名称作为关键字的处理。
部分处理冲突和求哈希值的代码:
//根据输入的name查找
public Restaurant findResByName(String name) {
//确定位置
int resLinkList = 0;
for (int i = 0; i < name.length(); i++) {
resLinkList += hashFun(name.charAt(i));
}
System.out.println(resLinkList);
//处理
return restaurant;
}
主要算法设计
本项目中的餐馆推荐功能使用了KMP算法进行实现,而在求餐馆最短路径的时候使用了Dijkstra算法实现。餐馆推荐功能查询到的结果按评分排序使用的快速排序。查询预定功能和注册排序功能使用了重写集合中Sort方法进行实现。
Dijkstra算法的实现
进行n(n为n的个数)次迭代去确定每个点到起点的最小值,最后输出的终点的即为我们要找的最短路的距离。
使用临界矩阵进行存储,开一个dist数组用户来记录1号点(郑州轻工业大学)到每个点的最短距离,再开一个boolean类型数组用来记录每个点的最短路径是否以及确定。具体的求最短路径的算法如下:
public double Dijkstra(int n) {//n表示目标点
dist=new double[850];
state=new boolean[850];
//初始化为无穷
Arrays.fill(dist, 0x7f);
dist[1] = 0;//第一个点到自身的距离为0
//迭代n次
for (int i = 0; i < n; i++) {
int t = -1;//更新位置,表示当前访问到哪个点
//找到还没确定的点中路径最小的点
for (int j = 1; j <= n; j++)//从1号点开始
if (!state[j] && (t == -1||dist[t] > dist[j]))
t = j;
state[t] = true;//标记为true表示已经确定
//依次更新每个点所到相邻的点路径值
for (int j = 1; j <= n; j++)
dist[j] = Math.min(dist[j], dist[t] + graph[t][j]);
}
if (dist[n] == 0x7f) return -1;//如果第n个点路径为无穷大即不存在最低路径
return dist[n];
}
KMP算法实现推荐功能
对next[j],是p[1,j]串中前缀和后缀相同的最大长度(部分匹配值),即 p[1,next[j]]=p[j-next[j]+1,j]。在处理完数据后定义一个新的集合,然后调用KMP算法进行匹配,每次匹配成功后就加入到集合中,最后遍历即可。具体使用KMP算法的代码:
public static boolean KMP(String s, String p) {
int[] next = new int[N];
next[0] = -1;
//求next数组
for (int i = 1, j = -1; i < p.length(); i++) {
while (j > 0 && p.charAt(i) != p.charAt(j + 1)) j = next[j];
if (p.charAt(i) == p.charAt(j + 1)) j++;
next[i] = j;
}
//匹配
for (int i = 0, j = -1; i < s.length(); i++) {
while (j != -1 && s.charAt(i) != p.charAt(j + 1)) j = next[j];
//省略
}
return false;
}
后端设计
通过前端页面文件中form表单等类似的发出请求的标签将数据请求给后端,然后在后端servlet文件中响应,最后将响应得到的数据传到前端,并使用EL表达式和JSTL容器将数据显示出来。
实现servlet的基本步骤:
- 定义service:定义需要的service变量用来调用前面完成的数据结构和算法函数。最好是定义成private类型的。
- 处理乱码:如果是post请求,需要调用request类中setCharacter方法进行字符集的设置。
- 获取数据,调用方法封装对象:调用前面定义的service中的方法和request的getParamater方法来处理前端传来的请求数据,并封装好对象。准备调用方法判断返回结果。
- 跳转页面:调用setAttribute方法来把对象响应数据传给前端,并跳转到对应的JSP页面中。
具体的Servlet类和展示如图所示。
系统展示
用户子系统
用户登录主界面:
用户主页面:
餐馆推荐和查询界面
餐馆主界面:
个人信息管理:
用户预定查询:
商家子系统
餐馆信息管理:
餐馆预定信息管理:
根据用户id查询预定的功能:
总结
这是我大二上学期的数据结构实训项目,当时因为疫情,生着病写的,怎么说呢,也算是对JSP和数据结构的一种结合吧。如果你只是想过个实训,那大可不必弄这么麻烦,如果是想多学点东西,可以看看学习学习。