数据结构期末课程设计

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

设计1----约瑟夫环问题
一、需求分析
1、问题描述:设编号为1,2…,n(n>0)个人按顺时针方向围坐一圈,每人持有一个正整数密码。

开始时任意给出一个报数上限值m,从第一人开始顺时针方向自1起顺序报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他在顺指针方向上的下一个人起重新自1起顺序报数;下去,直到所有人全部出列为止。

2、首先指定报数上限值,建立循环链表中不需要头结点,注意空表与非空表的界限。

3、程序执行的命令包括:创建链表;删除结点;输出出列顺序;结束。

二、概要设计
1、为实现上述程序功能,应以不带头结点的循环链表存储密码与编号。

为此,需要一个抽象数据类型:循环链表。

如下:
数据关系:R1={<ai-1,ai>|ai-1,ai∈D,ai-1<ai,i=1,2,……,n}
基本操作:creat(&L,n)
操作结果:构造长度为n的循环链表。

Listdelete(&L, e)
初始条件:线性表L存在。

操作结果:删去报数为e的元素L长度减一。

2、本程序包括三个模块:一是主程序模块;
Void main(){
初始化L 调用linklist creat(linklist L)
调用void deletenode(linklist L)
}
二是链表的建立;三是删除指定链表元素。

三、详细设计
主要程序:
typedef struct LNode {
int number;
int password;
struct LNode *next; }LNode,*LinkList;
LinkList create(int n)//建立一个没有头结点的循环链表
{
LinkList head,p1,p2;
int i;
for(i=1;i<=n;i++)
{
p1=(LinkList)malloc(sizeof(LNode));
printf("第%d个人的密码为:",i);
scanf("%d",&p1->password);
p1->number=i;
if(i==1)
head=p1;
else
p2->next=p1;
p2=p1;
}
p2->next=head;
return(head);
}
int main()//主函数
{
LinkList head,p,s;
int m,N,j,k,count=0;
printf("输入总的人数:");
scanf("%d",&N);
printf("输入初始密码:");
scanf("%d",&m);
head=create(N);
for(j=N;j>=1;j--)
{
count++;
p=head;
for(k=1;k<m+j;k++)
{
s=p;
p=p->next;
}
m=p->password;
printf("第%d个退出的是编号为%d的人,密码为%d\n",count,p->number,m);
s->next=p->next;
head=p->next;
free(p);
}
return 0;
}
四、运行结果及分析
五、总结
通过这次课程设计,让我对单循环链表有了更深刻的体会,掌握了单循环链表的初始化,创建,删除,遍历等操作。

在调试程序的时候,可以逐块的检查,遇到程序报错时,可以手工操作模拟程序的运行,需要跟踪某个变量时,可以在函数适当的位置加入输出语句,查看变量的值的变化情况。

经常会将链表中的指针所指的位置混淆,以致在头结点的位置上徘徊多时,今后应多注意这方面的问题。

设计2----迷宫问题
一、需求分析
1、问题描述:迷宫是一些互相连通的交叉路口的集合,给定一个迷宫入口,一个迷宫出口,当从入口到出口存在通路时输出其中的一条通路,当从入口到出口不存在通路时输出无通路存在。

2、要求:利用随机方法产生一个m n的迷宫,0和1分别表示迷宫中的通路和障碍。

存在回路时能记住已经走过的路口,不重复已经走过的路口。

3、程序执行命令包括:创建迷宫;创建空栈;销毁栈;寻找通路;输出迷宫。

二、概要设计
1、设定栈的抽象数据类型定义:
ADT Stack{
数据对象:D={ai|ai∈CharSet,i=1,2,…,n,n>=0}
数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,…,n}
}
2、求解迷宫的算法:
设定当前位置的初值为入口位置;
do{
若当前位置可通
则{将当前位置插入栈顶;
若当前位置是出口位置,则结束;
否则切换当前位置的相邻位置为新的当前位置;
}
否则{
若栈不空且栈顶位置尚有其他方向未被探索;
则设定新的位置为沿顺时针方向旋转找到的栈顶位置的下一邻块;
若栈不空且栈顶位置的四周均不可通;
则{删去栈顶位置;
若栈不空,则重新测试新的栈顶位置,直至找到一个可通的相邻块或栈空; }
}
}while (栈不空);
3、以结构的形式来表示迷宫矩阵的每个点以及后续的整个通路的点
struct
{
int i; //行号
int j; //列号
int di; //下一个可走相邻方位的方位号
} Stack[MaxSize]; //定义栈
三、详细设计
主要程序:
#include <stdio.h>
#define MaxSize 100
#define M 4
#define N 4
迷宫初始化:
int mg[6][6]={{1,1,1,1,1,1},
{1,0,1,1,1,1},
{1,0,1,1,1,1},
{1,0,0,1,1,1},
{1,1,0,0,0,1},
{1,1,1,1,1,1}};
int top=-1; //初始化栈顶
int count=1; //路径数计数
迷宫函数:
void MgPath()
{
int i,j,k,di,find;
top++; //初始方块进入栈
Stack[top].i=1;
Stack[top].j=1;
Stack[top].di=-1;
mg[1][1]=-1;
while (top>-1) //栈不空时循环
{
i=Stack[top].i;j=Stack[top].j;di=Stack[top].di; //取栈顶
if (i==M && j==N&&count>=1) //找到了出口,输出路径
{
printf("%d:",count++);
for (k=0;k<=top;k++)
{
printf("(%d,%d)",Stack[k].i,Stack[k].j);
}
printf("\n");
mg[Stack[top].i][Stack[top].j]=0; //让该位置变为其他路径可走方块
top--;
i=Stack[top].i;j=Stack[top].j;di=Stack[top].di;
}
find=0;
while (di<4 && find==0) //找(i,j)方块下一个可走方块
{
di++;
switch(di)
{
case 0:i=Stack[top].i-1;j=Stack[top].j;break;
case 1:i=Stack[top].i;j=Stack[top].j+1;break;
case 2:i=Stack[top].i+1;j=Stack[top].j;break;
case 3:i=Stack[top].i,j=Stack[top].j-1;break;
}
if (mg[i][j]==0)
find=1;
}
if (find==1) //找到了一个可走的相邻方块
{
Stack[top].di=di; //修改原栈顶元素的di值
top++; //将可走相邻方块进栈
Stack[top].i=i;
Stack[top].j=j;
Stack[top].di=-1;
mg[i][j]=-1; //避免重复走到该方块,将其置为-1
}
else //没有相邻方块可走,则退栈
{
mg[Stack[top].i][Stack[top].j]=0; //让该位置变为其他路径可走方块
top--;
}
}
if(count==1)
printf("迷宫无通路\n");
}
主函数:
int main()
{
printf("从(1,1)到(4,4)的通路为:\n");
MgPath();
return 0;
}
四、运行结果及分析
五、总结
开始对栈的构造以及出栈入栈函数不清楚,而且定义的出栈函数繁琐,定义的函数有逻辑上的错误。

通过迷宫求解的编程练习思考数据结构的使用,比如对栈、指针、链表等的深入了解,让我们感受到了数据结构及其算法的重要。

此外还熟悉了各种函数的应用。

对于我们初学者来说,学习编写迷宫求解,对我们掌握了解数据结构的知识有很大的帮助。

我们通过编程实践,还能拓展思路,让我们主动去寻找所需要的算法,怎样提高程序的质量等。

设计3----表达式求值问题
一、需求分析
1、问题描述:键盘输入表达式,求该表达式的后缀表达式、再求该表达式的值。

2、要求:分别测试表达式中运算符为一位数、多位数、小数时的值。

3、为了实现算符优先算法。

可以使用两个工作栈。

一个称为OPTR,用以寄存运算符,另一个称做OPND,用以寄存操作数或运算结果。

二、概要设计
1、首先置操作数栈为空栈,表达式起始符“#”为运算符栈的栈底元素;依次读入表达式,若是操作符即进OPND栈,若是运算符则和OPTR栈的栈顶运算符比较优先权后作相应的操作,直至整个表达式求值完毕(即OPTR栈的栈顶元素和当前读入的字符均为“#”)。

2、ADT描述:
ADT Stack{
数据对象:D={ai|ai∈ElemSet,i=1,2,…,n, n≧0}
数据对象:R1={<ai,ai-1>|ai-1,ai∈D,i=2,…,n}
约定an端为栈顶,ai端为栈底;
基本操作:
InitStack(&S) 操作结果:构造一个空栈S。

GetTop(S) 初始条件:栈S已存在。

操作结果:用P返回S的栈顶元素。

Push(&S,ch) 初始条件:栈S已存在。

操作结果:插入元素ch为新的栈顶元素。

Pop(&S) 初始条件:栈S已存在。

操作结果:删除S的栈顶元素。

In(ch) 操作结果:判断字符是否是运算符,运算符即返回1。

Precede(c1, c2) 初始条件:c1,c2为运算符。

操作结果:判断运算符优先权,返回优先权高的。

Operate(a,op,b) 初始条件:a,b为整数,op为运算符。

操作结果:a与b进行运算,op为运算符,返回其值。

num(n) 操作结果:返回操作数的长度。

EvaluateExpression() 初始条件:输入表达式合法。

操作结果:返回表达式的最终结果。

}ADT Stack
三、详细设计
主要程序:
#include <stdio.h>
#include <stdlib.h>
#define OK 1
#define ERROR 0
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 20 //定义字符类型栈
typedef struct{
char *base;
char *top;
int stacksize;
} Stack1; //定义整型栈
typedef struct{
float *base;
float *top;
int stacksize;
} Stack2;
int InitStack1(Stack1 *s) //构造运算符栈,操作数栈
{
s->base=(char *)malloc(STACK_INIT_SIZE*sizeof(char));
if(!s->base)
return ERROR;
s->top=s->base;
s->stacksize=STACK_INIT_SIZE;
return OK;
}
int In(char c) //判断字符是否是运算符,运算符即返回1
{
if(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c==')'||c=='#')
return 1;
else
return 0;
}
int Push1(Stack1 *s,char c) //运算符栈,操作数栈插入c为新的栈顶元素
{
*s->top=c;
s->top++;
return OK;
}
char Pop1(Stack1 *s) //删除运算符栈,操作数栈s的栈顶元素,用e返回其值
{
char e;
s->top--;
e=*s->top;
return e;
}
char GetTop1(Stack1 s)//用e返回运算符栈,操作数栈s的栈顶元素
{
char e;
e=*(s.top-1);
return e;
}
char Precede(char c1,char c2)
{
int i,j;
static char
a[49]={'>','>','<','<','<','>','>','>','>','<','<','<','>','>','>','>','>','> ','<','>','>','>','>','>','>','<','>','>','<','<','<','<','<','=','!','>','>' ,'>','>','!','>','>','<','<','<','<','<','!','='};
switch(c1)
{
case '+' : i=0;break;
case '-' : i=1;break;
case '*' : i=2;break;
case '/' : i=3;break;
case '(' : i=4;break;
case ')' : i=5;break;
case '#' : i=6;break;
}
switch(c2)
{
case '+' : j=0;break;
case '-' : j=1;break;
case '*' : j=2;break;
case '/' : j=3;break;
case '(' : j=4;break;
case ')' : j=5;break;
case '#' : j=6;break;
}
return (a[7*i+j]);
}
int GetNumber(char c)//转化数码
{
return (c-48);
}
float Operate(float a,char theta,float b) {
switch(theta)
{
case '+' : return (a+b);
case '-' : return (a-b);
case '*' : return (a*b);
case '/' : return (a/b);
}
}
float EvaluateExpression()
{
char c,theta;
float a,b,m,n;
int k=0,i,j=0;
Stack1 OPTR;
Stack2 OPND;
InitStack1(&OPTR);
Push1(&OPTR,'#');
InitStack2(&OPND);
c=getchar();
while(c!='#'||GetTop1(OPTR)!='#'){
if(!In(c)){
if(c=='.'){
k=2;
j++;
}
else{
m=GetNumber(c);
if(k==1){
n=Pop2(&OPND);
m=n*10+m;
Push2(&OPND,m);
k=1;
}
else if(k==2){
n=Pop2(&OPND);
for(i=1;i<=j;i++)
m=m*0.1;
m=n+m;
Push2(&OPND,m);
k=2;
j++;
}
else{
Push2(&OPND,m);
k=1;
}
}
c=getchar();
}
else
switch(Precede(GetTop1(OPTR),c)){
case '<': Push1(&OPTR,c);k=0;j=0;c=getchar();break;
case '=': Pop1(&OPTR); c=getchar();break;
case '>':
theta=Pop1(&OPTR);b=Pop2(&OPND);a=Pop2(&OPND);Push2(&OPND,Operate(a,theta,b)) ;break;
}
}
return GetTop2(OPND);
}
int main( )
{
printf("请输入正确的表达式以'#'结尾:");
printf("表达式结果为:%f\n", EvaluateExpression());
return 0;
}
四、运行结果及分析
五、总结
这次课程设计让我有一个深刻的体会,那就是细节决定成败,编程最需要的是严谨,如何的严谨都不过分,往往检查了半天发现错误发生在某个括号,分号,引号,或者数据类型上。

就像我在写EvaluateExpression()函数时,忘了指针的地址符值不用加*号,这一点小小的错误也耽误了我几十分钟,所以说细节很重要。

设计4----前缀算术表达式转换及表达式计算
一、需求分析
1、问题描述:算术表达式与二叉树之间存在着对应关系,编写把以前缀形式输入的合法算术表达式转换为中缀表达式,再转换为后缀表达式,并求表达式的值
2、要求:①把前缀表达式转换为中缀表达式;
②输出中缀表达式;
③把中缀表达式转换为后缀表达式;
④利用栈结构实现后缀表达式的求值;
3、利用二叉树的遍历的顺序实现把以前缀形式输入的算术表达式转换为中缀和后缀表达式。

二、概要设计
1、主模块:
Void main(){
新建栈,树,并实现初始化;
接受命令;
处理命令;
}
2、栈的抽象类型数据定义:
ADT Stack{
数据对象:D={ ai|ai ∈ElemSet,i=1,2,...,n,n≥0}
数据关系:R1={ <ai-1, ai >| ai-1, ai∈D, i=2,...,n }
基本操作:
InitStack(SqStack *S)
Push(SqStack *S,SNodeEType e)
Pop(SqStack *S,SNodeEType *e)
StackEmpty(SqStack *S)
} ADT Stack
三、详细设计
主要程序:
typedef struct BiTNode
{
char data[10];
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
int Visit(char data[10])
{
printf("%s ",data);
return OK;
}
int InitBiTree(BiTree &T)
{
if(!(T=(BiTree)malloc(sizeof(BiTNode))))
return ERROR;
T->lchild=NULL;
T->rchild=NULL;
return OK;
}
void CreateBiTree(BiTree &T)
{
char ch[20];
scanf("%s",ch);
if
(strcmp(ch,"+")==0||strcmp(ch,"-")==0||strcmp(ch,"*")==0||strcmp(ch,"/")==0) {
strcpy(T->data,ch);
if (!(T->lchild=(BiTNode *)malloc(sizeof(BiTNode)))) exit(0);
CreateBiTree(T->lchild);
if (!(T->rchild=(BiTNode *)malloc(sizeof(BiTNode)))) exit(0);
CreateBiTree(T->rchild);
}
else
{
strcpy(T->data,ch);
T->lchild=NULL;
T->rchild=NULL;
}
}
int PreOrderTraverse(BiTree &T)
{
if(T)
{
Visit(T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
return OK;
}
else
return ERROR;
}
int InOrderTraverse(BiTree &T)
{
if(T)
{
InOrderTraverse(T->lchild);
Visit(T->data);
InOrderTraverse(T->rchild);
return OK;
}
else
return ERROR;
}
int PostOrderTraverse(BiTree &T)
{
if(T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
Visit(T->data);
Calculator(T->data,stack);//设计3表达式求值
return OK;
}
else
return ERROR;
}
int main()
{
InitStack(stack);
BiTree T;
InitBiTree(T);
printf("请输入前缀表达式:\n");
CreateBiTree(T);
printf("前缀表达式为:");
PreOrderTraverse(T);
printf("\n");
printf("中缀表达式为:");
InOrderTraverse(T);
printf("\n");
printf("后缀表达式为:");
PostOrderTraverse(T);
printf("\n");
printf("结果为:%g",(GetTop(stack)));
printf("\n");
}
四、运行结果及分析
五、总结
通过此次题目,对创建树,前序,中序,后序遍历树有了更深刻的理解,同时和栈联
系在一起,入栈出栈的操作需要更熟练。

同时,此次练习对考虑问题也有了进一步启示,首先要了解这个问题的基本要求,即输入、输出、完成从输入到输出的要求是什么;其次,从问题的要害入手,从前到后的解决问题的每个方面,即从输入开始入手,着重考虑如何从输入导出输出,在这个过程中,可确定所需的变量、数组、函数,然后确定处理过程算法,可得最后结论。

附:主要源代码
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<string.h>
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define INITSIZE 20
#define STACK_INCREMENT 10
typedef struct Stack
{
float *base;
float *top;
int stacksize;
}Stack;
Stack stack;
int InitStack(Stack &S)
{
S.base=(float *)malloc(INITSIZE*sizeof(float));
S.top=S.base;
S.stacksize=INITSIZE;
return OK;
}
float Pop(Stack &S)
{
if(S.top==S.base)
return ERROR;
return *--S.top;
}
int Push(Stack &S,float e)
{
if(S.top-S.base>=INITSIZE)
{
S.base=(float
*)realloc(S.base,(S.stacksize+STACK_INCREMENT)*sizeof(float));
S.top=S.base+S.stacksize;
S.stacksize+=STACK_INCREMENT;
}
*(S.top++)=e;
return OK;
}
float GetTop(Stack &S)
{
if(S.base==S.top)
return ERROR;
return *(S.top-1);
}
int StackEmpty(Stack &S)
{
if(S.base==S.top)
return OK;
else
return ERROR;
}
int Calculator(char data[10],Stack &S){
switch (*data)
{
case '+': *(S.top-2)=*(S.top-2)+(*(S.top-1));Pop(stack);break;
case '-': *(S.top-2)=*(S.top-2)-(*(S.top-1));Pop(stack);break;
case '*': *(S.top-2)=*(S.top-2)*(*(S.top-1));Pop(stack);break;
case '/': if(*(S.top-1)==0)
{
printf("\n出现除数为零的情况!\n");exit(0);
}
else
*(S.top-2)=*(S.top-2)/(*(S.top-1));Pop(stack);break;
default:
Push(stack,atof(data));
}
return OK;
}
设计5----最短路径及其长度
一、需求分析
1、自己构造一个连接山东省各城市的通讯网络图(假设链接任意两个城市的通讯光缆的长度)
2、要求:
①求该图的最小生成树。

②求任给两个顶点之间的最短路径和路径的长度。

二、概要设计
1、构造网的最小生成树,在两顶点之间之间存在多条路径,求两顶点之间路径长度最短的路径。

2、用图的数组存储,用普利姆算法求最小生成树,迪杰斯特拉算法求最短路径:
3、普利姆算法:假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,TV 是 WN 上最小生成树中顶点的集合,TE 是最小生成树中边的集合。

显然,在算法执行结束时,TV=V,而 TE 是 E 的一个子集。

在算法开始执行时,TE 为空集,TV 中只有一个顶点,因此,按普里姆算法构造最小生成树的过程为:在所有“其一个顶点已经落在生成树上,而另一个顶点尚未落在生成树上”的边中取一条权值为最小的边,逐条加在生成树上,直至生成树中含有 n-1条边为止。

三、详细设计
迪杰斯特拉算法:
Void Dijkstra(){
Int k;
for(int i=1;i<=n;i++)
dis[i] = map[1][i];
for(int i=1;i<n;i++){
Int tmin = maxint;
for(int j=1;j<=n;j++)
if( !used[j] && tmin > dis[j] ){
tmin = dis[j];
k = j;
}
used[k] = 1;
for(int j=1;j<=n;j++)
if( dis[k] + map[k][j] < dis[j] )
dis[j] = dis[k] + map[k][j];
}
printf("%d",dis[n]);
主要程序:
typedef struct ArcCell
{
VRType adj;
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; typedef enum GraphKind
{
DG,DN,UDG,UDN
}GraphKind;
typedef struct MGraph
{
VertexType vexs[MAX_VERTEX_NUM];
AdjMatrix arcs;
int vexnum, arcnum;
GraphKind kind;
} MGraph;
int LocateVex(MGraph *G,char v)
int i;
for (i=0;i<=G->vexnum;i++)
if(v==G->vexs[i]) return i;
return ERROR;
}
void CreateUDN(MGraph *G)
{
int i,j,k;
char v1,v2;
char x, y,z;
int w;
printf("\n请输入城市网的顶点数和路径数:");
scanf("%d,%d",&G->vexnum,&G->arcnum);//,&info);
getchar();
for (i=0; i<G->vexnum; i++)
{
G->vexs[i]=gets();
gets();
}
for (i=0 ; i< G->vexnum; ++i)
for(j=0 ; j< G->vexnum; ++j)
G->arcs[i][j].adj =INFINITY;
printf("\n请输入各城市的路径:\n");
for (k=0;k<G->arcnum;k++)
{
v1=getchar();
x=getchar();
v2=getchar();
y=getchar();
scanf("%d",&w);
z=getchar();
i=LocateVex(G,v1) ;
j=LocateVex(G,v2) ;
G->arcs[i][j].adj=w;
G->arcs[j][i]= G->arcs[i][j];
}
return G;
}
void MiniSpanTree_P(MGraph G,VertexType u)
{
int i,j,k;
Closedge closedge;
k = LocateVex ( &G, u );
for ( j=0; j<G.vexnum;++j )
if (j!=k)
{
closedge[j].adjvex=u;
closedge[j].lowcost=G.arcs[k][j].adj;
}
closedge[k].lowcost = 0;
for (i=0; i<G.vexnum; ++i)
{
k = minimum(closedge);
printf("%d %d \n",closedge[k].adjvex, G.vexs[k]);
closedge[k].lowcost = 0;
for (j=0; j<G.vexnum; ++j)
if (G.arcs[k][j].adj < closedge[j].lowcost)
{
closedge[j].adjvex=u;
closedge[j].lowcost=G.arcs[k][j].adj;
}
}
}
void ShortestPath_DIJ(MGraph G,int v0,PathMatrix &P,ShortPathTable &D) {
int i=0,j, v,w,min;
bool final[MAX_VERTEX_NUM];
for (v=0; v<G.vexnum; ++v)
{
final[v] = FALSE;
D[v] = G.arcs[v0][v].adj;
for (w=0; w<G.vexnum; ++w)
P[v][w] = FALSE;
if (D[v] < INFINITY)
{
P[v][v0] = TRUE;
P[v][v] = TRUE;
}
}
D[v0] = 0; final[v0] = TRUE;
for (i=1; i<G.vexnum; ++i)
{
min = INFINITY;
for (w=0; w<G.vexnum; ++w)
if (!final[w])
if (D[w]<min) { v = w; min = D[w];
}
final[v] = TRUE;
for (w=0; w<G.vexnum; ++w)
if (!final[w] && (min+G.arcs[v][w].adj<D[w]))
{
D[w] = min + G.arcs[v][w].adj;
for(j=0;j<G.vexnum;j++) P[w][j] = P[v][j];
P[w][w] = TRUE; // P[w] = P[v]+[w]
}
}
}
四、运行结果及分析
五、总结
通过编程我知道了想要写出好的程序,需要有扎实的基础,这样才会遇到一些基本算法时做的游刃有余。

在编程时,我们要有丰富的想象力,不拘泥于固定的思维方式,试试别人从没想过的方法。

丰富的想象力是建立在丰富的知识的基础上,所以我们要通过多个途径来帮助自己建立较丰富的知识结构。

在编程时,我们遇到了很多的困难,这就需要我们多与别人交流。

在编程时我们也看到了有良好的编程风格是十分重要的,至少在时间效率上就体现了这一点。

附:主要源代码
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define MAX_VERTEX_NUM 20
#define INFINITY 20000
#define ERROR 0
#define Status int
#define VRType int
#define VertexType string
int main()
{ int i,j,v0;
char v1[10],v2[10];
MGraph *G;
PathMatrix P;
ShortPathTable D;
G=(MGraph *)malloc(sizeof(MGraph));
if(!G) exit(0);
CreateUDN(G);
for (i=0 ; i< G->vexnum; ++i){
for(j=0 ; j< G->vexnum; ++j)
{if(G->arcs[i][j].adj==INFINITY) printf(" ∞"); else printf("%8d",G->arcs[i][j].adj);}
printf("\n");
}
MiniSpanTree_P(G,"");
printf("请输入你要查找的城市代号:");
gets(v1);gets(v2);
ShortestPath_DIJ(G,v0,&P,&D);
printf("最短路径为:%d\n",v1);
return 0;}
设计6----排序树中的查找问题
一、需求分析
1、问题描述:从小到大输出二叉排序树中所有关键字不小于x的数据元素。

2、若根结点的关键字值符合查找的要求,成功。

否则,若小于根结点的关键字值,递归查左子树。

若大于根结点的关键字值,递归查右子树。

若子树为空,查找不成功。

二、概要设计
1、二叉树的类型BiTree定义如下:
typedef struct {
KeyType key;
... ... // 其他数据域
} ElemType;
2、主要算法:
typedef struct BiTNode
{
ElemType data;
BiTNode *lchild,*rchild;
}BiTNode, *BiTree;
void OrderOut(BiTree t, KeyType x, void(*visit)(TElemType))
/* Output is to use visit(t->data); */
{ if(t->rchild) OrderOut(t->rchild,x,visit);
if(t->data.key>=x)
visit(t->data);
if(t->lchild)OrderOut(t->lchild,x,visit);
}
三、详细设计
二叉排序树的性质有:
①若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
②若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
③左、右子树也分别为二叉排序树;
主要程序:
typedef int KeyType; typedef char InfoType[10];
typedef struct node {
KeyType key; InfoType data;
struct node *lchild,*rchild; }BSTNode;
int InsertBST(BSTNode *&p,KeyType k) {
if (p==NULL) {
p=(BSTNode *)malloc(sizeof(BSTNode)); p->key=k;
p->lchild=p->rchild=NULL; return 1; }
else if (k==p->key) return 0;
else if (k<p->key)
return InsertBST(p->lchild,k);
N
else
return InsertBST(p->rchild,k); }
BSTNode *CreateBST(KeyType A[],int n) {
BSTNode *bt=NULL;
int i=0;
while (i<n)
{
InsertBST(bt,A[i]);
i++;
}
return bt;
}
int Visit(char data[10])
{
printf("%d ",data);
return OK;
}
int PreOrderTraverse(BSTNode* &T) {
if(T)
{
Visit(T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
return OK;
}
else
return ERROR;
}
int InOrderTraverse(BSTNode* &T)
{
if(T)
{
InOrderTraverse(T->lchild);
Visit(T->data);
InOrderTraverse(T->rchild);
return OK;
}
else
return ERROR;
}
void OrderOut(BSTNode* t, KeyType x)
{
if(t->rchild)
OrderOut(t->rchild,x,visit);
if(t->data.key>=x)
visit(t->data);
if(t->lchild)
OrderOut(t->lchild,x,visit);
}
四、运行结果及分析
五、总结
这次课程设计,加强了对二叉排序树的理解和应用,对树的遍历都有了更清晰的认识,用二叉排序树来查找关键数非常方便。

同时,促进了我的动手能力,二叉树的递归算法非常有用,可以把很复杂的问题变得更简单并且容易理解,所以在以后的编程过程中要学会好好利用递归的思想。

附:主要源代码
*#include <stdio.h>
#include <malloc.h>
int main()
{
BSTNode *T;
int data,x;
T=(BSTNode*)malloc(sizeof(BSTNode));
T->rchild=NULL;
T->lchild=CreatBST(T->lchild);
printf("请输入二叉排序树中的数据:");
while(scanf("%d",&data)!=EOF){
InsertBST(T,data);
}
PreOrderTraverse(T->lchild);
printf("请输入x的值:");
scanf("%d",&x);
OrderOut(T->lchild,x);
putchar('\n');
return 0;
}
设计7----排序问题
一、需求分析
1、问题描述:某学校一个年级有M个班的学生参加某门课程的考试,每个班最多有N个学生,利用堆排序方法实现基于文件的学生成绩排名。

2、要求:
①每个班的学生都是按学号顺序输入数据的,每个学生记录至少包含排列名次、学号、姓名、成绩四个域;
②输出每个学生在本年级的排名情况,具有相同成绩的名次相同;
二、概要设计
1、堆排序算法:
voidHeapSort(intarray[],intlength)
{
inttmp;
// 调整序列的前半部分元素,调整完之后第一个元素是序列的最大的元素
//length/2-1是第一个非叶节点,此处"/"为整除
for(inti =floor(length -1)/ 2 ; i >= 0; --i)
HeapAdjust(array, i, length);
// 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
for(inti = length - 1; i > 0; --i)
{
// 把第一个元素和当前的最后一个元素交换,
// 保证当前的最后一个位置的元素都是在现在的这个序列之中最大的
// Swap(&array[0], &array[i]);
tmp = array[i];
array[i] = array[0];
array[0] = tmp;
// 不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最
大值
HeapAdjust(array, 0, i);
}
}
2、堆采用顺序表存储表示;基于文件进行排名,要熟练使用文件操作。

将数据存入stu1.txt 中,运行后的结果存入同目录下的stu2.txt中
FILE *p1,*p2;
p1=fopen("stu1.txt","r");
p2=fopen("stu2.txt","w+");
if(p1==NULL)
{
printf("error\n");
exit(0);
}
if(p2==NULL)
{
printf("error\n");
exit(0);
}
printf("成绩统计已存入stu2.txt中\n");
fclose(p1);
fclose(p2);
return 0;
}
三、详细设计
主要程序:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define MAXSIZE 1000 typedef sruct
{
int key;
int class;
char name[9];
char id[13];
float score;
}student;
typedef struct{
student s[MAXSIZE+1];
int length;
}HeapType;
void HeapAdjust(HeapType &H, int s, int m) {
int j;
student rc;
rc = H.r[s];
for (j=2*s; j<=m; j*=2)
{
if (j<m && H.r[j].key<H.r[j+1].key) ++j;
if (rc.key >= H.r[j].key)
break;
H.r[s] = H.r[j]; s = j;
}
H.r[s] = rc;
}
void HeapSort(HeapType &H)
{
int i;
student temp;
for (i=H.length/2; i>0; --i)
HeapAdjust ( H, i, H.length );
for (i=H.length; i>1; --i)
{
temp=H.r[i];
H.r[i]=H.r[1];
H.r[1]=temp;
HeapAdjust(H, 1, i-1);
}
}
int main()
{
student s;
int i=0,j;
FILE *p1,*p2;
p1=fopen("stu1.txt","r");
p2=fopen("stu2.txt","w+");
if(p1==NULL)
{
printf("error\n");
exit(0);
}
if(p2==NULL)
{
printf("error\n");
exit(0);
}
while(read(H.r[i++],p1)!=EOF)
H.length++;
HeapSort(&H);
fprintf(p2,"学号姓名成绩名次\n");
for(j=0;j<i;j++)
{
fprintf(p2,"%s %s %-4d %-4d",H.r[j].id,H.r[j].name,H.r[j].score,H.r[j].key );
}
fclose(p1);
fclose(p2);
return 0;
}
四、运行结果及分析
五、总结
通过这次课程设计,我对文件的使用有了更深的理解。

堆排序是一种很有用的方法,简便而且易于理解,应该在以后的编程过程中多多使用。

同时在编程时,我们要有丰富的想象力,不拘泥于固定的思维方式,试试别人从没想过的方法。

丰富的想象力是建立在丰富的知识的基础上,所以我们要通过多个途径来帮助自己建立较丰富的知识结构。

在编程时,我们遇到了很多的困难,这就需要我们多与别人交流。

相关文档
最新文档