课程设计实践报告.docx
《课程设计实践报告.docx》由会员分享,可在线阅读,更多相关《课程设计实践报告.docx(39页珍藏版)》请在冰豆网上搜索。
![课程设计实践报告.docx](https://file1.bdocx.com/fileroot1/2023-1/30/cb5dd2f2-ef1d-4273-b4b4-dfa5348b1982/cb5dd2f2-ef1d-4273-b4b4-dfa5348b19821.gif)
课程设计实践报告
北京工商大学
课程设计实践报告
学院:
计算机与信息工程学院
课程名称:
算法与数据结构
任课教师:
叶红
班级:
工科092
学号:
姓名:
同组学生:
无
实践地点:
北京工商大学良乡校区工二楼406
实践时间:
2011年1月3日至2011年1月7日
1、课程设计题目内容:
对一批汽车牌照进行排序和查找
排序和查找是在数据信息处理中使用频度极高的操作。
为加快查找的速度需先对数据记录按关键字排序,在汽车数据的信息模型中,汽车牌照是关键字,而且是具有结构特点的一类关键字。
因为汽车牌照号是数字和字母混编的,例如01B7328,这种记录集合是一个适于利用多关键字进行排序的典型例子,故我们可以利用链式基数排序方法实现排序。
在排序基础上,利用二分查找的思想,实现对这批汽车记录按关键字的查找。
2、设计要求
基本要求:
利用链式基数排序和二分查找的思想完成程序设计任务。
3、设计内容
(1)需求分析
程序的功能:
主要功能是对含有关键字的批量数据进行排序和查找;另外根据实际增添了输出到文件、删除、插入、简单统计功能。
输入输出的要求:
程序会显示提示,根据提示输入数字、字符或数据。
测试数据:
测试数据的每个记录包括五项,分别为牌照号码、汽车商标、颜色、注册日期和车主的姓名,其中牌照号码为七位(k0-k6),输入形式如下:
K0和k1输入值为01-04(代表地区),k2输入值为A~Z(代表车的使用类型),后4位为0000~9999(代表车号),例如:
O1B7328。
其余四项输入内容因为不涉及本程序的核心思想,故只要求一般字符串类型即可。
查询时,输入合法的汽车牌照号码。
测试数据要求用30个左右的数据项进行测试,头两位暂限定01~04,第3位为A~Z,以便可使牌照号码相对集中。
程序测试数据:
30
01S5842将明2007-12-02bluejid
04D2154陈琳2005-11-01yellowjo
02A0021潘晓静2011-04-22whitejae
01S8930李峰2010-08-13greenaie
03C3589张三2007-02-18bluenhi
04E2184Lucy2009-11-28blackas6
04A2505赵晗2009-10-30brownja
03C3269Lily2007-11-30pinkjos
03B3568Tom2005-12-17bluejos
01A8983Jim2006-02-19whitekfe
02A7777韩梦龙2005-02-07blackvds
02C2222钱国正2009-08-05greenyer
01G8652刘晓莉2008-11-07whitekfe
03H0029Kasserine2008-04-08blackxfd
04G9665索海丰2009-04-09redtrs
03B3222唐如云2007-10-08brownhtr
02L6622王睫2007-11-08bluenrr
04L1122Shelly2006-11-03blackgf
04A2200David2009-02-22redert
01E8000赵远2007-03-08pinktre
02V0009唐文2006-07-02bluethh
01B3321郑华2008-12-02whitejh
03S6699索耀光2008-01-01whiterd
03D4115赵沙2007-11-11yellowkew
01F6339赵欢欢2007-07-14redkfe
02H7775叶丽娜2009-08-15brownwg
02A8993孙珍珍2010-11-27whitewb
02P8692赵楠2006-10-12blacktrt
04W5524孙中华2004-03-21yellowms
03W6688John2007-01-11pinkesg
(2)概要设计
本程序所用的抽象数据类型的定义:
ArrType//指针数组类型
SLList//静态链表类型
SLCell//静态链表的结点类型
KeysType//定义关键字类型为字符型
InfoType//定义其它数据项的类型
主程序的流程及各程序模块之间的层次关系:
开始先选择读入原始数据方式:
1:
从文件读入(在桌面建立test.txt文档,第一行为记录数,记录数<=10000,记录数必须符实,否则程序出错;第二行开始数据,数据用空格隔开,例如:
01S5842将明2007-12-02bluejid);
2:
直接用程序内数据。
然后对数据进行操作:
1:
按车牌号排序并输出;
是否输出到文件?
(y/n)
2:
查找;
1):
按车牌号查找(排序后进行);
0:
退出1:
删除
2):
按车牌号前两位查找;
3):
按车牌号第三位查找。
3:
按顺序插入数据;(排序后)
4:
简单统计。
1):
按车牌号前两位统计;
2):
按车牌号第三位统计。
(3)详细设计
采用C语言定义相关的数据类型:
typedefstructInfoType//车主姓名等其它信息
{
charname[17];
chardate[12];
charcolor[11];
charmark[10];
}InfoType;//定义其它数据项的类型
typedefcharKeysType;//定义关键字类型为字符型
typedefstructSLCell//静态链表的结点类型
{
KeysTypekeys[MAX_NUM_OF_KEY+1];//关键字(字符串末尾+'\0')
InfoTypeoth;//其它数据项
intnext;
}SLCell;
typedefstructSLList//静态链表类型
{
SLCellr[MAX_SPACE];/*静态链表的可利用空间,r[0]为头结点*/
intkeynum;//记录的当前关键字个数
intrecnum;//静态链表的当前长度
}SLList;
typedefintArrType[RADIX];//指针数组类型
各模块的算法:
①基数排序:
voidDistribute(SLCellr[],inti,ArrTypef,ArrTypee);
/*静态键表L的r域中记录已按(keys[0],…,keys[i-1])有序。
本算法按第i个关键字keys[i]建立RADIX个子表,使同一子表中记录的keys[i]相同。
f[0..RADIX-1]和e[0..RADIX-1]分别指向各子表中第一个和最后一个记录*/
voidCollect(SLCellr[],ArrTypef,ArrTypee);
/*本算法按keys[i]自小至大地将f[0..RADIX-1]所指各子表依次链接成一个链表,e[0..RADIX-1]为各子表的尾指针。
*/
voidSort(SLListL,intadr[]);
/*求得adr[1..L.length],adr[i]为静态链表L的第i个最小记录的序号*/
voidRearrange(SLList&L,intadr[]);
/*adr给出静态链表L的有序次序,即L.r[adr[i]]是第i小的记录。
本算法按adr重排L.r,使其有序。
*/
voidRadixSort(SLList&L);
/*L是采用静态链表表示的顺序表。
对L作基数排序,使得L成为按关键字自小到大的有序静态链表,L.r[0]为头结点。
*/
voidwrite(SLListl);//输出到文件
②查找:
intjudge(chars[]);//判断车牌号是否合法
intSearch1(SLListST);/*在表ST中折半查找其关键字等于key的数据元素。
若找到,则打印该元素在表中的信息*/
voidDelete(SLList*l,intd);//删除l中第d个记录
voidSearch2(SLListl);//据车牌号前两位搜索
voidSearch3(SLListl);//据车牌号第三位搜索
③插入:
intRead(SLListl,SLCell*r);/*读取车牌号到r,若l中有此车牌号则读取失败*/
voidInsert(SLList*l);/*在l中按基数排序顺序插入车牌号及其他信息*/
④统计:
voidStatistic1(SLListl);//据车牌号前两位进行统计
voidStatistic2(SLListl);//据车牌号第三位进行统计
函数的调用关系图:
(4)调试分析
调试中遇到的问题及对问题的解决方法:
我在调试中遇到了许多问题,由于问题太多无法一一说明,这里只说一些编译无错误而程序无法正常运行,或者程序的执行结果与预想的不同,其它的大部分错误软件在编译时会有提示,就不说了。
1、出现如图1情况的,我碰到的有几种。
图1
1)scanf或fscanf语句中一定要用变量的地址,而不是变量本身。
这种错误在学习C语言时就强调过,但编程时还是得小心,我的程序在编了300多行时出现这个错误,费了好些时间才查找出来;
2)数组或其它变量定义空间不足。
例如在基数排序中,需要两个指针数组,大小与基数相同,如果小于基数的话,会出现图1所示的情况。
2、程序执行结果与预想结果不同,如图2和图3所示
图2
这里有一个经常不经意犯的小错误,就是经常把“==”写成“=”,上图中while(a==0);以下还有一例:
图4和图5中,if(c==’y’)。
图3
图4
图5
3、有三个问题我不知如何解决:
①图4和图5中,运行结果是打印完“是否输出到文件?
(y/n)”后直接回车打印“输入错误”,之间并没有让输入字符进行选择;②图5中程序中使用的是scanf函数而不是getch()函数,因为编译时会提示没有getch()此函数,应该如何做才能把它找出来?
③如图6、图7和图8所示,当进行选择时,若输入字母,则会进入死循环,而输入其它数字时则不会,我试了一下,当输入如!
@#等特殊字符时也会进入死循环,我暂时没能解决掉这个问题。
图6
图7
图8
暂时就这些问题了。
(5)使用说明及测试结果
程序开始后,先选择读入原始数据方式;
选择后,程序会先将数据按原来顺序打印出来;
然后程序显示主菜单,对数据进行操作;
1:
按车牌号排序并输出;
程序会先对原始数据以车牌号为关键字进行基数排序并输出;
输出后程序会提示是否输出到文件,进行选择;
若选择“y”,程序会将排好序的数据记录在桌面建立txt文档保存;若选择“n”,程序会继续回到主菜单。
2:
查找;
1):
按车牌号查找(排序后进行);
程序会要求输入要查找的车牌号,读入后对其合法性进行检验,若不合法(格式不正确),会要求重新输入;若合法,则查找。
查找到后,程序会打印出车牌号的位置及其相关信息,然后进行选择是否删除;若未查找到,则打印“未找到与此车牌号相关的信息”;
2):
按车牌号前两位查找;
程序读入前两位后,会依次将满足条件的车牌号及其它相关信息打印出来,并在最后统计有多少个记录满足条件;
3):
按车牌号第三位查找;
同前一个查找类似,程序找到满足条件的车牌号后会依次打印出车牌号及其相关信息,并在最后总和共有多少记录满足条件。
先说,4:
简单统计。
1):
按车牌号前两位统计;
程序会对已存在的记录以前两位进行统计,分别打印出各个种类有多少个;
2):
按车牌号第三位统计
程序会对已存在的记录以车牌号第三位进行统计,分别打印出各个种类有多少个。
3:
按顺序插入数据;(排序后)
程序会先要求输入要插入数据的车牌号,进行判断是否合法,不合法包括格式不正确和原始数据中已存在,程序会给出相应的提示,要求不合法的重新输入,然后要求输入车主姓名及其它相关信息,进行插入操作,成功后程序会提示插入成功并将所在位置打印出来;
最后可以选择主菜单中的排序进行查看插入的数据及其所在位置。
完成操作后,想退出程序的可以通过主菜单中的“0:
退出”实现,其它菜单中一样可以通过此功能退出当前菜单。
(6)源程序(带注释)
这是我从cpp文件中直接复制粘贴过来的:
#include
#include
#include
#include
#include
#defineN30
#defineRADIX26/*关键字基数,此时是二十六个字母(包括十进制整数)的基数*/
#defineMAX_SPACE10000//链表最大空间
#defineMAX_NUM_OF_KEY7//关键字位数
typedefstructInfoType//车主姓名等其它信息
{
charname[17];
chardate[12];
charcolor[11];
charmark[10];
}InfoType;//定义其它数据项的类型
typedefcharKeysType;//定义关键字类型为字符型
typedefstructSLCell//静态链表的结点类型
{
KeysTypekeys[MAX_NUM_OF_KEY+1];//关键字(字符串末尾+'\0')
InfoTypeoth;//其它数据项
intnext;
}SLCell;
typedefstructSLList//静态链表类型
{
SLCellr[MAX_SPACE];/*静态链表的可利用空间,r[0]为头结点*/
intkeynum;//记录的当前关键字个数
intrecnum;//静态链表的当前长度
}SLList;
typedefintArrType[RADIX];//指针数组类型
intmenu0();//选择读入原始数据方式
intmenu();//总菜单
intmenu1();//查找菜单
intmenu11();//删除菜单
intmenu2();//统计菜单
intduru(SLList*l,intr);//执行读入原始数据
voidprint(SLListL,intw);//按数组序号输出静态链表
voidwrite(SLListl);//输出到文件
voidDistribute(SLCellr[],inti,ArrTypef,ArrTypee);
/*静态键表L的r域中记录已按(keys[0],…,keys[i-1])有序。
本算法按第i个关键字keys[i]
建立RADIX个子表,使同一子表中记录的keys[i]相同。
f[0..RADIX-1]和e[0..RADIX-1]分别指
向各子表中第一个和最后一个记录*/
voidCollect(SLCellr[],ArrTypef,ArrTypee);
/*本算法按keys[i]自小至大地将f[0..RADIX-1]所指各子表依次链接成一个链表,e[0..RADIX-1]为各子表的尾指针。
*/
voidSort(SLListL,intadr[]);
/*求得adr[1..L.length],adr[i]为静态链表L的第i个最小记录的序号*/
voidRearrange(SLList&L,intadr[]);
/*adr给出静态链表L的有序次序,即L.r[adr[i]]是第i小的记录。
本算法按adr重排L.r,使其有序。
*/
voidRadixSort(SLList&L);
/*L是采用静态链表表示的顺序表。
对L作基数排序,使得L成为按关键字自小到大的有序静态链表,L.r[0]为头结点。
*/
intjudge(chars[]);//判断车牌号是否合法
intSearch1(SLListST);/*在表ST中折半查找其关键字等于key的数据元素。
若找到,则打印该元素在表中的信息*/
voidSearch2(SLListl);//据车牌号前两位搜索
voidSearch3(SLListl);//据车牌号第三位搜索
voidStatistic1(SLListl);//据车牌号前两位进行统计
voidStatistic2(SLListl);//据车牌号第三位进行统计
voidDelete(SLList*l,intd);//删除l中第d个记录
intRead(SLListl,SLCell*r);/*读取车牌号到r,若l中有此车牌号则读取失败*/
voidInsert(SLList*l);/*在l中按基数排序顺序插入车牌号及其他信息*/
intmain()
{
SLListl;
inta,o,x,y,z;
l.recnum=N;
l.keynum=MAX_NUM_OF_KEY;
do
{
a=menu0();
a=duru(&l,a);
}while(a==0);
printf("车牌号排序前:
\n");
print(l,0);
do
{
x=menu();
switch(x)
{
case1:
RadixSort(l);
printf("车牌号排序后:
\n");
print(l,0);
write(l);
break;
case2:
do
{
y=menu1();
switch(y)
{
case1:
o=Search1(l);
if(o)
Delete(&l,o);
break;
case2:
Search2(l);break;
case3:
Search3(l);break;
case0:
break;
}
}while(y!
=0);
break;
case3:
if(l.recnum{
Insert(&l);
break;
}
else
printf("空间已满,无法插入!
\n");
break;
case4:
do
{
z=menu2();
switch(z)
{
case1:
Statistic1(l);break;
case2:
Statistic2(l);break;
case0:
break;
}
}while(z!
=0);
break;
case0:
printf("\n\t\t\tByebye!
\n\n\n");
break;
}
}while(x!
=0);
system("pause");
return0;
}
intmenu0()
{
intx;
printf("-----------------------------------------------------------\n");
printf("|1:
从文件读入(在桌面建立test.txt文档,第一行为记录数,|\n");
printf("|记录数<=10000,记录数必须符实,否则程序出错;第二行|\n");
printf("|开始数据,数据用空格隔开,例如:
|\n");
printf("|01S5842将明2007-12-02bluejid);|\n");
printf("|2:
直接用程序内数据。
|\n");
printf("-----------------------------------------------------------\n");
printf("pleaseselect(1-2):
");
scanf("%d",&x);
while(x<1||x>2)
{
printf("输入错误!
\n");
printf("Pleaseenterthenumber(1--2):
");
scanf("%d",&x);
};
returnx;
}
intmenu()
{
intx;
printf("-----------------------------\n");
printf("|0:
退出!
|\n");
printf("|1:
按车牌号排序并输出;|\n");
printf("|2:
查找;|\n");
printf("|3:
按顺序插入数据;(排序后)|\n");
printf("|4:
简单统计。
|\n");
printf("-----------------------------\n");
printf("pleaseselect(0-4):
");
scanf("%d",&x);//怎样能避免输入两个数字和字母的情况?
while(x<0||x>4)
{
printf("输入错误!
\n");
printf("Pleaseenterthenumber(0--4):
");
scanf("%d",&x);
};
returnx;
}
intmenu1()
{
intx;
printf("------------------------------\n");
printf("|0:
退出!
|\n");
printf("|1:
按车牌号查找(排序后进行);|\n");
printf("|2:
按车牌号前两位查找;|\n");
printf("|3:
按车牌号第三位查找。
|\n");
printf("------------------------------\n");
printf("pleaseselect(0-3):
");
scanf("%d",&x);
while(x<0||x>3)
{
printf("输入错误!
\n");
printf("Pleaseenterthenumber(0--3):
");
scanf("%d",&x);
};
returnx;
}
intmenu11()
{
intx;
printf("------------------------------------\n");
printf("|0:
退出