数据结构课程设计插队买票.docx

上传人:b****6 文档编号:7730200 上传时间:2023-01-26 格式:DOCX 页数:16 大小:92.62KB
下载 相关 举报
数据结构课程设计插队买票.docx_第1页
第1页 / 共16页
数据结构课程设计插队买票.docx_第2页
第2页 / 共16页
数据结构课程设计插队买票.docx_第3页
第3页 / 共16页
数据结构课程设计插队买票.docx_第4页
第4页 / 共16页
数据结构课程设计插队买票.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

数据结构课程设计插队买票.docx

《数据结构课程设计插队买票.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计插队买票.docx(16页珍藏版)》请在冰豆网上搜索。

数据结构课程设计插队买票.docx

数据结构课程设计插队买票

 

数据结构课程设计报告

插队买票

专业

学生姓名

班级

学号

指导教师

完成日期

2015年1月24日

数据结构课程的设计

1、设计题目

春节前夕,一年一度的运输高潮也开始了,成千上万的外出人员都往家赶.火车站售票窗前买票队伍一眼望不到头.运气好的,碰到一个已经在排队的朋友,直接走过去,排他后面,这就叫"插队",但对队伍里的其他人来说是不公平的.本课程设计的任务是写一个程序模拟这种情况.每个队伍都允许插队.如果你在排队,有一个以上的朋友要求插队,则你可以安排他们的次序.每次一个人入队,并且如果这个入队的人发现队伍中有自己的朋友,则可以插入到这个朋友的后面;当队伍中的朋友不止一个的时候,这个人会排在最后一个朋友的后面;如果队伍中没有朋友,则他只能够排在这个队伍的最后面.每一个入队的人都先进行上述的判断.当队伍前面的人买到车票之后.依次出队.

2、课题目的及要求

2.1目的:

数据结构课程设计是为数据结构课程独立开设的实践性教学环节。

数据结构课程设计对于巩固数据结构知识,加强学生的实际动手能力和提高学生综合素质是十分必要的。

 本题目主要解决两个问题:

一是怎么存放和查找大量数据(主要是姓名);二是怎么操作“ENQUEUE”和“DEQUEUE”命令。

2.2要求:

1)输入要求:

程序从“input.txt”文件读入测试用例,一个文件可包含多个测试用例。

每个用例的第一行是朋友组的数目n(1<=n<=1000).对于一个朋友组以朋友的数目j(1<=j<=1000)开始,由朋友的个数以及他们的名字组成,一个空格后接该组朋友的名字,以空格分开,并且每个人的名字都不同。

每个名字不超过4个字母,由{A,B,…,Z,a,b,…,z}组成。

一个朋友组最多有1000个人,每个人只属于一个朋友组。

n=0时,测试数据结束。

下面是一些具体命令:

ENQUEUEX——X入队

DEQUEUE——排队头的人买票,离开队伍,即出队

STOP——一个测用例结束

2)、输出要求:

测试结果输出到“output.txt”文件中。

每个测试用例的第一行输出“Scenario#k”,k是测试用例的序号(从1开始)。

对每一个DEQUEUE命令,输出刚买票离开队伍的人名。

两个测试用例之间隔一空行,最后一个用例结束不输出空行。

3、设计分析

图1系统总图

3.1用散列表来存放和查找数据

由于最多有1000个朋友组,每组最多1000人,使用平方探测法解决冲突,则表的大小至少是2*(1000*1000),所以选择TableSize=2000003。

同一个组内的都是朋友,所以每个人除了记录他的名字name,还要记录他属于哪个朋友组group,另外用info来表示该单元是否被占用,数据结构如图2所示。

散列函数是根据Honer法则计算一个以64为阶的多项式,如图3所示。

冲突解决方法采用平方探测法,如图4所示。

#defineTabSize2000003

typedefstructhashtab*PtrToHash;

structhashtab

{

charname[5];

intgroup;

charinfo;/*用来表示该单元是否被占用*/

};

图2数据结构:

散列表

intHash(char*key,intTableSize)

{

intHashVal=0;

while(key!

=NULL)

HashVal=(HashVal<<6)+*key;

ReturnHashVal%TableSize;

}

图3散列函数

long int Find(PtrToHash hash,char *c)

{

   key=c; 

 CurrentPos=Hash(key,TabSize);                     /*计算散列值*/

  CollisionNum=0; 

  while((单元被占用)and(单元内的名字与查找的名字不同))  /*发生冲突*/

 {        /*平方探测法*/  

 CurrentPos+=2*(++CollisionNum)-1;   

if(CurrentPos>=TabSize)    

CurrentPos-=TabSize; 

 }     

 return CurrentPos;/*返回在散列表中的位置*/ 

图4用平方探测法处理冲突

3.2怎么操作“ENQUEUE”和“DEQUEUE”命令

这可以用队列来模拟。

由于有插队现象的存在,不能单纯地用一个数组来表示队列,因为这样的话,插入一个朋友,则他后面的人都要往后移一个单位,删除一个人,则他后面的人都要前移一个,会降低效率。

所以,采用一个Index标记来表示当前元素的后继元素,最后一个单元的后继元素是第0个,形成环,数据结构如图5所示。

不用链表是因为链表存放指针也需要空间,并且链表插入、删除的效率没有数组高。

typedef struct Que *PtrToQue; 

struct Que{ 

 long int HashVal;              /*散列值*/ 

 long int Index;                /*在中的队列序号*/ 

};

图5数据结构:

队列

1)输入ENQUEUE命令,如果队伍里有朋友,则排在朋友后面;如果没有遇到朋友,则排到队尾。

入队时,用一个数组记录每个朋友组的最后一位,以便下一个朋友到来时排到他后面,这个数组被称为“插入数组”。

 

2)输入“DEQUEUE”命令,则根据“先进先出”,按照各个元素和它后继元素的先后顺序,每次删除队列中的第一个。

程序结构如图6所示。

 

While(读测试文件) 

if(输入“ENQUEUE”) 

{

读入名字; 

插入散列表; 

插入队列;

 } 

else if(输入“DEQUEUE”) 

{

删除队列第一个名字;

 将该名字输出到文件; 

Else stop; 

图6入队、出队操作

4、调试与测试

4.1调试

先运行,出现如图7所示:

图7运行

4.2测试

1)测试输入

2

3AnnBobJoe

3ZoeJimFat

ENQUEUEAnn

ENQUEUEZoe

ENQUEUEBob

ENQUEUEJim

ENQUEUEJoe

ENQUEUEFat

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

STOP

2

5AnnyJackJeanBillJane

6EvaMikeRonSonyGeoZoro

ENQUEUEAnny

ENQUEUEEva

ENQUEUEJack

ENQUEUEJean

ENQUEUEBill

ENQUEUEJane

DEQUEUE

DEQUEUE

ENQUEUEMike

ENQUEUERon

DEQUEUE

DEQUEUE

DEQUEUE

DEQUEUE

STOP

0

2)正确输出

Scenario#1

Ann

Bob

Joe

Zoe

Jim

Fat

Scenario#2

Anny

Jack

Jean

Bill

Jane

Eva

4.3实际结果

1)实际输入

图8输入数据

2)实际输出

图9输出数据

5、小结

在前面的学习过程中我们学到了很多知识,而这次课程设计又是对我们所学的一次总结.我们必须掌握很多已学的知识才能很好的完成本次的课程设计。

在这次课程设计中,总的感觉是我遇到了很多困难,这主要是由于我编写代码的经验不足,有时虽然是一个很小的问题,但解决起来却花费了我不少的时间,值得欣慰的是,当自己苦思冥想或者和其它同学一起探讨,把问题解决的时候我还是觉得获益非浅,这就是在摸索中寻求到的知识。

设计期间,我发现只有有目的的去学习一些将要用到的东西,充分的运用所学知识,才能顺利的完成设计。

在设计时也免不了存在着一些不足,所以在今后的学习中我会努力取得更大的进步,对于我不足的地方希望老师能够及时给予批评,以便我在今后的学习中能够及时的改正。

 

通过这次课程设计,我收获的不仅仅是课程上的知识得到实际应用,还有编程的基本习惯和应注意的细节。

6、参考文献

[1]范策,周世平,胡哓琨.《算法与数据结构(C语言版)》[M].北京:

机械工业出版社,2004

[2]严蔚敏.《数据结构(C语言版)》.北京:

清华大学出版社,2004

[3]许卓群,杨冬青,唐世渭,张铭.《数据结构与算法》.北京:

高等教育出版社,2004

[4]徐孝凯.《数据结构实用教程(第二版)》.北京:

清华大学出版社,2006

7、源程序清单

#include

#include

#include

#defineTabSize2000003/*散列表大小TabSize是大于表最大空间的素数*/

#defineMax1000001/*队列空间最大值*/

structhashtab;

typedefstructhashtab*PtrToHash;

structhashtab/*散列表数据结构*/

{

charname[5];/*名字*/

intgroup;/*属于哪个朋友组*/

charinfo;/*标志位,该单元是否被占用*/

};

structQue;

typedefstructQue*PtrToQue;

structQue/*队列数据结构*/

{

longintHashVal;/*散列值*/

longintIndex;/*在中的队列序号*/

};

inthashedx=0;/*标记元素是否已经在散列表里*/

longintFind(PtrToHashhash,char*c)/*查找在散列表中的位置*/

{

char*key;

longintCurrentPos,CollisionNum;

key=c;

for(CurrentPos=0;*key;++key)/*散列函数,计算散列值*/

CurrentPos=(CurrentPos<<6)+*key;

CurrentPos%=TabSize;/*散列值*/

CollisionNum=0;

/*如果当前单元被占用:

单元内的元素与当前操作的名字不同,使用平方探测法解决冲突;与当前操作的名字相同,则直接返回在散列中的位置*/

while((hash[CurrentPos].info)&&(strcmp(hash[CurrentPos].name,c)))

{/*平方探测法*/

CurrentPos+=2*(++CollisionNum)-1;

if(CurrentPos>=TabSize)

CurrentPos-=TabSize;

}

if((hash[CurrentPos].info)&&(strcmp(hash[CurrentPos].name,c)==0))

/*元素已经在散列表里*/

hashedx=1;

else/*元素不在散列表里*/

hashedx=0;

returnCurrentPos;/*返回在散列表中的位置*/

}

intmain()

{

longintFind(PtrToHashhash,char*c);/*查找在散列表中的位置*/

PtrToHashhash;/*散列表*/

PtrToQuequeue;/*队列*/

int*grouppos;/*记录每个朋友组的最后一位,即插队数组*/

intn;/*测试用例数目*/

intnum;/*当前测试用例序号*/

longinti,ii,j,key,temp;

longinthead,last;/*队列的头和尾*/

charc[8],tempc[8];/*名字*/

FILE*fpin,*fpout;/*输入、输出文件指针*/

if(!

(fpin=fopen("input.txt","r")))/*打开测试文件*/

{

printf("fopenerror!

");/*文件打开错误*/

return-1;

}

if(!

(fpout=fopen("output.txt","w")))/*打开输出文件*/

{

printf("fopenerror!

");

return-1;

}

hash=(PtrToHash)malloc(sizeof(structhashtab)*TabSize);/*为散列表申请空间*/

queue=(PtrToQue)malloc(sizeof(structQue)*Max);/*为队列申请空间*/

grouppos=(int*)malloc(sizeof(int)*1000);/*申请空间记录每个朋友组的最后一位*/

for(i=0,j=1;i

queue[i].Index=j;

queue[i-1].Index=0;/*最后一个单元的后继单元是第0个,形成环*/

num=0;

for(fscanf(fpin,"%d",&n);n;fscanf(fpin,"%d",&n))/*输入当前测试用例的朋友组数*/

{

if(n<1||n>1000)/*处理异常输入n*/

{

fprintf(fpout,"nisoutofrange\n");

return-1;

}

num++;

if(num!

=1)/*两个测试用例间输入一空行*/

fprintf(fpout,"\n");

for(i=0;i

hash[i++].info=0;/*初始化散列表,标记位置0*/

for(i=0;i

{

fscanf(fpin,"%d",&j);/*当前组里的人数*/

if(j<1||j>1000)/*处理异常输入j*/

{

fprintf(fpout,"jisoutofrange\n");

return-1;

}

for(;j;--j)

{

fscanf(fpin,"%s",c);/*输入名字*/

for(ii=0;ii

tempc[ii]='\0';

strcpy(tempc,c);

ii=0;

while(tempc[ii]!

='\0')/*是否由四个以内字母组成*/

{

if(tempc[ii]<'A'||('Z''z'||ii>4)

{

fprintf(fpout,"Group%d:

Nonstandardname\n",i);

return-1;

}

ii++;

}

key=Find(hash,c);/*找到在散列表中的位置*/

if(hashedx==1)/*重名*/

{

fprintf(fpout,"repeatedname%s\n",c);

return-1;

}

strcpy(hash[key].name,c);/*插入散列表*/

hash[key].info=1;/*标记置1,该单元被占用*/

hash[key].group=i;/*记录他属于哪个组*/

}

}

for(i=0;i<1000;)

grouppos[i++]=0;/*初始化插队数组*/

head=0;/*初始化队列头、尾标记*/

last=0;

fprintf(fpout,"Scenario#%d\n",num);/*输出当前用例序号到文件*/

for(fscanf(fpin,"%s",c);;fscanf(fpin,"%s",c))/*输入命令*/

{

if(*c=='E')/*入队命令*/

{

fscanf(fpin,"%s",c);/*输入名字*/

key=Find(hash,c);/*查找在散列表中的位置*/

if(hashedx==0)/*散列表里没这个人*/

{

fprintf(fpout,"no%s\n",c);

return-1;

}

temp=queue[0].Index;/*队列第0个位置记录队尾的后继单元*/

queue[0].Index=queue[temp].Index;

/*在队列中申请一个新单元,队尾标记后移一个位置*/

queue[temp].HashVal=key;/*入队*/

if(!

head)/*如果是队列里的第一个元素*/

last=head=temp;/*队头、队尾标记指向第一个元素*/

if(!

grouppos[hash[key].group])/*如果队列里没朋友*/

{

queue[temp].Index=0;/*队尾指向对头,形成环*/

queue[last].Index=temp;/*前一次队尾的后继元素是当前元素*/

last=temp;/*队尾标记指向当前元素*/

grouppos[hash[key].group]=temp;

/*插队数组记录该朋友组里已入队的最后一位*/

}

else/*如果队列中已经有他的朋友*/

{

queue[temp].Index=queue[grouppos[hash[key].group]].Index;

/*插队到朋友的后面*/

queue[grouppos[hash[key].group]].Index=temp;

/*插队到朋友后面一位的前面*/

grouppos[hash[key].group]=temp;

/*替换插队数组里该组的元素为当前元素*/

if(hash[queue[last].HashVal].group==hash[key].group)

/*如果当前元素和前一元素是朋友,队尾标志指向当前元素*/

last=temp;

}

}

elseif(*c=='D')/*出队命令*/

{

if(last==0)/*不能对空队列执行出队命令*/

{

fprintf(fpout,"Emptyqueue!

\nCan'texecuteDEQUEUE!

\n");

return-1;

}

fprintf(fpout,"%s\n",hash[queue[head].HashVal].name);

/*输出队头元素到文件*/

temp=head;

head=queue[temp].Index;/*队列第一位出队,队头标记后移一位*/

queue[temp].Index=queue[0].Index;/*队列第0个元素后移一位*/

queue[0].Index=temp;/*释放空间*/

if(grouppos[hash[queue[temp].HashVal].group]==temp)

/*当前删除的元素是该朋友组在队列里的最后一位*/

grouppos[hash[queue[temp].HashVal].group]=0;

if(last==temp)/*出队后,队列为空*/

last=0;

}

else/*输入"STOP"*/

break;/*测试结束*/

}

}

fprintf(fpout,"\b");

fclose(fpin);

fclose(fpout);

return1;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 研究生入学考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1