数据结构课设.docx
《数据结构课设.docx》由会员分享,可在线阅读,更多相关《数据结构课设.docx(21页珍藏版)》请在冰豆网上搜索。
![数据结构课设.docx](https://file1.bdocx.com/fileroot1/2023-6/11/4fd6855c-6aaf-4346-9030-21bb55779b42/4fd6855c-6aaf-4346-9030-21bb55779b421.gif)
数据结构课设
摘要
“数据结构”是计算机专业一门重要的专业技术基础课程,是计算机专业的一门核心的关键性课程。
它较系统地介绍了软件设计中常用的数据结构以及相应的存储结构和实现算法,介绍了常用的多种查找和排序技术,并做了性能分析和比较,内容非常丰富。
数据结构的学习将为后续课程的学习以及软件设计水平的提高打下良好的基础。
为了更好地学习,理解和掌握算法设计所需的技术,为整个专业学习打好基础,要求运用所学知识,上机解决一些典型问题,通过分析、设计、编码、调试等各环节的训练,使我们深刻理解、牢固掌握所用到的一些技术。
数据结构中稍微复杂一些的算法设计中可能同时要用到多种技术和方法,如算法设计的构思方法,动态链表,算法的编码,递归技术,与特定问题相关的技术等,要求重点掌握线性链表、二叉树和树、图结构、数组结构相关算法的设计。
在掌握基本算法的基础上,掌握分析、解决实际问题的能力。
关键字:
链表;邻接距阵;遍历;
目录
设计题目………………………………………………………3
设计目的………………………………………………………4
设计程序………………………………………………………5
设计总结………………………………………………………16
设计心得………………………………………………………17
参考资料………………………………………………………18
致谢……………………………………………………………19
设计题目
1、二叉树的周游
(1)目的
掌握二叉树的二叉链表存贮结构。
掌握栈的基本运算实现。
掌握二叉树的先序、中序、后序三种周游的算法实现。
(2)设计内容和要求
对任意给定的二叉树(顶点数自定)建立它的二叉链表存贮结构,并利用栈的五种基本运算(清空堆栈、压栈、弹出、取栈顶元素、判栈空)实现二叉树的先序、中序、后序三种周游,输出三种周游的结果
2、图的深度周游
(1)目的
掌握图的邻接表存贮结构。
掌握堆栈的基本运算实现。
掌握图的邻接表的算法实现。
掌握图的深度优先搜索周游算法实现。
(2)设计内容和要求
对任意给定的图(顶点数和边数自定),建立它的邻接表并输出,然后利用堆栈的五种基本运算(清空堆栈、压栈、弹出、取栈顶元素、判栈空)实现图的深度优先搜索周游。
3、joseph环
(1)目的
检验对链表结构及算法的掌握程度。
(2)设计内容和要求
编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个仍开始顺时针方向自1开始顺序报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。
设计一个程序来求出出列顺序。
要求:
利用单向循环链表存储结构模拟此过程,按照出列的顺序输出各个人的编号。
测试数据:
m的初值为20,n=7,7个人的密码依次为3,1,7,2,4,7,4,首先m=6,则正确的输出是什么?
要求:
输入数据:
建立输入处理输入数据,输入m的初值,n,输入每个人的密码,建立单循环链表。
输出形式:
建立一个输出函数,将正确的输出序列。
设计目的:
通过本课程设计集中性的编程训练,培养学生上机动手能力,巩固《数据结构》课程学习的内容,使学生系统的掌握如何将客观实际问题与计算机的算法对应起来,如何将客观信息与数据的逻辑结构和存储结构对应起来的方法。
为后续各门计算机课程的学习打下坚实基础。
图的深度优先遍历
深度优先搜索(Depth-FirstSearch)遍历类似于树的先根遍历,是树的先根遍历的推广。
其基本思想如下:
假定以图中某个顶点vi为出发点,首先访问出发点,然后选择一个vi的未访问过的邻接点vj,以vj为新的出发点继续进行深度优先搜索,直至图中所有顶点都被访问过。
显然,这是一个递归的搜索过程。
现以图5-3-1中G为例说明深度优先搜索过程。
假定v0是出发点,首先访问v0。
因v0有两个邻接点v1、v2均末被访问过,可以选择v1作为新的出发点,访问v1之后,再找v1的末访问过的邻接点。
同v1邻接的有v0、v3和v4,其中v0已被访问过,而v3、v4尚未被访问过,可以选择v3作为新的出发点。
重复上述搜索过程,继续依次访问v7、v4。
访问v4之后,由于与v4相邻的顶点均已被访问过,搜索退回到v7。
由于v7、v3和v1都是没有末被访问的邻接点,所以搜索过程连续地从v7退回到v3,再退回v1,最后退回到v0。
这时再选择v0的末被访问过的邻接点v2,继续往下搜索,依次访问v2、v5和v6,止此图中全部顶点均被访问过。
遍历过程见图5-3-1(b),得到的顶点的访问序列为:
v0→v1→v3→v7→v4→v2→v5→v7。
(a)无向图G(b)G的深度优先搜索过程
图5-3-1深度优先搜索遍历过程示例
设计程序如下
#include
#include
#defineINFINITY32767
#defineMAX_VEX20//最大顶点个数
bool*visited;//访问标志数组
//图的邻接矩阵存储结构
typedefstruct{
char*vexs;//顶点向量
intarcs[MAX_VEX][MAX_VEX];//邻接矩阵
intvexnum,arcnum;//图的当前顶点数和弧数
}Graph;
//图G中查找元素c的位置
intLocate(GraphG,charc){
for(inti=0;iif(G.vexs[i]==c)returni;
return-1;
}
//创建无向网
voidCreateUDN(Graph&G){
inti,j,w,s1,s2;
chara,b,temp;
printf("输入顶点数和弧数:
");
scanf("%d%d",&G.vexnum,&G.arcnum);
temp=getchar();//接收回车
G.vexs=(char*)malloc(G.vexnum*sizeof(char));//分配顶点数目
printf("输入%d个顶点.\n",G.vexnum);
for(i=0;iprintf("输入顶点%d:
",i);
scanf("%c",&G.vexs[i]);
temp=getchar();//接收回车
}
for(i=0;ifor(j=0;jG.arcs[i][j]=INFINITY;
printf("输入%d条弧.\n",G.arcnum);
for(i=0;iprintf("输入弧%d:
",i);
scanf("%c%c%d",&a,&b,&w);//输入一条边依附的顶点和权值
temp=getchar();//接收回车
s1=Locate(G,a);
s2=Locate(G,b);
G.arcs[s1][s2]=G.arcs[s2][s1]=w;
}
}
//图G中顶点k的第一个邻接顶点
intFirstVex(GraphG,intk){
if(k>=0&&kfor(inti=0;iif(G.arcs[k][i]!
=INFINITY)returni;
}
return-1;
}
//图G中顶点i的第j个邻接顶点的下一个邻接顶点
intNextVex(GraphG,inti,intj){
if(i>=0&&i=0&&jfor(intk=j+1;kif(G.arcs[i][k]!
=INFINITY)returnk;
}
return-1;
}
//深度优先遍历
voidDFS(GraphG,intk){
inti;
if(k==-1){//第一次执行DFS时,k为-1
for(i=0;iif(!
visited[i])DFS(G,i);//对尚未访问的顶点调用DFS
}
else{
visited[k]=true;
printf("%c",G.vexs[k]);//访问第k个顶点
for(i=FirstVex(G,k);i>=0;i=NextVex(G,k,i))
if(!
visited[i])DFS(G,i);//对k的尚未访问的邻接顶点i递归调用DFS
}
}
//主函数
voidmain(){
inti;
GraphG;
CreateUDN(G);
visited=(bool*)malloc(G.vexnum*sizeof(bool));
printf("\n深度优先遍历:
");
for(i=0;ivisited[i]=false;
DFS(G,-1);
printf("\n程序结束.\n");
}
2二叉树的周游
Top从顶向下遍历
而p指针为右子树定位
程序如下:
#include"stdio.h"
#include"stdlib.h"
#defineMAX_NODE100
#defineNODE_COUNT18
#defineNODE_COUNT215
intTreeValue0[NODE_COUNT1][2]={{'0',0},{'D',1},{'B',2},{'F',3},{'A',4},{'C',5},{'E',6},{'G',7}};
intTreeValue1[NODE_COUNT1][2]={{'0',0},{'A',1},{'B',2},{'C',3},{'D',4},{'E',5},{'F',6},{'G',7}};
intTreeValue2[NODE_COUNT2][2]={{'0',0},{'A',1},{'B',2},{'C',3},{'D',4},{'E',5},{'F',6},{'G',7},{'H',8},{'I',9},{'J',10},{'K',11},{'L',12},{'M',13},{'N',14}};
structBTree
{
intdata;
intorder;
BTree*lchild;
BTree*rchild;
};
voidSwap(int*p1,int*p2)
{
intt;
t=*p1;
*p1=*p2;
*p2=t;
}
/*
functionCreateBTree()功能:
创建一颗二叉树,并返回一个指向其根的指针
*/
BTree*CreateBTree(intdata[][2],intn)
{
BTree*Addr[MAX_NODE];
BTree*p,
*head;
intnodeorder,//节点序号
noderoot,//节点的双亲
i;
if(n>MAX_NODE)
{
printf("参数错误!
\n");
return(0);
}
for(i=1;i<=n;i++)
{
p=(BTree*)malloc(sizeof(BTree));
if(p==NULL)
{
printf("内存溢出错误!
\n");
return(0);
}
else
{
p->data=data[i][0];
p->lchild=NULL;
p->rchild=NULL;
nodeorder=data[i][1];
p->order=nodeorder;
Addr[nodeorder]=p;
if(nodeorder>1)
{
noderoot=nodeorder/2;
if(nodeorder%2==0)
Addr[noderoot]->lchild=p;
else
Addr[noderoot]->rchild=p;
}
else
head=p;
printf("BTree[%d]=%c\t",p->order,p->data);
}
//free(p);
}
return(head);
}
/*
functionFirstOrderAccess0()功能:
实现二叉树的前序遍历
二叉树前序遍历的思想:
从根节点开始,沿左子树一直走到没有左孩子的节点为止,
依次访问所经过的节点,同时所经[节点]的地址进栈;
当找到没有左孩子的节点时,从栈顶退出该节点的双亲的
右孩子,此时,此节点的左子树已访问完毕;
在用上述方法遍历该节点的右子树,如此重复到栈空为止。
*/
voidFirstOrderAccess0(BTree*header)
{
BTree*stack[MAX_NODE];
BTree*p;
inttop;
top=0;
p=header;
do
{
while(p!
=NULL)
{
printf("BTree[%d]=%c\t",p->order,p->data);//访问节点P
top=top+1;
stack[top]=p;
p=p->lchild;//继续搜索节点P的左子树
}
if(top!
=0)
{
p=stack[top];
top=top-1;
p=p->rchild;//继续搜索节点P的右子树
}
}while((top!
=0)||(p!
=NULL));
}
/*
functionFirstOrderAccess1()功能:
实现二叉树的前序遍历
二叉树前序遍历的思想:
从根节点开始,沿左子树一直走到没有左孩子的节点为止,
依次访问所经过的节点,同时所经[节点的非空右孩子]进栈;
当找到没有左孩子的节点时,从栈顶退出该节点的双亲的
右孩子,此时,此节点的左子树已访问完毕;
在用上述方法遍历该节点的右子树,如此重复到栈空为止。
*/
voidFirstOrderAccess1(BTree*header)
{
BTree*stack[MAX_NODE];
BTree*p;
inttop;
top=0;
p=header;
do
{
while(p!
=NULL)
{
printf("BTree[%d]=%c\t",p->order,p->data);
if(p->rchild!
=NULL)
stack[++top]=p->rchild;
p=p->lchild;
}
if(top!
=0)
p=stack[top--];
}while((top>0)||(p!
=NULL));
}
/*
functionMiddleOrderAccess()功能:
实现二叉树的中序遍历
二叉树中序遍历的思想:
从根节点开始,沿左子树一直走到没有左孩子的节点为止,
并将所经[节点]的地址进栈;
当找到没有左孩子的节点时,从栈顶退出该节点并访问它,
此时,此节点的左子树已访问完毕;
在用上述方法遍历该节点的右子树,如此重复到栈空为止。
*/
voidMiddleOrderAccess(BTree*header)
{
BTree*stack[MAX_NODE];
BTree*p;
inttop;
top=0;
p=header;
do
{
while(p!
=NULL)
{
stack[++top]=p;//节点P进栈
p=p->lchild;//继续搜索其左子树
}
if(top!
=0)
{
p=stack[top--];//节点P出栈
printf("BTree[%d]=%c\t",p->order,p->data);//访问节点P
p=p->rchild;//继续搜索其左子树
}
}while((top!
=0)||(p!
=NULL));
}
/*
functionLastOrderAccess()功能:
实现二叉树的后序遍历
二叉树后序遍历的思想:
从根节点开始,沿左子树一直走到没有左孩子的节点为止,
并将所经[节点]的地址第一次进栈;
当找到没有左孩子的节点时,此节点的左子树已访问完毕;
从栈顶退出该节点,判断该节点是否为第一次进栈,如是,再
将所经[节点]的地址第二次进栈,并沿该节点的右子树一直走到
没有右孩子的节点为止,如否,则访问该节点;此时,该节点的
左、右子树都已完全遍历,且令指针p=NULL;
如此重复到栈空为止。
*/
voidLastOrderAccess(BTree*header)
{
BTree*stack[MAX_NODE];//节点的指针栈
intcount[MAX_NODE];//节点进栈次数数组
BTree*p;
inttop;
top=0;
p=header;
do
{
while(p!
=NULL)
{
stack[++top]=p;//节点P首次进栈
count[top]=0;
p=p->lchild;//继续搜索节点P的左子树
}
p=stack[top--];//节点P出栈
if(count[top+1]==0)
{
stack[++top]=p;//节点P首次进栈
count[top]=1;
p=p->rchild;//继续搜索节点P的左子树
}
else
{
printf("BTree[%d]=%c\t",p->order,p->data);//访问节点P
p=NULL;
}
}while((top>0));
}
intmain(intargc,char*argv[])
{
BTree*TreeHeader;
printf("二叉树创建数据结果:
\n");
TreeHeader=CreateBTree(TreeValue1,NODE_COUNT1-1);
//TreeHeader=CreateBTree(TreeValue2,NODE_COUNT2-1);
if(TreeHeader==0)
{
printf("二叉树创建失败!
\n");
return(0);
}
else
{
printf("\n二叉树前序遍历结果:
\n");
FirstOrderAccess1(TreeHeader);
printf("\n二叉树中序遍历结果:
\n");
MiddleOrderAccess(TreeHeader);
printf("\n二叉树后序遍历结果:
\n");
LastOrderAccess(TreeHeader);
return0;
}
}
3、joseph环:
typedefstructLNode
{
intpassword;//密码
intNo;//序号
structLNode*next;//下一成员指针
}member;//成员结构体
typedefintstatus;
#defineOVERFLOW-2
#defineOK1
#defineERROR0
#include
#include
statusCreateList_Circle(member**,int);
statusDeleteNode(member**);
statusmain()
{
intn,m;
member*head=NULL,*p=NULL;//头指针即首成员地址,遍历指针p
printf("Pleaseenternumberofpeople:
\n");
scanf("%d",&n);//总成员数
while(n<=0)
{
printf("nmustbepositive,pleaseenteragain:
\n");
scanf("%d",&n);
}
if(!
CreateList_Circle(&head,n))//创建循环链表,返回头指针head
returnOVERFLOW;
printf("Pleaseenterinitialm:
\n");
scanf("%d",&m);//初始m
while(m<=0)
{
printf("mmustbepositive,pleaseenteragain:
\n");
scanf("%d",&m);
}
printf("\nTheorderis:
\n");
p=head;
while(n>=2)//寻找出列成员
{
inti;
m=(m%n==0)?
n:
m%n;//化简m值
for(i=1;ip=p->next;//p指向出列成员
printf("%d\n",p->No);//输出出列成员序号
m=p->password;//修改m
DeleteNode(&p);//删除链表中的出列成员
n--;//成员数自减
}
printf("%d\n",p->No);//输出最后一个成员序号
returnOK;
}
statusCreateList_Circle(member**p_head,intn)
{
//此算法创建一个无头结点的循环链表,结点数n,*p_head返回链表头指针即首结点地址
inti;
member*tail,*p;
*p_head=(member*)malloc(sizeof(member));
if(!
(*p_head))returnOVERFLOW;
(*p_head)->No=1;//储存成员一序号
printf("PleaseenterpasswordofNo.1:
\n");
scanf("%d",&(*p_head)->password);//储存成员一密码
tail=*p_head;
tail->next=NULL;
for(i=