本科参与项目文档合集: 点击跳转~
一、 目的与要求
1. 目的
本课程设计是数据结构课程的实践环节。主要目的在于加强学生在课程中学习的相关算法和这些方法的具体应用,使学生进一步掌握在C语言中应用这些算法的能力。
2. 要求
综合运用数据结构中的相关算法,针对任务书中提出的相关设计要求,在指定的时间内提交相关的程序和源代码,并按照学校规定的格式提交书面课程设计报告。
二、 所选题目
1.通讯录的制作
要求每条信息至少包含姓名(name )城市(city)电话(tel)QQ号(qq),完成如下功能:
(1) 输入信息—— enter();
(2) 显示信息——display( );
(3) 查找以姓名作为关键字 ——search( );
(4) 删除信息——delete( );
(5) 存盘(将数据保存在文件中,此功能选做)——save ( );
完整代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
typedef int ElemType;
typedef struct person{
char name[10]; //姓名
char sex[10]; //性别
char city[10]; //所在城市
char phone[20]; //电话
}personal;
typedef struct node{
person data; //数据域
struct node * next; //指针域
}ListNode,* LinkList;
LinkList InitList();
LinkList Create(LinkList head);
void Display(LinkList head); //显示所有记录
void save(LinkList head); //保存到文件
void Search(LinkList head); //按要求查找
void Enter(LinkList head); //增加新的联系人
void Delete(LinkList head); //删除已有联系人
void Quit(); //退出菜单
void Menu(LinkList head); //菜单
LinkList InitList(){
LinkList head=(LinkList)malloc(sizeof(ListNode)); //创立头结点
head->next=NULL;
return head;
}
LinkList Create(LinkList head){
person LM; //接受文件数据
LinkList rear;
rear=head;
FILE *fp= fopen("通讯录.txt","r"); //只读
if(fp==NULL) {
printf("打开文件失败!");
return NULL;
}
//从一个流中执行格式化输入,fscanf遇到空格和换行时结束,注意空格时也结束。
//处理到文件尾 EOF:文件结束的标志
//尾插法将信息录入
while(fscanf(fp,"%s%s%s%s",LM.name,LM.sex,LM.city,LM.phone)!=EOF){
LinkList s=(LinkList)malloc(sizeof(ListNode));
s->data=LM;
s->next=NULL;
rear->next=s;
rear=s;
}
fclose(fp); //函数关闭打开的文件
return head;
}
void Display(LinkList head) {
LinkList p;
p = head->next;
//如果head指针为空说明链表为空
if (!p){
printf("\n链表为空!\n\n");
}
else{
printf("\n通信录:\n\n");
printf("姓名 性别 所在城市 电话 \n");
//循环将各个节点值输出
while (p){
printf("%s\t%s\t%s\t%s\t\t\n",p->data.name,p->data.sex,p->data.city,p->data.phone);//打印
p = p->next; //将指针指向下一个结点
}
printf("\n返回主菜单\n");
system("pause"); //页面停留
Menu(head);
}
}
void save(LinkList head){
LinkList rear;
person LM;
rear=head->next; //跳过头节点
FILE *fp;
int i;
/*只打开或建立一个二进制文件,只允许写数据*/
if((fp=fopen("通讯录.txt","wb"))==NULL){
printf("\n文件不存在!\n");
}
//处理到文件尾
while(rear){
LM=rear->data; //格式化信息输出到指定的文件流中
fprintf(fp,"%s\t%s\t%s\t%s\n",LM.name,LM.sex,LM.city,LM.phone);
rear=rear->next;
}
fclose(fp);
}
void Search(LinkList head){
int Loop=0;
char name[10];
printf("请输入要查询联系人的姓名 \b\b\b\b\b\b");
scanf("%s",name);
LinkList rear=head->next;
//处理到文件尾
while(rear){
//比较两字符串是否相等
if (strcmp(rear->data.name,name)==0){
printf("姓名 性别 所在城市 电话 \n");
printf("%s\t%s\t%s\t%s\n",rear->data.name,rear->data.sex,rear->data.city,rear->data.phone);
Loop=1;
}
rear=rear->next;
}
if(Loop==1){
printf("\n查询联系人成功!返回菜单\n");
system("pause");
Menu(head);
}
else{
int n;
printf("无此联系人!!!\n\n返回菜单:输入1) or 重新输入:输入2) \b\b\b");
scanf("%d",&n);
printf("\n");
switch(n){
case 1:system("cls");Menu(head);break;//先清屏,再去执行
case 2:system("cls");Search(head);break;
}
}
}
//新建联系人操作函数
void Enter(LinkList head){
char c;
person LM;
LinkList p=head;
printf("请输入新建联系人的信息\n/姓名 /性别 /所在城市 /电话号码:\n");
do{
scanf("%s",LM.name);
scanf("%s",LM.sex);
scanf("%s",LM.city);
scanf("%s",LM.phone);
LinkList s=(LinkList)malloc(sizeof(ListNode));
s->data=LM;
s->next=NULL;
//找到链表尾部
while(p->next){
p=p->next;
}
p->next=s;
save(head);
printf("是否继续添加 y/n\n");
scanf(" %c",&c);
}while(c=='y'||c=='Y');
printf("\n返回主菜单\n");
system("pause");
Menu(head);
}
//删除联系人操作
void Delete(LinkList head){
LinkList rear=head; //用来找要删除节点的前一节点
LinkList p=rear->next; //用来找要删除节点
char name[10];
int Loop=0,n;
printf("请输入要删除联系人的姓名: \b\b\b\b\b");
scanf("%s",name);
printf("\n");
while(p){
//比较两字符串是否相等
if(strcmp(p->data.name,name)==0){
rear->next=p->next;
free(p);
save(head);
Loop=1;
}
rear=p;
p=p->next;
}
if(Loop==1){
printf("\n删除联系人成功!返回菜单\n");
system("pause");
Menu(head);
}
else{
printf("无此联系人!!!\n\n返回菜单(1) or 重新输入(2) \b\b\b");
scanf("%d",&n);
printf("\n");
switch(n){
case 1:system("cls");Menu(head);break;
case 2:system("cls");Delete(head);break;
}
}
}
void Quit(){
puts("\n");
puts("\t感谢访问通信录管理系统!");
puts("\t欢迎下次再来!");
puts("\t制作人:安**");
puts("\t2021.1.3");
puts("\n ");
}
void Menu(LinkList head){
int n;
int choice=0;
do{
system("cls");
printf("\n");
printf(" ---通讯录---\n");
puts("\n");
printf(" 1、按姓名查询联系人信息\n");
puts("\n");
printf(" 2、新建联系人\n");
puts("\n");
printf(" 3、删除联系人信息\n");
puts("\n");
printf(" 4、显示所有联系人信息\n");
puts("\n");
printf(" 5、退出\n");
puts("\n");
printf(" 请选择服务种类(1-5) : \b\b");
scanf("%d",&n);
if(n<1||n>6){
system("cls");
printf("选择错误! 请重新选择!\n");
system("pause");
choice=1;
}
else{
break;
}
}while(choice==1);
switch(n)
{
case 1:system("cls");Search(head);break; //Search函数查询
case 2:system("cls");Enter(head);break; //Enter函数新建联系人
case 3:system("cls");Delete(head);break; //Delete删除联系人信息
case 4:system("cls");Display(head);break; //display显示所有信息
case 5:system("cls");Quit();break; //退出
}
}
int main(){
LinkList head=InitList();
head=Create(head);
printf("\n信息录入成功!");
system("pause");
Menu(head);
}
2、二叉树的基本运算
编写一个程序实现二叉树的基本功能:
1、用户输入字符串创建二叉树,A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))
2、实现:
- 实现二叉树的各种遍历。包括先序遍历、中序遍历、后序遍历的归和非递归算法、以及层次遍历。
- 要求能查找任一结点在某种遍历序列中的前驱和后继。
- 查找输出从根结点A出发到任意指定结点的路径。
- 查找任意一个节点为根的子树所有节点。
完整代码:
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
#define ElemType char
#define MaxSize 100
#define st_MaxSize 30
#define qu_MaxSize 30
/*关于结点的声明*/
typedef struct node //定义二叉树的结点类型BTNode
{
ElemType data;
struct node* lchild;
struct node* rchild;
int ltag,rtag;
}BTNode;
typedef struct //定义顺序栈的结点类型
{
BTNode* data[st_MaxSize]; //存放栈中的二叉结点元素
int top; //栈顶指针
}SqStack;
typedef struct //定义顺序队列的结点类型
{
BTNode* data[qu_MaxSize];
int front,rear;
} SqQueue;
/*关于顺序栈操作的声明*/
void InitStack(SqStack* &s) //初始化栈
{
s=(SqStack*)malloc(sizeof(SqStack)); //分配一个顺序栈空间,首地址存放在s中
s->top=-1; //栈顶指针置为-1
}
void DestroyStack(SqStack* &s) //销毁顺序栈
{
free(s);
}
bool StackEmpty(SqStack* s) //判断栈是否为空
{
return(s->top==-1);
}
bool Push(SqStack* &s,BTNode* e) //入栈
{
if(s->top==st_MaxSize-1)
return false;
s->data[++s->top]=e;
return true;
}
bool Pop(SqStack* &s,BTNode* &e) //出栈
{
if(s->top==-1)
return false;
e=s->data[s->top--];
return true;
}
bool GetTop(SqStack* s,BTNode* &e) //取栈顶元素
{
if(s->top==-1)
return false;
e=s->data[s->top];
return true;
}
/*关于环形队列操作的声明*/
void InitQueue(SqQueue* &q) //初始化环形队列
{
q=(SqQueue*)malloc(sizeof(SqQueue));
q->front=q->rear=0;
}
void DestroyQueue(SqQueue* &q) //销毁环形队列
{
free(q);
}
bool QueueEmpty(SqQueue* q) //判断环形队列是否为空
{
return (q->front==q->rear);
}
bool enQueue(SqQueue* &q,BTNode* &e) //入队操作
{
if((q->rear+1)%qu_MaxSize==q->front)
return false;
q->rear=(q->rear+1)%qu_MaxSize;
q->data[q->rear]=e;
return true;
}
bool deQueue(SqQueue* &q,BTNode* &e)
{
if(q->front==q->rear)
return false;
q->front=(q->front+1)%qu_MaxSize;
e=q->data[q->front];
return true;
}
/*关于二叉树操作的声明*/
void CreateBTree(BTNode* &b,char* str) //创建二叉树
{
BTNode* St[MaxSize];
BTNode* p; //用于创建结点,然后接到树上
int top=-1; //初始化栈顶指针
int k=0; //用于标明操作左孩子结点还是右孩子结点的flag
int j=0; //用于遍历字符串
char ch; //用于遍历给定字符串的字符参数
b=NULL; //先将根结点初始化为空结点
ch=str[j]; //指遍历参数指向开头,准备遍历
while(ch!='\0') //开始遍历字符串
{
switch(ch)
{
case '(': //遍历到左括号
top++;
St[top]=p; //结点入栈,作为子树的根结点
k=1; //k=1:准备创建左孩子结点
break;
case ')': //遍历到右括号
top--; //元素出栈
break;
case ',': //有逗号说明有右孩子结点不为空,准备创建右孩子结点
k=2;
break;
default:
p=(BTNode*)malloc(sizeof(BTNode)); //为p创建一个新的空结点
p->data=ch; //在新结点中存入数据
p->lchild=p->rchild=NULL; //将左右结点首先设为空结点
if(b==NULL) //若操作的是树的根结点
b=p;
else //若操作的不是树的根结点
{
switch(k) //判断标明操作左右孩子结点的flag
{
case 1: //k=1,新建的结点为0
St[top]->lchild=p;
break;
case 2:
St[top]->rchild=p;
break;
}
}
}
ch=str[++j]; //继续遍历str字符串
}
}
void RPreOrder(BTNode* b) //先序遍历递归输出
{
if(b!=NULL)
{
cout<<b->data; //输出根结点数据
RPreOrder(b->lchild); //递归遍历左树
RPreOrder(b->rchild); //递归遍历右树
}
}
void RInOrder(BTNode* b) //中序遍历递归输出
{
if(b!=NULL)
{
RInOrder(b->lchild); //递归遍历左树
cout<<b->data; //输出根结点的数据
RInOrder(b->rchild); //递归遍历右树
}
}
void RPostOrder(BTNode* b) //后序遍历递归输出
{
if(b!=NULL)
{
RPostOrder(b->lchild); //递归遍历左树
RPostOrder(b->rchild); //递归遍历右树
cout<<b->data; //输出根结点的数据
}
}
void UPreOrder(BTNode* b) //先序遍历非递归输出(第一种方法)
{
BTNode* p;
SqStack *st; //声明一个顺序栈
InitStack(st); //初始化栈st
p=b;
while(!StackEmpty(st)||p!=NULL) //当栈不为空,且未输出完所有的叶子节点
{
while(p!=NULL) //一路向左,把所有左下结点入栈
{
cout<<p->data; //输出根结点
Push(st,p); //然后将根结点的左孩子结点入栈
p=p->lchild;
}
if(!StackEmpty(st))
{
Pop(st,p); //出栈结点p,
p=p->rchild; //然后将右孩子结点入栈,进而循环遍历右子树
}
}
DestroyStack(st);
}
void UPreOrder2(BTNode* b) //先序遍历非递归输出(第二种方法)
{
BTNode* p;
SqStack *st; //声明一个顺序栈
InitStack(st); //初始化栈st
if(b!=NULL)
{
Push(st,b); //根结点入栈
while(!StackEmpty(st)) //栈不空时循环
{
Pop(st,p); //出栈结点p并访问
cout<<p->data;
/*先进后出,所以先入栈右孩子*/
if(p->rchild!=NULL)
Push(st,p->rchild); //有右孩子时将其入栈
if(p->lchild!=NULL)
Push(st,p->lchild); //有左孩子时将其出栈
}
}
DestroyStack(st); //销毁栈
}
void UInOrder(BTNode* b) //中序遍历非递归输出
{
BTNode* p;
SqStack *st; //声明一个顺序栈
InitStack(st); //初始化栈st
p=b;
while(!StackEmpty(st)||p!=NULL) //当栈不为空,且未输出完所有的叶子节点
{
while(p!=NULL) //一路向左,把所有左下结点入栈
{
Push(st,p);
p=p->lchild;
}
if(!StackEmpty(st)) //当栈不为空时
{
Pop(st,p); //出栈结点p
cout<<p->data; //输出p
/*至此,完成了最小子树的左孩子的输出和子根的输出,转而处理右子树*/
p=p->rchild; //转而处右子树
}
}
DestroyStack(st);
}
void UPostOrder(BTNode* b) //后序遍历非递归输出
{
BTNode* p;
BTNode* r;
bool flag;
SqStack* st; //定义一个顺序栈指针st
InitStack(st); //初始化栈
p=b;
do
{
while(p!=NULL) //一路向左,把所有左下结点入栈
{
Push(st,p);
p=p->lchild;
}
r=NULL; //r指向刚访问的结点,初始时为空
flag=true; //flag为真表示正在处理栈顶结点
while(!StackEmpty(st)&&flag) //当栈不为空且即将处理栈顶结点
{
GetTop(st,p); //取出当前的栈顶结点p
if(p->rchild==r) //若结点p的右孩子结点为空或为刚刚访问过的结点
{
cout<<p->data; //输出该根结点p
Pop(st,p);
r=p; //r指向刚刚访问过的结点
}
else
{
p=p->rchild; //转向处理右子树
flag=false; //表示现在不是在处理栈顶结点
}
}
}while(!StackEmpty(st));
DestroyStack(st); //销毁栈
}
void LevelOrder(BTNode* b) //层次遍历算法
{
BTNode* p;
SqQueue* qu;
InitQueue(qu);
enQueue(qu,b);
while(!QueueEmpty(qu))
{
deQueue(qu,p);
cout<<p->data;
if(p->lchild!=NULL)
enQueue(qu,p->lchild);
if(p->rchild!=NULL)
enQueue(qu,p->rchild);
}
}
BTNode* FindNode(BTNode* b,ElemType x) //查找二叉树b中值为x的结点
{
BTNode* p;
if(b==NULL)
return NULL; //若树或子树为空,直接返回NULL
else if(b->data==x)
return b; //若根结点或子根结点就是要找的结点,返回该(子)根结点
else
{
p=FindNode(b->lchild,x); //查找左树
if(p!=NULL)
return p; //若左树未搜索到,不一定没有,要转而搜索右树
else
return FindNode(b->rchild,x); //若右树未搜索到,那就是真的没有了,所以不需要判断NULL的情况了
}
}
BTNode* pre; //用于线索化二叉树的全局变量
void Thread(BTNode* &p) //将头结点为p的二叉树进行中序线索化
{
if(p!=NULL)
{
Thread(p->lchild); //将左子树线索化
if(p->lchild==NULL) //左孩子不存在时,进行前驱结点线索化
{
p->lchild=pre;
p->ltag=1; //用于标记线索
}
else
p->ltag=0;
if(pre->rchild==NULL)
{
pre->rchild=p;
pre->rtag=1;
}
else
pre->rtag=0;
pre=p;
Thread(p->rchild); //右子树线索化
}
}
BTNode* CreateThread(BTNode* b) //将二叉树b进行中序线索化
{
BTNode* node; //创建指向根结点b的指针root
node=(BTNode*)malloc(sizeof(BTNode));
node->ltag=0; //node有左孩子结点,ltag设为0
node->rtag=1; //node无右孩子结点,rtag设为1
node->rchild=b; //右孩子结点指向后继节点,即根结点b
if(b==NULL) //空二叉树时
node->lchild=node; //node的前驱结点就是自己
else
{
node->lchild=b;
pre=node; //pre是p的前驱结点,供加线索用
Thread(b); //中序遍历线索化二叉树
pre->rchild=node;
pre->rtag=1;
node->rchild=pre; //将头结点右线索化
}
return node;
}
BTNode* InPrenode(BTNode* p) //查找中序线索二叉树的前驱
{
BTNode* Pre;
Pre=p->lchild;
if(p->ltag!=1)
while(Pre->rtag==0)
Pre=Pre->rchild;
return (Pre);
}
BTNode* InPostnode(BTNode* p) //查找中序线索二叉树的后继
{
BTNode* Post;
Post=p->rchild;
if(p->rtag!=1)
while(Post->ltag==0)
Post=Post->lchild;
return(Post);
}
bool PathStack(BTNode* b,SqStack* &st,BTNode* x) //将从根结点到某结点的路线入栈
{
if(b==NULL)
return false;
Push(st,b); //将根结点入栈
if(b==x)
return true;
bool temp=false;
if(b->lchild!=NULL) //先查找左子树
temp=PathStack(b->lchild,st,x);
if(!temp&&b->rchild!=NULL) //左子树未找到且右子树不为空时,查找右子树
temp=PathStack(b->rchild,st,x);
if(!temp) //左右都找不到,栈顶元素出栈
{
BTNode* ab;
Pop(st,ab);
}
return temp;
}
void SearchPath(BTNode* b,BTNode* x) //倒叙进入,用另一个栈存 再输出。
{
SqStack* d;
InitStack(d);
PathStack(b,d,x);
SqStack* z;
InitStack(z);
BTNode* trans;
while(!StackEmpty(d))
{
Pop(d,trans);
Push(z,trans);
}
BTNode* out;
while(!StackEmpty(z))
{
Pop(z,out);
cout<<out->data;
}
}
int main()
{
BTNode* b;
char a[40]="A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))";
CreateBTree(b,a);
RInOrder(b); //中序递归正确顺序
cout<<endl<<endl;
BTNode* X=FindNode(b,'H'); //先找到值为 H 的结点
BTNode* head=CreateThread(b); //然后构建线索二叉树
BTNode* t = InPrenode(X); //查找值为 H 的结点的前驱
cout<<t->data<<endl;
t = InPostnode(X); //查找值为 H 的结点的后继
cout <<t->data;
return 0;
}
3、编写病人看病模拟程序
内容: 编写一个程序,反映病人到医院排队看医生的情况。在病人排队过程中主要重复下面两件事。
- 病人到达诊室,将病历本交给护士,排到等待队列中候诊。
- 护士从等待队列中取出下一位病人的病历,该病人进入诊室就诊。
要求模拟病人等待就诊这一过程。程序采用菜单方式,需要有排队、就诊、查看排队、不再排队,余下依次就诊、下班五个功能。
需求分析: 如题目所说,该设计需要有排队、就诊、查看排队、不再排队以及下班这五个功能,每个功能思路如下:
- 排队——输入排队病人的病历号,加入到病人排队队列中;
- 就诊——病人排队队列中最前面的病人就诊,并将其从队列中删除;
- 查看排队——从队首到队尾列出所有的排队病人的病历号;
- 不再排队,余下依次就诊——出队所有元素,从队首到队尾列出所有的排队病人的病历号;
- 下班——退出运行。
完整代码:
#include<bits/stdc++.h>
typedef struct DataNode //节点结构体
{
int data;
struct DataNode* next;
} DataNode;
typedef struct //链队结点结构体
{
DataNode* front;
DataNode* rear;
} QuNode;
void in (QuNode*&q) //入队,排队函数;
{
DataNode*p;
p=(DataNode*)malloc(sizeof(DataNode));
printf(" 请输入排队病人病历号:");
scanf("%d",&p->data);
p->next=NULL;
if(q->rear==NULL) //此时队中无数据
q->front=q->rear=p;
else
{
q->rear->next=p;
q->rear=p;
}
}
void out (QuNode*&q) //出队,就诊函数;
{
DataNode*t;
if(q->front==NULL)
{
printf(" 当前没有病人就诊!\n");
return ;
}
t=q->front;
printf(" 请病历号为%d的患者就诊\n",t->data);
if(q->front==q->rear) //此时队列中只有一个数据结点
q->front=q->rear=NULL;
else
q->front=q->front->next;
free(t);
}
void check(QuNode*&q) //依次出队,查看排队;
{
int num=1; //记录病人个数
DataNode*p=(DataNode*)malloc(sizeof(DataNode));
if(q->front==NULL)
{
printf(" 当前没有病人排队就诊\n");
return ;
}
for(p=q->front;p!=NULL;p=p->next)
{
printf(" 第%d位病人病历号:%d\n",num,p->data);
num++;
}
}
void all_out(QuNode*&q) //不再排队,输出所有排队的病历号;
{
DataNode*p=(DataNode*)malloc(sizeof(DataNode));
DataNode*s; //中间辅助参数结点
p=q->front;
while(p!=NULL)
{
s=p;
p=p->next;
printf(" 请病历号为%d的患者就诊\n",s->data);
free(s);
}
q->front=q->rear=NULL;
}
void menu()
{
printf(" \n");
printf(" 菜单 \n\n");
printf(" 输入1:病人开始排队 \n");
printf(" 输入2:开始就诊 \n");
printf(" 输入3:查看所有排队患者 \n");
printf(" 输入4:不再排队,余下依次就诊 \n");
printf(" 输入5:下班 \n\n");
}
int main()
{
menu(); //先输出选择菜单,让用户选择操作
int T=0,n; //辅助变量T,输入的选项序号n;
QuNode*q=(QuNode*)malloc(sizeof(QuNode));
q->front=q->rear=NULL;
while(true)
{
printf("请输入选项序号: ");
scanf("%d",&n);
switch(n)
{
case 1:
in(q);
break;
case 2:
out(q);
break;
case 3:
check(q);
break;
case 4:
all_out(q); //输入4后剩下所有患者就诊,并且结束程序,执行完4后继续执行5
case 5:
T=1;
break;
default:
printf("选项序号输入错误,请重新输入!\n");
}
if(T==1)
break;
}
printf("\n\t \n\n");
puts("\n");
puts("\t ");
puts("\t ");
puts("\t 程序结束!欢迎访问病人排队就诊小程序 ");
puts("\t ");
puts("\t ");
puts("\t 制作人:计算机19-1安** ");
puts("\t 日期:2021.1.3 ");
puts("\n ");
}
4、迷宫问题
功能要求:
1)用户可以定义迷宫的大小和入口位置。
2)输出从入口到出口的路径。
3)要求用3种以上算法实现
完整代码:
1. 使用递归实现
#include<iostream>
#include<cstdio>
#include<stdlib.h>
#include<bits/stdc++.h>
#define M 100
#define N 100
using namespace std;
int n=1;
const int MaxSize=100;
int mg[M+2][N+2];
/*={
{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,0,1,0,1},
{1,0,0,1,0,0,0,1,0,1},{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,0,1},{1,0,0,0,1,0,0,0,0,1},
{1,0,1,0,0,0,1,0,0,1},{1,0,1,1,1,0,1,1,0,1},
{1,1,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1}
};*/
typedef struct{
int i;
int j;
}Box;
typedef struct {///定义栈
Box data[MaxSize];
int length;
}PathType;
void mgpath2(int xi,int yi,int xe,int ye,PathType path){
int di,k,i,j;
if(xi==xe&&yi==ye){
path.data[path.length].i=xi;
path.data[path.length].j=yi;
path.length++;
printf("迷宫路径%d如下",n++);
for(k=0;k<path.length;k++){
printf("\t(%d,%d)",path.data[k].i,path.data[k].j);
}
printf("\n");
}
else{
if(mg[xi][yi]==0){
di=0;
while(di<4){
path.data[path.length].i=xi;
path.data[path.length].j=yi;
path.length++;
switch(di){
case 0:i=xi-1;j=yi;break;
case 1:i=xi;j=yi+1;break;
case 2:i=xi+1;j=yi;break;
case 3:i=xi;j=yi-1;break;
}
mg[xi][yi]=-1;
mgpath2(i,j,xe,ye,path);
mg[xi][yi]=0;
path.length--;
di++;
}
}
}
}
int main(){
PathType path;
path.length=0;
int q,w,e,r; //起点终点坐标
int a,b; //遍历变量
int mm,nn;
printf("请输入迷宫的行数:") ;
scanf("%d",&mm);
printf("\n请输入迷宫的列数:");
scanf("%d",&nn);
printf("\n请用空格隔开输入迷宫的行和列(0代表路1代表墙)\n");
for(a=1;a<=mm;a++){
for(b=1;b<=nn;b++){
scanf("%d",&mg[a][b]);
}
}
for(a=0;a<=mm+1;a++){ //加围墙
mg[a][0]=1;
mg[a][nn+1]=1;
}
for(b=0;b<=nn+1;b++){
mg[0][b]=1;
mg[mm+1][b]=1;
}
printf("所得迷宫如下");
printf("\n");
for(a=0;a<=mm+1;a++){ //输出迷宫
for(b=0;b<=nn+1;b++){
printf("%d ",mg[a][b]);
}
printf("\n");
}
printf("输入入口坐标\n");
scanf("%d%d",&q,&w);
printf("输入出口坐标\n");
scanf("%d%d",&e,&r);
mgpath2(q,w,e,r,path);
return 1;
}
2. 使用队列实现
#include<bits/stdc++.h>
const int MaxSize=100;
typedef struct{
int i,j; //方块的位置
int pre; //本路径中上一个方块在队列中的下标
}Box; //方块类型
typedef struct{
Box data[MaxSize];
int front,rear; //队头指针和队尾指针
}QuType; //顺序队类型
/*int M=8,N=8;
int mg[10][10]={{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,0,1},{1,0,0,0,1,0,0,0,0,1},{1,0,1,0,0,0,1,0,0,1},{1,0,1,1,1,0,1,1,0,1},
{1,1,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1} };*/
void InitQueue(QuType *&q){ //初始化队列
q=(QuType *)malloc(sizeof(QuType));
q->front=q->rear=-1;
}
void DestroyQueue(QuType *&q){ //摧毁队列
free(q);
}
bool QueueEmpty(QuType *q){ //判断队列是否为空
return (q->front==q->rear);
}
bool enQueue(QuType *&q,Box e){ //入队
if(q->rear==MaxSize-1)
return 0;
q->rear++;
q->data[q->rear]=e;
return 1;
}
bool deQueue(QuType *&q,Box &e){ //出队
if(q->front==q->rear)
return 0;
q->front++;
e=q->data[q->front];
return 1;
}
void print(QuType *qu,int front){ //从队列qu中输出一条迷宫路径
int k=front,j,ns=0;
printf("\n");
do{ //反向找到最短路径,将该路径上的方块的pre成员设置成-1
j=k;k=qu->data[k].pre;
qu->data[j].pre=-1;
}
while(k!=0);
printf("一条迷宫路径如下:\n");
k=0;
while(k<MaxSize){ //正向搜索到pre为-1的方块,即构成正向的路径
if(qu->data[k].pre==-1){
ns++;
printf("\t(%d,%d)",qu->data[k].i,qu->data[k].j);
if(ns%5==0) printf("\n"); //每输出五个方块后换行
}
k++;
}
printf("\n");
}
bool mgpath1(int xi,int yi,int xe,int ye){ //输出路径为:(xi,yi)->(xe,ye)
Box e;
int i,j,di,i1,j1;
int M=100,N=100;
int mg[M+2][N+2];
int a,b; //遍历变量
printf("请输入迷宫的行数:") ;
scanf("%d",&M);
printf("\n请输入迷宫的列数:");
scanf("%d",&N);
printf("\n请用空格隔开输入迷宫的行和列(0代表路1代表墙)");
for(a=1;a<=M;a++){
for(b=1;b<=N;b++){
scanf("%d",&mg[a][b]);
}
}
for(a=0;a<=M+1;a++){ //加围墙
mg[a][0]=1;
mg[a][N+1]=1;
}
for(b=0;b<=N+1;b++){
mg[0][b]=1;
mg[M+1][b]=1;
}
printf("所得迷宫如下");
printf("\n");
for(a=0;a<=M+1;a++){ //输出迷宫
for(b=0;b<=N+1;b++){
printf("%d ",mg[a][b]);
}
printf("\n");
}
printf("输入入口坐标\n");
scanf("%d%d",&xi,&yi);
printf("输入出口坐标\n");
scanf("%d%d",&xe,&ye);
QuType *qu; //定义顺序队指针qu
InitQueue(qu); //初始化队列
e.i=xi;e.j=yi;e.pre=-1;
enQueue(qu,e); //(xi,yi)进队
mg[xi][yi]=-1; //将其赋值为-1,以避免回过来重复搜索
while(!QueueEmpty(qu)){ //队不空循环
deQueue(qu,e); //出队方块e,由于不是环形队列 ,该出队元素仍在队列中
i=e.i;j=e.j;
if(i==xe&&j==ye){ //找到了出口,输出路径
print(qu,qu->front); //调用print函数输出路径
DestroyQueue(qu); //销毁队列
return 1; //找到一条路径时返回真
}
for(di=0;di<4;di++){ //循环扫描每个方位,把每个可走的方块插入到队列中
switch(di){
case 0:i1=i-1;j1=j;break;
case 1:i1=i;j1=j+1;break;
case 2:i1=i+1;j1=j;break;
case 3:i1=i;j1=j-1;break;
}
if(mg[i1][j1]==0){
e.i=i1;e.j=j1;
e.pre=qu->front; //指向路径中上一个方块的下标
enQueue(qu,e); //(i1,j1)方块进队
mg[i1][j1]=-1; //将其赋值-1,一面会过来重复搜索
}
}
}
DestroyQueue(qu); //销毁队列
return 0; //未找到任何路径时返回假
}
int main(){
int xi,yi,xe,ye;
mgpath1(xi,yi,xe,ye);
return 1;
}
3. 使用栈实现
#include<bits/stdc++.h>
using namespace std;
const int MaxSize=100;
typedef int ElemType;
typedef struct{
int i;
int j;
int di;
}Box;
typedef struct { //定义栈
Box data[MaxSize];
int top;
}StType;
/*int M=8,N=8;
int mg[10][10]={{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,0,0,1,1,0,0,1},
{1,0,1,1,1,0,0,0,0,1},{1,0,0,0,1,0,0,0,0,1},{1,0,1,0,0,0,1,0,0,1},{1,0,1,1,1,0,1,1,0,1},
{1,1,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1} };*/
void InitStack(StType *&s){ //初始化栈
s=(StType *)malloc(sizeof(StType));
s->top=-1;
}
void DestroyStack(StType *&s){ //销毁栈
free(s);
}
bool StackEmpty(StType *s){ //判断是否空
return(s->top==-1);
}
bool Push(StType *&s,Box e){ //进栈
if(s->top==MaxSize-1)
return false;
s->top++;
s->data[s->top]=e;
return true;
}
bool Pop(StType *&s,Box &e){ //出栈
if(s->top==-1)
return false;
e=s->data[s->top];
s->top--;
return true;
}
bool GetTop(StType *s,Box &e){ //取栈顶元素
if(s->top==-1)
return false;
e=s->data[s->top];
return true;
}
bool mgpath(int xi,int yi,int xe,int ye){
Box path[MaxSize],e;
int M=100,N=100;
int i,j,di,i1,j1,k;
bool find;
int mg[M+2][N+2];
int a,b;
printf("请输入迷宫的行数:") ;
scanf("%d",&M);
printf("\n请输入迷宫的列数:");
scanf("%d",&N);
printf("\n请用空格隔开输入迷宫的行和列(0代表路1代表墙)");
for(a=1;a<=M;a++){
for(b=1;b<=N;b++){
scanf("%d",&mg[a][b]);
}
}
for(a=0;a<=M+1;a++){ //加围墙
mg[a][0]=1;
mg[a][N+1]=1;
}
for(b=0;b<=N+1;b++){
mg[0][b]=1;
mg[M+1][b]=1;
}
printf("迷宫如下");
printf("\n");
for(a=0;a<=M+1;a++){ //输出迷宫
for(b=0;b<=N+1;b++){
printf("%d ",mg[a][b]);
}
printf("\n");
}
printf("输入入口坐标\n");
scanf("%d%d",&xi,&yi);
printf("输入出口坐标\n");
scanf("%d%d",&xe,&ye);
StType *st;
InitStack(st);
e.i=xi;e.j=yi;e.di=-1;
Push(st,e);
mg[xi][yi]=-1;
while(!StackEmpty(st))
{
GetTop(st,e);
i=e.i;j=e.j;di=e.di;
if (i==xe&&j==ye)
{
printf("一条迷宫路径如下:\n");
k=0;
while(!StackEmpty(st))
{
Pop(st,e);
path[k++]=e; //将e添加到path数组中
}
while (k>=1)
{
k--;
printf("\t(%d,%d)",path[k].i,path[k].j);
if((k+2)%5==0) printf("\n"); //每输出每5个方块后换一行
}
printf("\n");
DestroyStack(st);
return true; //输出一条迷宫路径后返回true
}
find=false;
while (di<4&&!find) //找相邻可走方块(i1,j1)
{
di++;
switch (di)
{
case 0:i1=i-1;j1=j;break; //上
case 1:i1=i;j1=j+1;break; //右
case 2:i1=i+1;j1=j;break; //下
case 3:i1=i;j1=j-1;break; //左
}
if(mg[i1][j1]==0) find=true;
}
if(find)
{
st->data[st->top].di=di; //修改原栈顶元素的di值
e.i=i1;e.j=j1,e.di=-1;
Push(st,e);
mg[i1][j1]=-1;
}
else
{
Pop(st,e); //四个方位都不能走且未找到出口-出栈
mg[e.i][e.j]=0;
}
}
DestroyStack(st);
return false;
}
int main()
{
int xi,yi,xe,ye;
mgpath(xi,yi,xe,ye);
return 1;
}
结语
道阻且长 行则将至
有任何不明白的地方欢迎私我~~
一切学习一起进步。