数据结构B线段树及其应用Word文档格式.docx
《数据结构B线段树及其应用Word文档格式.docx》由会员分享,可在线阅读,更多相关《数据结构B线段树及其应用Word文档格式.docx(54页珍藏版)》请在冰豆网上搜索。
5.1.3张越测试27
5.2组装与系统测试30
5.3系统运行31
6课题总结32
6.1课题评价32
6.2团队协作32
6.3个人设计小结(按组员分工)32
6.3.1余灏然设计小结32
6.3.2魏嘉设计小结32
6.3.3张越设计小结33
7附录A课题任务分工34
A-1课题程序设计分工34
A-2课题报告分工35
附录B课题设计文档(光盘)
B-1课程设计报告(电子版)
B-2源程序代码(*.H,*.CPP)
B-3工程与可执行文件)
B-4屏幕演示录像文件(可选)
附录C用户操作手册(可选)36
C.1运行环境说明36
C.2操作说明36
1课题概述
1.1课题任务
我们选择利用线段树这种结构来建立一个车票购票系统。
【设计要求】
1.2课题原理
线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)!
流程图如下:
1.3相关知识
前序遍历树,将树变成链表,用于存储;
Si与Sj用于测试,可删除;
2需求分析
2.1课题调研
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。
因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。
2.2用户需求分析
利用线段树高效快速的运行车票出售系统。
功能需求
(1)输入功能和显示功能
(2)购买车票、查询车票余额
(3)添加、修改、删除站点信息
(4)读取文件功能和保存文件功能
(5)需要用户友好的界面以便用户方便使用
3方案设计
3.1总体功能设计
线段树
3.2数据结构设计
前序遍历树,将树变成链表,用于存储。
3.3函数原型设计
函数原型
功能描述
voidTreeToList(TreeT,list<
SaveData>
&
p)
voidListToTree(Tree&
T,list<
:
iterator&
iterP)
链表还原成树
intLoading(Tree&
T)
读取数据将数据还原成树
voidprint(list<
staname>
显示乘车顺序
TreeFind(inta,TreeT)
寻找叶子
voidBuyTicket(inta,intb,intn,Tree&
T)
购票
voidCheck()
检查数据文件
voidwelcome()
初始界面显示
voidInquire(TreeT,list<
查询车票数量
voidintitle(list<
p)
站号对应站名的处理
3.4主算法设计
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
3.5用户界面设计
Dos界面
输入后:
4方案实现
4.1开发环境与工具
主要编程环境:
MicrosoftVisualStudioC++6.0
编程工具:
C++。
4.2程序设计关键技术
线段树及其应用:
(1)C#语言的学习和MicrosoftVisualStudio2008的使用方法,因为未学习过此语言,学会使用C#和开发工具是程序设计的关键。
(2)线段树的实现问题,线段树的实现还是相对复杂的,我们从网上,书籍查阅了许多资料,进行了多次debug才完成此部分。
(3)多人程序的融合性问题,由于没怎么接触过多人写程序,每个人写的程序必须能够很好组合。
4.3.1余灏然设计实现
Main函数
#include"
head.h"
save.cpp"
StationName.cpp"
buy.cpp"
check.cpp"
inquire.cpp"
frame.cpp"
voidmain()
{
list<
p;
TreeT;
inti,j,a,b,n,t=0;
//t值用于判断第一次"
重新生成线段树"
时是否执行DelData(T),t=0不执行t=1执行
Check();
//检查数据文件是否丢失
t=Loading(T);
//读取线段树数据
Loading2(p);
//读取站名链表数据
welcome();
while
(1)
{
system("
cls"
);
frame();
gotoxy(25,8);
cout<
<
"
1.购票与查询"
;
gotoxy(25,9);
2.管理功能"
gotoxy(25,10);
3.退出"
gotoxy(25,12);
----请选择功能:
cin>
>
i;
if(i==1)
{
while
(1)
{
print(p);
cout<
endl<
1.购票车票2.查询车余额3.返回---请选择:
cin>
j;
if(j==1)
{
cout<
请分别输入出发站、到达站号及购买票数:
cin>
a>
b>
n;
if(a<
b)BuyTicket(a,b,n,T);
if(a>
b)BuyTicket2(a,b,n,T);
}
if(j==2)Inquire(T,p);
if(j==3)break;
}
}
if(i==2)
system("
请选择(1.重新生成线段树2.改变站名对应站号3.删除树并初始化4.返回):
"
{
请输入线段区间(a,b)[必须符合0<
a<
b]:
b;
if(t)DelData(T);
CreateTree(T,a,b);
SaveTree(T);
t=1;
}
if(j==2)intitle(p);
if(j==3)DelData(T);
if(j==4)break;
if(i==3)exit(0);
}//while尾
}
save.cpp
p)//前序遍历树,将树变成链表,用于存储,
SaveDataa;
if(T!
=NULL)
a.k=1;
a.Si=T->
a.Sj=T->
a.Snum=T->
num;
a.Snum2=T->
num2;
p.push_back(a);
TreeToList(T->
lchild,p);
rchild,p);
}
else
a.k=0;
//a.Si=-1;
a.Sj=-1;
//Si与Sj用于测试,可删除
voidSaveTree(TreeT)
FILE*fp;
SaveDatah;
iteratoriterP=p.begin();
TreeToList(T,p);
iterP=p.begin();
fp=fopen("
TicketData.dat"
"
wb"
h.k=iterP->
k;
h.Si=iterP->
Si;
h.Sj=iterP->
Sj;
h.Snum=iterP->
Snum;
h.Snum2=iterP->
Snum2;
fwrite(&
h,sizeof(SaveData),1,fp);
iterP++;
if(iterP==p.end())break;
SaveDatat;
t.k=-1;
//t->
k=-1表链表尾
fwrite(&
t,sizeof(SaveData),1,fp);
fclose(fp);
//cout<
存储成功!
endl;
iterP)//链表还原成树
if(iterP->
k==0){T=NULL;
iterP++;
{
if(!
(T=(Btree*)malloc(sizeof(Btree))))exit(-1);
T->
i=iterP->
T->
j=iterP->
T->
num=iterP->
num2=iterP->
ListToTree(T->
lchild,iterP);
rchild,iterP);
T)//读取数据将数据还原成树
iteratoriterP;
rb"
fread(&
if(h.k==-1)
{cout<
--------无数据内容。
return0;
while(h.k!
=-1)//判断是不是链表尾
p.push_back(h);
fread(&
ListToTree(T,iterP);
数据读取成功,已生成树。
return1;
intDelData(TreeT)
DestroyTree(T);
wb+"
//不写入内容,即可清除数据
inquire.cpp
TreeFind(inta,TreeT);
p)//查询车票数量
inti=0;
Treet;
cout<
当前相邻两站间的车票余额:
t=Find(iterP->
k,T);
cout<
iterP->
k<
号站-"
name<
===>
name<
(max-t->
num)<
elseiterP--;
iterP--;
iterP--;
num2)<
elseiterP++;
4.3.2魏嘉设计实现
head.h
#ifndef_HEAD_H
#define_HEAD_H//运用#ifndef避免重复定义
iostream"
stdio.h"
windows.h"
conio.h"
#include<
list>
usingnamespacestd;
#definemax100//每站票数的最大上限
typedefstructNode{
inti,j;
//分别表示线段树左右节点
intnum;
//存储数据,表示当前已出售票数
intnum2;
//返程
structNode*lchild,*rchild;
}Btree,*Tree;
typedefstructstation{
intk;
//站点所对应的数字
charname[20];
}staname;
typedefstructsave{
//k=1时储存节点信息,k=0时代表空格不存储其他信息,k=-1时表示链表尾(NULL不知为何不好使=A=)
intSi,Sj;
intSnum;
intSnum2;
}SaveData;
intCreateTree(Tree&
T,inta,intb)
if(b<
a||a<
1||b<
1)//b大于a或a,b不大于零时,则提示输入错误
error!
returnNULL;
T=(Btree*)malloc(sizeof(Btree));
i=a;
j=b;
num=-1;
num2=-1;
//只有树的叶子节点才用于存储数据,其他非叶子节点令其值为-1
if(b-a>
1)
CreateTree(T->
lchild,a,(a+b)/2);
rchild,(a+b)/2,b);
lchild=NULL;
rchild=NULL;
num=0;
//初始化为0
num2=0;
voidDestroyTree(Tree&
T)//删除时用这个,判断树是否已为空,若不空则执行Destroy(TreeT);
intDestroy(TreeT);
if(T->
num==-1){Destroy(T);
线段树已销毁。
}//如果树不为空,则T->
num=-1
elsecout<
树已为空,无需销毁。
intDestroy(TreeT)//完全销毁线段树
if(T==NULL)return1;
Destroy(T->
lchild);
rchild);
free(T);
voidPreOrder(TreeT)//前序遍历树
i<
j<
PreOrder(T->
!
voidgotoxy(intx,inty)//光标移动x为列坐标,y为行坐标
COORDpos={x,y};
HANDLEhOut=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOut,pos);
#endif
StationName.cpp
string.h"
p)//站号对应站名的处理
voidLoading2(list<
p);
voidfirstuse();
charb[20];
stanameh;
iterP=p.begin();
fp=fopen("
StationName.dat"
h,sizeof(staname),1,fp);
while(h.k!
=0)
cout<
号站----"
iterP++;
if(iterP==p.end())break;
fclose(fp);
1.添加或更改站点(请从1开始按顺序添加)2.重置清空3.返回"
请选择:
请分别输入站号及站名(站号误重复)"
cin>
h.k>
h.name;
p.push_back(h);
iterP=p.begin();
fp=fopen("
h.k=iterP->
strcpy(h.name,iterP->
name);
fwrite(&
iterP++;
if(iterP==p.end())break;
h.k=0;
fwrite(&
fclose(fp);
if(i==2){firstuse();
p.clear();
if(i==3)break;
voidfirstuse()//站名数据文件初始化
stanamep;
p.k=0;
p,sizeof(staname),1,fp);
voidLoading2(list<
p)//读取站名链表数据
buy.cpp
p)//显示乘车顺序
inti=1;
乘车区间:
while(i)
号站:
name;
if(i==5){cout<
i=1;
if(!
(iterP==p.end()