-
课程设计目的
- 熟练掌握线性表、栈、队列、串、数组、树和图等基本数据结构的逻辑特性和存储表示方法;熟练掌握各种基本数据结构的基本算法和其应用;熟练掌握问题分析、数据结构设计、程序设计的基本技能和技术。
- 能够综合运用数据结构与算法和相关的数学等理论知识对复杂工程中的算法问题进行抽象、分析和建模;能够依据工程实际问题的需求合理组织数据、并在计算机中有效地存储数据;能够针对复杂工程中的算法问题,设计出比较合理的解决方案,利用具体的编程语言实现解决方案,并具有一定的创新思维能力。
- 具有良好的工程素养和职业素养,诚信守法,能够坚持职业操守和道德规范;具有精益求精的工匠精神、创新精神和探索未知终身学习的意识;具有科技报国的社会责任感、使命感和爱国主义情操。
-
问题描述
本次课程设计要求协助中国大学生计算机设计大赛江苏省组委会,设计一款赛事管理系统,实现赛务相关的数据管理及信息服务,该系统能够为省级赛事管理解决以下问题:
1.能够管理各参赛队的基本信息
包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项,包括增加、删除、修改参赛队伍的信息。
public class Team {
private int teamId; // 参赛队编号
private String teamName; // 参赛作品名称
private String school; // 参赛学校
private String eventType; // 赛事类别
private String participant; // 参赛者
private String teacher; // 指导老师
public Team(int teamId, String teamName, String school, String eventType, String participant, String teacher) {
this.teamId = teamId;
this.teamName = teamName;
this.school = school;
this.eventType = eventType;
this.participant = participant;
this.teacher = teacher;
}
public int getTeamId() {
return teamId;
}
public String getTeamName() {
return teamName;
}
public String getSchool() {
return school;
}
public String getEventType() {
return eventType;
}
public String getParticipant() {
return participant;
}
public String getTeacher() {
return teacher;
}
@Override
public String toString() {
return "参赛队伍信息:" +
"参赛队编号:" + teamId +
", 参赛作品名称:" + teamName +
", 参赛学校:" + school +
", 赛事类别:" + eventType +
", 参赛者:" + participant +
", 指导老师:" + teacher;
}
}
基本信息,实现基于二叉排序树的查找。
根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
// 从team.txt中读取参赛队伍信息
public void readTeamFile(String filename) {
File file = new File(filename);
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = null;
while ((line = reader.readLine()) != null) { // 读取文件内容
String[] data = line.split("#"); // 按符号“#”切分数据
int teamId = Integer.parseInt(data[0]);
String teamName = data[1];
String school = data[2];
String eventType = data[3];
String participant = data[4];
String teacher = data[5];
Team team = new Team(teamId, teamName, school, eventType, participant, teacher);
addTeam(team);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 基于二叉排序树的查找
public void search() {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要查找的参赛队编号:");
int teamId = scanner.nextInt();
BinarySortTree.BSTNode temp = binarySortTree.search(teamId);
if (temp != null) { // 查找成功
Team team = (Team) temp.getData();
System.out.println(team);
System.out.println("平均查找长度ASL:" + binarySortTree.getASL());
} else { // 查找失败
System.out.println("查找失败!");
}
}
//二叉树类
public class BinarySortTree {
private BSTNode root;
private int size;
private int sum; //二叉排序树中所有结点的深度之和
public BinarySortTree() {
root = null;
size = 0;
sum = 0;
}
public BSTNode getRoot() {
return root;
}
public int getSize() {
return size;
}
public int getASL() {
return sum / size;
}
// 插入操作
public void insert(int key, Object data) {
insert(root, key, data);
}
private void insert(BSTNode node, int key, Object data) {
if (root == null) {
root = new BSTNode(key, data);
size++;
return;
}
if (node == null) {
node = new BSTNode(key, data);
size++;
return;
}
if (key < node.key) {
if (node.leftChild == null) {
node.leftChild = new BSTNode(key, data);
size++;
return;
}
insert(node.leftChild, key, data);
} else if (key > node.key) {
if (node.rightChild == null) {
node.rightChild = new BSTNode(key, data);
size++;
return;
}
insert(node.rightChild, key, data);
} else {
node.data = data;
}
}
// 删除操作
public boolean delete(int key) {
BSTNode parent = root; // 记录要删除结点的父结点
BSTNode current = root; // 记录要删除结点
boolean isLeftChild = true;
while (current.key != key) {
parent = current;
if (key < current.key) {
isLeftChild = true;
current = current.leftChild;
} else {
isLeftChild = false;
current = current.rightChild;
}
if (current == null) {
return false;
}
}
// 情况1:要删除的结点没有子结点
if (current.leftChild == null && current.rightChild == null) {
if (current == root) {
root = null;
} else if (isLeftChild) {
parent.leftChild = null;
} else {
parent.rightChild = null;
}
}
// 情况2:要删除的结点只有一个子结点
else if (current.rightChild == null) {
if (current == root) {
root = current.leftChild;
} else if (isLeftChild) {
parent.leftChild = current.leftChild;
} else {
parent.rightChild = current.leftChild;
}
} else if (current.leftChild == null) {
if (current == root) {
root = current.rightChild;
} else if (isLeftChild) {
parent.leftChild = current.rightChild;
} else {
parent.rightChild = current.rightChild;
}
}
// 情况3:要删除的结点有两个子结点
else {
BSTNode successor = getSuccessor(current);
if (current == root) {
root = successor;
} else if (isLeftChild) {
parent.leftChild = successor;
} else {
parent.rightChild = successor;
}
successor.leftChild = current.leftChild;
}
size--;
return true;
}
// 获取后继结点
private BSTNode getSuccessor(BSTNode delNode) {
BSTNode successorParent = delNode;
BSTNode successor = delNode;
BSTNode current = delNode.rightChild;
while (current != null) {
successorParent = successor;
successor = current;
current = current.leftChild;
}
if (successor != delNode.rightChild) {
successorParent.leftChild = successor.rightChild;
successor.rightChild = delNode.rightChild;
}
return successor;
}
// 修改操作
public void update(int key, Object newData) {
BSTNode node = search(key);
if (node != null) {
node.data = newData;
}
}
// 查找操作
public BSTNode search(int key) {
BSTNode current = root;
while (current != null && current.key != key) {
if (key < current.key) {
current = current.leftChild;
} else {
current = current.rightChild;
}
}
return current;
}
// 中序遍历操作
public void inorderTraversal(BSTNode node, Queue queue, int eventType) {
if (node != null) {
inorderTraversal(node.leftChild, queue, eventType);
Team team = (Team) node.data;
if (team.getEventType().equals(String.valueOf(eventType))) { // 赛事类别匹配
queue.enqueue(team);
}
sum += getNodeDepth(node);
inorderTraversal(node.rightChild, queue, eventType);
}
}
// 计算结点深度
private int getNodeDepth(BSTNode node) {
if (node == null || node == root) {
return 0;
}
int depth = 1;
BSTNode parent = node.parent;
while (parent != null) {
depth++;
parent = parent.parent;
}
return depth;
}
// 二叉排序树结点类
public class BSTNode {
private int key;
private Object data;
private BSTNode parent;
private BSTNode leftChild;
private BSTNode rightChild;
public BSTNode(int key, Object data) {
this.key = key;
this.data = data;
parent = leftChild = rightChild = null;
}
public int getKey() {
return key;
}
public Object getData() {
return data;
}
public BSTNode getParent() {
return parent;
}
public BSTNode getLeftChild() {
return leftChild;
}
public BSTNode getRightChild() {
return rightChild;
}
}
}
(3)赛事系统为参赛者提供赛地的校园导游程序,为参赛者提供各种路径导航的查询服务。
以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。
- 需求分析
设计一个校园导游程序,为来访的客人提供各种信息查询服务。根据学校平面图设计一个校园导游咨询系统,系统中存有景点。可实现功能:
(1)设计你的学校的校园平面图,所含景点不少于10个。以图中顶点表示校内各景点,存放景点名称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。
(2)为来访客人提供图中任意景点相关信息的查询。
(3)为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。
(4)提供图中任意景点问路查询,即求任意两个景点之间的所有路径。
(5)校园导游图的景点和道路的修改扩充功能。
数据的条件限定:采用无向图-邻接数组的存储结构,点的类型是自定义结构体spot类型,其中含int和字符串类型,邻接数组类型为int**类型。
操作的限定:根据选择提示进行选择,限定输入所规定范围内的int类型作选择操作,有时要输入字符串如修改景点的信息。
输出的限定:输出的是字符串或十进制数。
实现思路:
(1)利用对象流实现读取和存储平面图的邻接矩阵以及景点信息,实现查询不同区域的景点信息
(2)根据用户提供数据生成当前平面图的邻接矩阵
(3)通过Dijkstra算法实现查询两景点的最短路径功能
- 概要设计
1.Dijkstra算法
用于查询最短路径,其主要思想如下:
每次从未标记的结点中找到离起始结点最短的结点并将其收入最短路径集合。
计算新加入结点A的临近结点B(未被标记)的距离,即代码中的minDist + map[temp][i]。
若计算得到的距离小于原来从起始结点到结点B的距离,则更新B结点的dist和path。
用c++代码实现如下:
#include<iostream>
#include<vector>
using namespace std;
void dijkstra(const int& beg,//出发点
const vector<vector<int> >& adjmap,//邻接矩阵,通过传引用避免拷贝
vector<int>& dist,//出发点到各点的最短路径长度
vector<int>& path)//路径上到达该点的前一个点
//负边被认作不联通
{
const int& NODE = adjmap.size();//用邻接矩阵的大小传递顶点个数,减少参数传递
dist.assign(NODE, -1);//初始化距离为未知
path.assign(NODE, -1);//初始化路径为未知
vector<bool> flag(NODE, 0);//标志数组,判断是否处理过
dist[beg] = 0;//出发点到自身路径长度为0
while (1)
{
int v = -1;//初始化为未知
for (int i = 0; i != NODE; ++i)
if (!flag[i] && dist[i] >= 0)//寻找未被处理过且
if (v < 0 || dist[i] < dist[v])//距离最小的点
v = i;
if (v < 0)return;//所有联通的点都被处理过
flag[v] = 1;//标记
for (int i = 0; i != NODE; ++i)
if (adjmap[v][i] >= 0)//有联通路径且
if (dist[i] < 0 || dist[v] + adjmap[v][i] < dist[i])//不满足三角不等式
{
dist[i] = dist[v] + adjmap[v][i];//更新
path[i] = v;//记录路径
}
}
}
int main()
{
int n_num, e_num, beg;//含义见下
cout << "输入点数、边数、出发点:";
cin >> n_num >> e_num >> beg;
vector<vector<int> > adjmap(n_num, vector<int>(n_num, -1));//默认初始化邻接矩阵
for (int i = 0, p, q; i != e_num; ++i)
{
cout << "输入第" << i + 1 << "条边的起点、终点、长度(负值代表不联通):";
cin >> p >> q;
cin >> adjmap[p][q];
}
vector<int> dist, path;//用于接收最短路径长度及路径各点
dijkstra(beg, adjmap, dist, path);
for (int i = 0; i != n_num; ++i)
{
cout << beg << "到" << i << "的最短距离为" << dist[i] << ",反向打印路径:";
for (int w = i; path[w] >= 0; w = path[w])
cout << w << "<-";
cout << beg << ' \n';
}
}
下面给出校园景点的无向带权图:
设计要求
1)赛事数据要求存入文件(txt或excel)并能读入查询;
2)赛地目的地查询,需提供目的地(建筑物)名称、代号、简介、两地之间路径长度等信息;
3)输入数据形式和范围:赛事相关数据可从键盘输入,或自文件导入。
4)界面要求:交互设计要合理,每个功能可以设计菜单,用户根据提示,完成相关功能的要求