数据结构图及其应用实验报告+代码
数据结构实验报告(C语言)(强力推荐)
数据结构实验实验内容和目的:掌握几种基本的数据结构:集合、线性结构、树形结构等在求解实际问题中的应用,以及培养书写规范文档的技巧。
学习基本的查找和排序技术。
让我们在实际上机中具有编制相当规模的程序的能力。
养成一种良好的程序设计风格。
实验教材:数据结构题集(C语言版)清华大学出版社2007年实验项目:实验一、栈和循环队列㈠、实验内容:①栈掌握栈的特点(先进后出FILO)及基本操作,如入栈、出栈等,栈的顺序存储结构和链式存储结构,以便在实际问题背景下灵活应用。
本程序采用的是链栈结构,具有初始化一个栈、PUSH、POP、显示所有栈里的元素四个功能。
②循环队列掌握队列的特点(先进先出FIFO)及基本操作,如入队、出队等,学会循环队列的实现,以便在实际问题背景下灵活运用。
本程序具有初始化一个队列、入队、出队、显示队列的所有元素、队列长度五个功能。
㈡、实验代码①栈程序代码:#include <stdio.h>#include <malloc.h>#define Stack_Size 6#define ERROR 0#define OK 1typedef int SElemType;typedef struct SNode{SElemType data;struct SNode *next;}SNode,*LinkStack;int CreatTwo(LinkStack &head,int n){int i;SNode *p;head=(LinkStack)malloc(sizeof(SNode));head->next=NULL;printf("请输入数据(数字):\n");for(i=n;i>0;--i){p=(SNode *)malloc(sizeof(SNode));scanf("%d",&p->data);p->next=head->next;head->next=p;}return 1;}int menu_select(){int sn;for(;;){scanf("%d",&sn);if(sn<1||sn>6)printf("\n\t输入错误,请重新输入\n");elsebreak;}return sn;}int Push(LinkStack &top,SElemType e){SNode *q;q=(LinkStack)malloc(sizeof(SNode));if(!q){printf("溢出!\n");return(ERROR);}q->data=e;q->next=top->next;top->next=q;return(OK);}int Pop(LinkStack &top,SElemType &e){SNode *q;if(!top->next){printf("error!\n");return(ERROR);}e=top->next->data;q=top->next;top->next=q->next;free(q);return(OK);}void main(){ int e;LinkStack top;printf("1.初始化一个栈;\n2.PUSH;\n3.POP;\n4.显示所有栈里的元素;\n5.结束;\n");while(1){switch(menu_select()){case 1:if(CreatTwo(top,Stack_Size))printf("Success!\n");break; case 2:printf("Push:\n");scanf("%d",&e);if(Push(top,e))printf("Success!\n");break;case 3:if(Pop(top,e))printf("Success!\n");printf("%d\n",e);break;case 4:LinkStack p;printf("所有栈里的元素:\n");p=top;while(p->next){p=p->next;printf("%7d",p->data);}printf("\n");break;case 5:return;}}}运行结果:②循环队列程序代码:#include<stdlib.h>#include<stdio.h>#define OVERFLOW -1#define OK 1#define ERROR 0#define MAXSIZE 100typedef struct{int *elem;//队列存储空间int front;int rear;}SqQueue;//判断选择是否正确int menu_select(){int sn;for(;;){scanf("%d",&sn);if(sn<1||sn>6)printf("\n\t输入错误,请重新输入\n");elsebreak;}return sn;}//参数(传出)SqQueue &Q,循环队列(空)int InitQueue(SqQueue &Q){Q.elem=(int *)malloc(MAXSIZE*sizeof(int));if(!Q.elem)exit(OVERFLOW);Q.front=Q.rear=-1;for(int i=0;i<MAXSIZE;i++)Q.elem[i]=-1;return OK;}//返回Q的元素个数int QueueLength(SqQueue Q){return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;}//显示队列的元素void Display(SqQueue Q){for(int i=0;i<=QueueLength(Q);i++)if(Q.elem[i]!=-1)printf("%d ",Q.elem[i]);printf("\n");}//入队int EnQueue(SqQueue &Q,int e){Q.rear=(Q.rear+1)%MAXSIZE;if(Q.rear==Q.front)return ERROR;Q.elem[Q.rear]=e;return OK;}//出队int DeQueue(SqQueue &Q,int &e){if(Q.front==Q.rear)return ERROR;e=Q.elem[Q.front+1];Q.elem[Q.front+1]=-1;Q.front=(Q.front+1)%MAXSIZE;return OK;}void main(){SqQueue Q;InitQueue(Q);int elem,e;printf("请输入队列元素(以0结束):\n");scanf("%d",&elem);while(elem!=0){EnQueue(Q,elem);scanf("%d",&elem);}printf("队列为:\n");Display(Q);printf("1.初始化一个队列;\n2.入队;\n3.出队;\n4.显示队列的所有元素;\n5.队列长度:\n6.结束;\n");while(1){switch(menu_select()){case 1:printf("请输入队列元素(以0结束):\n");scanf("%d",&elem);while(elem!=0){EnQueue(Q,elem);scanf("%d",&elem);}printf("队列为:\n");Display(Q);fflush(stdin);break;case 2:scanf("%d",&elem);EnQueue(Q,elem);printf("队列为:\n");Display(Q);fflush(stdin);break;case 3:DeQueue(Q,elem);printf("队列为:\n");Display(Q);break;case 4:printf("\n队列的所有元素:\n");Display(Q);break;case 5:printf("%d\n",QueueLength(Q));break;case 6:return;}}}运行结果:实验二、数组㈠、实验内容:数组一般不做插入或删除操作,也就是说,一旦建立了数组,则结构中的数据元素个数和元素之间的关系就不再发生变动。
数据结构实验代码2
数据结构实验代码2第一点:数据结构实验代码2的背景与意义数据结构是计算机科学中至关重要的一个领域,它研究如何有效地存储、组织和管理数据,以及如何高效地执行相关操作。
在现代软件开发和计算机科学教育中,理解和掌握数据结构是不可或缺的。
数据结构实验代码2,作为一个具体的实践案例,旨在帮助学生深化对数据结构理论知识的理解,通过亲自动手编写和调试代码,增强对数据结构在实际应用中的认识。
实验代码2通常涉及到复杂的数据结构,比如图(Graph)、树(Tree)的高级算法实现,比如深度优先搜索(DFS)、广度优先搜索(BFS)、最短路径算法(如Dijkstra或Bellman-Ford算法)、最小生成树算法(如Prim或Kruskal算法)等。
通过对这些算法的实验实现,学生不仅能够掌握算法的工作原理,还能够理解其在解决实际问题时的效率和适用场景。
此外,数据结构实验代码2也是对学生编程能力和问题解决能力的一种锻炼。
在编写代码的过程中,学生需要考虑到算法的效率、空间复杂度,以及代码的可读性和可维护性。
这对于学生将来从事软件开发工作,具有重要的现实意义。
在当前的数字经济时代,数据结构的掌握程度直接关系到软件质量的高低和开发效率的快慢,因此,数据结构实验代码2在计算机科学与技术教育中占有举足轻重的地位。
第二点:数据结构实验代码2的关键技术与实现步骤数据结构实验代码2在技术实现上,涉及多个关键的步骤和考虑因素。
首先,学生需要选择合适的编程语言和开发环境,这对于代码的编写和调试都是非常重要的。
常见的编程语言如C/C++、Java、Python等,都具备实现复杂数据结构和算法的性能和灵活性。
接下来,是数据结构的具体实现。
这要求学生不仅要熟悉类和对象的概念,还需要能够设计出既符合数据结构特性,又能够有效实现算法逻辑的类和对象。
例如,在实现图的数据结构时,学生需要定义图的节点(Vertex)和边(Edge),并且提供添加节点、添加边、查找节点等基础操作。
数据结构上机实验源代码
数据结构上机实验源代码栈的应用十进制数转换为八进制数,逆序输出所输入的数实验代码://stack.h,头文件class stack{public:stack();bool empty()const;bool full()const;error_code gettop(elementtype &x)const;error_code push(const elementtype x);error_code pop();private:int count;elementtype data[maxlen];};stack::stack(){count=0;}bool stack::empty()const{return count==0;}bool stack::full()const{return count==maxlen;}error_code stack::gettop(elementtype &x)const{if(empty())return underflow;else{x=data[count-1];return success;}}error_code stack::push(const elementtype x){if(full())return overflow;data[count]=x;count++;return success;}error_code stack::pop(){if(empty())return underflow;count--;return success;}//主程序#include<iostream.h>enum error_code{overflow,underflow,success};typedef int elementtype;const int maxlen=20;#include"stack.h"void read_write() //逆序输出所输入的数{stack s;int i;int n,x;cout<<"please input num int n:";cin>>n;for(i=1;i<=n;i++){cout<<"please input a num:";cin>>x;s.push(x);}while(!s.empty()){s.gettop(x);cout<<x<<" ";s.pop();}cout<<endl;}void Dec_to_Ocx(int n) //十进制转换为八进制{stack s1;int mod,x;while(n!=0){mod=n%8;s1.push(mod);n=n/8;}cout<<"the ocx of the dec is:";while(!s1.empty()){s1.gettop(x);cout<<x;s1.pop();}cout<<endl;}void main(){int n;// read_write();cout<<"please input a dec:";cin>>n;Dec_to_Ocx(n);}队列的应用打印n行杨辉三角实验代码://queue.hclass queue{public:queue(){count=0;front=rear=0;}bool empty(){return count==0;}bool full(){return count==maxlen-1;}error_code get_front(elementtype &x){if(empty())return underflow;x=data[(front+1)%maxlen];return success;}error_code append(const elementtype x){if(full())return overflow;rear=(rear+1)%maxlen;data[rear]=x;count++;return success;}error_code serve(){if(empty())return underflow;front=(front+1)%maxlen;count--;return success;}private:int count;int front;int rear;int data[maxlen];};//主程序#include<iostream.h>enum error_code{overflow,underflow,success};typedef int elementtype;const int maxlen=20;#include"queue.h"void out_number(int n) //打印前n行的杨辉三角{int s1,s2;int i;int j;int k;queue q;for(i=1;i<=(n-1)*2;i++)cout<<" ";cout<<"1 "<<endl;q.append(1);for(i=2;i<=n;i++){s1=0;for(k=1;k<=(n-i)*2;k++)cout<<" ";for(j=1;j<=i-1;j++){q.get_front(s2);q.serve();cout<<s1+s2<<" ";q.append(s1+s2);s1=s2;}cout<<"1 "<<endl;q.append(1);}}void main(){int n;cout<<"please input n:";cin>>n;out_number(n);}单链表实验实验目的:实验目的(1)理解线性表的链式存储结构。
数据结构实验报告代码
《数据结构》实验报告实验序号:5 实验项目名称:链式栈五、分析与讨论对上机实践结果进行分析,上机的心得体会。
六、教师评语成绩签名:日期:附源程序清单:实验要求编程实现如下功能:(1)按照输入的栈中元素个数n和各元素值成立一个顺序栈,并输出栈中各元素值。
(2)将数据元素e入栈,并输出入栈后的顺序栈中各元素值。
(3)将顺序栈中的栈顶元素出栈,并输出出栈元素的值和出栈后顺序栈中各元素值。
2. 实验相关原理:栈是一种插入和删除操作都限制在表的一端进行的特殊线性表,它的操作具有“先进后出”的特性。
采用顺序存储结构的栈称为顺序栈。
栈的存储结构描述如下:#define MAXSIZE 100; /*顺序栈的最大长度*/typedef struct{ Selemtype base[MAXSIZE]; /*存储栈中数据元素的数组*/int top; /*top为栈顶指针,它指示栈顶元素的存储空间的下一个存储单元*/}Sqstack;【核心算法提示】1.顺序栈入栈操作的大体步骤:第一判断顺序栈是不是为满,若是满,则函数返回ERROR,不然将待入栈的数据元素寄存在top所指示的存储单元中,再使top后移一个存储单元位置,即将top值加1,最后函数返回OK。
2.顺序栈出栈操作的大体步骤:第一判断顺序栈是不是为空,若是空,则函数返回ERROR,不然将栈顶指针前移一个存储单元位置,即将top值减1,再将top所指示的栈顶元素用e返回其值,并使函数返回OK。
【核心算法描述】status Push(Sqstack &S,Selemtype e)/*将数据元素e压入到顺序栈S中,使其成为新的栈项元素*/{ if >=MAXSIZE) /*若是栈满,则函数返回ERROR*/return ERROR;[++]=e;/*将新元素e寄存在top所指示的存储单元中,并使top值加1*/return OK;}status Pop(Sqstack &S,Selemtype &e)/*将顺序栈S中的栈顶元素从栈中删除,并用e返回其值*/{ if ==0) /*若是栈空,则函数返回ERROR*/Return ERROR;e=[];/*将top值减1,并用e保留top所指示的栈顶元素值*/return OK;}3.源程序代码参考#define MAXSIZE 100typedef struct{ int base[MAXSIZE];int top; /*top指示存储栈顶元素的下一存储单元*/}Sqstack; /*顺序栈的类型概念*/Sqstack Push(Sqstack S,int e) /*顺序栈的入栈操作函数*/{ if >=MAXSIZE)printf("Stack is Overflow\n");else[++]=e;return S;}Sqstack Pop(Sqstack S,int *e) /*顺序栈的出栈操作函数*/{ if ==0)printf("Stack is Empty\n");else*e=[];return S;}void Stack_display(Sqstack S) /*顺序栈的输出函数*/{ int i;for(i=0; i<;i++) /*依次输出栈中各元素的值,栈顶元素在表的尾部*/printf("%4d", [i]);printf("\n");}main(){ Sqstack S;int i,j,n,x,e;printf("please input the length:");/*请求输入顺序栈中元素个数*/scanf("%d",&n);printf("please input the Value:\n ");/*请求输入顺序栈中各个元素值*/for(i=0;i<n;i++)scanf("%d",&[i]);=n;printf("the stack is:\n");Stack_display(S);printf("please input the insert node:");/*请求输入需要入栈的新元素*/scanf("%d",&x);S=Push(S,x);printf("the stack after push is:\n");/*提示输出入栈后栈中各个元素值*/Stack_display(S); /*挪用顺序栈的输出函数*/S=Pop(S,&e);printf("the pop value is:%d\n",e); /*输出出栈元素的值*/printf("the stack after pop is:\n");/*提示输出出栈后栈中各个元素值*/Stack_display(S); /*挪用顺序栈的输出函数*/}(1)按照输入的栈中元素个数和各元素值成立一个链栈,并输出链栈中各元素值, 观察输入的内容与输出的内容是不是一致,特别注意栈顶元素的位置。
数据结构实验报告图的应用
实验题目:图的应用一、实验目的和任务1 掌握图的邻接表和邻接矩阵存储;2 掌握图的拓扑排序算法;二、实验内容及原理1以下两项内容选做一项。
2 请按照书中介绍的拓扑排序算法,完成P303页第5题。
3 给定某一个图,完成其深度优先搜索遍历和广度优先搜索遍历,每种遍历都必须在邻接矩阵和邻接表中完成。
四、实验数据及程序代码#include <iostream.h>#include <stdlib.h>#include <strstrea.h>#include <string.h>#include <stdio.h>const int MaxVertexNum=10;typedef int WeightType;struct edgenode{int adjvex;WeightType weight;edgenode*next;};typedef edgenode *adjlist[MaxVertexNum];void InitAdjoin(adjlist GL)//初始化{for(int i=0;i<MaxVertexNum;i++)GL[i]=NULL;}void CreatAdjoin(adjlist GL,int n,char*s,int k1,int k2)//生成邻接表{istrstream sin(s);char c1,c2,c3;WeightType w;edgenode*p;sin>>c1;if(k2==0){do{sin>>c1>>i>>c2>>j>>c3;p=new edgenode;p->adjvex=j;p->weight=1;p->next=GL[i];GL[i]=p;if(k1==0){p=new edgenode;p->adjvex=i;p->weight=1;p->next=GL[j];GL[j]=p;}sin>>c1;}while(c1==',');}else{do{sin>>c1>>i>>c2>>j>>c3>>w;p=new edgenode;p->adjvex=j;p->weight=w;p->next=GL[i];GL[i]=p;if(k1==0){p=new edgenode;p->adjvex=i;p->weight=w;p->next=GL[j];GL[j]=p;}sin>>c1;}while(c1==',');}}void PrintAdjion(adjlist GL, int n,int k1, int k2) {edgenode*p;cout<<"V={";for(i=0; i<n-1; i++) cout<<i<<',';cout<<n-1<<'}'<<endl;cout<<"E={";for(i=0;i<n;i++){if(k2==0){p=GL[i];while(p){j=p->adjvex;if(k1==0){if(i<j) cout<<'('<<i<<','<<j<<')'<<',';}elsecout<<'<'<<i<<","<<j<<'>'<<',';p=p->next;}}else{p=GL[i];while(p){j=p->adjvex;if(k1==0){if(i<j) cout<<'('<<i<<','<<j<<')'<<p->weight<<',';}elsecout<<'<'<<i<<','<<j<<'>'<<p->weight<<',';p=p->next;}}}cout<<'}'<<endl;}void Toposort(adjlist GL , int n){int i,j,k,top,m=0;edgenode*p;int*d=new int[n];for(i=0;i<n;i++) d[i]=0;for(i=0;i<n;i++){p=GL[i];while(p!=NULL){j=p->adjvex;d[i]++;p=p->next;//cout<<j;}}top=-1;for(i=0;i<n;i++)if(d[i]==0){d[i]=top; top=i;}while(top!=-1){j=top;top=d[top];cout<<j<<' ';m++;p=GL[j];while(p!=NULL){k=p->adjvex;d[k]--;if(d[k]==0){d[k]=top;top=k;}p=p->next;}}cout<<endl;cout<<top<<endl;cout<<m<<endl;cout<<n<<endl;if(m<n) cout<<"The network has a cycle!"<<endl;delete []d;}void main(){int n,k1,k2;cout<<"输入待处理图的顶点数:";cin>>n;cout<<"输入图的有无向和有无权选择(0为无,非0为有):";cin>>k1>>k2;adjlist gl;InitAdjoin(gl);cout<<"输入图的边集:";FILE *p;p=fopen("d:\\1.txt","r+");char *a=new char[100];while (!feof(p)){fscanf(p,"%s ",a);cout<<a;}cout<<endl;//cin>>a;CreatAdjoin(gl,n,a,k1,k2);Toposort(gl,n);}五、实验数据分析及处理六、实验结论与感悟(或讨论)图的邻接矩阵,邻接表和边集数组表示各有利弊,具体运用时,要根据图的稠密和稀疏程度以及算法的要求进行选择。
数据结构实验报告图
数据结构实验报告图数据结构实验报告图问题描述:;四则运算表达式求值,将四则运算表达式用中缀表达式;一、需求分析:;1、本程序是利用二叉树后序遍历来实现表达式的转换;2、输入输出格式:;输入格式:在字符界面上输入一个中缀表达式,回车表;请输入表达式:;输入一个中缀表达式;输出格式:如果该中缀表达式正确,那么在字符界面上;式,其中后缀表达式中两相邻操作数之间利用空格隔开;果不正确,在字符界面上输出问题描述:四则运算表达式求值,将四则运算表达式用中缀表达式,然后转换为后缀表达式,并计算结果。
一、需求分析:1、本程序是利用二叉树后序遍历来实现表达式的转换,同时可以使用实验三的结果来求解后缀表达式的值。
2、输入输出格式:输入格式:在字符界面上输入一个中缀表达式,回车表示结束。
请输入表达式:输入一个中缀表达式输出格式:如果该中缀表达式正确,那么在字符界面上输出其后缀表达式,其中后缀表达式中两相邻操作数之间利用空格隔开;如果不正确,在字符界面上输出表达式错误提示。
逆波兰表达式为:3、测试用例输入:21+23*(12-6)输出:21 23 12 6 -*+ 输出逆波兰表达式运算结果为:输出运算后的结果二、概要设计:抽象数据类型二叉树类BiTree算法的基本思想根据题目要求,利用栈计算,和二叉树存储,来计算表达式该算法的基本思想是:先利用栈进行计算,然后用二叉树进行存储,和实验三算法一样来计算逆波兰表达式的值程序的流程程序由三个模块组成:(1) 输入模块:输入一个运算式(2) 计算模块:利用栈进行表达式的计算,二叉树来存储。
(3 ) 输出模块:屏幕上显示出后缀表达式和运算结果。
三、详细设计物理数据类型程序含有两个类,其中栈不再赘述,另一个类为二叉树class BiTree包含私有成员struct BiTreeNode,根节点BiTreeNode *T;索引index; int number_of_point 优先级比较函数compare(char a,char b);生成树的函数void InorderCreate(BiTreeNode *&T,char str,int start,int end);判断数字函数bool IsNumber(char a);求值函数double Operate(BiTreeNode *T);还有显示后缀表达式的函数void display(BiTreeNode *T) ;而公有成员函数则是对私有函数的重载,为方便使用,因为函数中普遍使用了递归的算法。
《数据结构》实验指导书(源代码)
实验一线性表的链式存储结构一、实验目的:1.掌握线性表的链式存储结构。
2.熟练地利用链式存储结构实现线性表的基本操作。
3.能熟练地掌握链式存储结构中算法的实现。
二、实验内容:1.用头插法或尾插法建立带头结点的单链表。
2.实现单链表上的插入、删除、查找、修改、计数、输出等基本操作。
三、实验要求:1. 根据实验内容编写程序,上机调试、得出正确的运行程序。
2. 写出实验报告(包括源程序和运行结果)。
四、实验学时:2学时五、实验步骤:1.进入编程环境,建立一新文件;2. 参考以下相关内容,编写程序,观察并分析输出结果。
①定义单链表的数据类型,然后将头插法和尾插法、插入、删除、查找、修改、计数、输出等基本操作都定义成子函数的形式,最后在主函数中调用它,并将每一种操作前后的结果输出,以查看每一种操作的效果。
②部分参考程序//单链表的建立(头插法),插入,删除,查找、修改、计数、输出#include<iostream.h>#define elemtype intstruct link{ elemtype data;//元素类型link *next; //指针类型,存放下一个元素地址};//头插法建立带头结点的单链表link *hcreat(){ link s,p;elemtype i;cout<<”输入多个结点数值(用空格分隔),为0时算法结束”;cin>>i;p=new link;p->next=NULL;while(i) //当输入的数据不为0时,循环建单链表{s=new link;s->data=i;s->next=p->next;p->next=s;cin>>i; }return p;}//输出单链表void print(1ink *head){1ink *p;p=head->next;while(p->next!=NULL){cout<<p->data<<”->”; //输出表中非最后一个元素p=p->next;}cout<<p->data; //输出表中最后一个元素cout<<endl;}∥在单链表head中查找值为x的结点Link *Locate(1ink *head,elemtype x){Link *p;p=head->next;while((p!=NULL)&&(p->data!=x))p=p->next;return p; }//在head为头指针的单链表中,删除值为x的结点void deletel(1ink *head,elemtype x){1ink *p, *q;q=head;p=head->next;while((p!=NULL)&&(p->data!=x)){q=p;p=p->next;}If(p==NULL) cout<<“要删除的结点不存在”;elseq->next=p ->next;delete(p);}}//在头指针head所指的单链表中,在值为x的结点之后插入值为y的结点void insert(1ink *head,elemtype x,elemtype y){ link *p, *s;s=new link;s->data=y;if(head->next==NULL) //链表为空{head->next=s;s->next=NULL:}p=Locate(head,x);//调用查找算法‘if(p==NULL)cout<<”插入位置非法”:else(s->next=p->next;p->next=s;}}//将单链表p中所有值为x的元素修改成y void change(1ink *p,elemtype x,elemtype y) {link *q;q=p->next;while(q!=NULL){ if(q->data==x) q->data=y;q=q->next;}}void count(1ink *h) //统计单链表中结点个数{1ink *p;int n=0;p=h->next;while(p!=NULL){n++;p=p->next;}return n;}void main(){ int n;elemtype x,y;link *p, *q;p=hcreat(); //头插法建立链表print(p); //输出刚建立的单链表cout<<”请输入要删除的元素”;cin>>y;deletel(p,y);print(p); //输出删除后的结果cout<<”请输入插入位置的元素值(将待插元素插入到它的后面)”; cin>>x;cout<<”请输入待插元素值”;cin>>y;insert(p,x,y);print(p); //输出插入后的结果cout<<”请输入要修改前、后的元素值”;cin>>x>>y;change(p,x,y);print(p);cout<<”请输入要查找的元素值”;cin>>x;q=Locate(p,x);if(q==NULL)cout<<x<<”不在表中,找不到!”<<endl;else cout<<x<<”在表中,已找到!”<<endl;n=count(p);cout<<”链表中结点个数为:”<<n<<endl:}//单链表的建立(尾插法)、插入、删除、查找、修改、计数、输出#include<iostream.h>#define elemtype intstruct link{ elemtype data;//元素类型link *next;//指针类型,存放下-个元素地址};//尾插法建立带头结点的单链表link *rcreat(){link *s, *p, *r;elemtype i;cout<<”输入多个结点数值(用空格分隔),为0时算法结束”; cin>>i;p=r=new link;p->next=NULL;while(i){s=new link;s->data=i;r->next=s;r=s;cin>>i; }r->next=NULL;return p;}//输出单链表void print(1ink *head){link *p;p=head->next;while(p->next!=NULL){cout<<p->data<<"->”; //输出表中非最后一个元素p=p->next;)cout<<p->data; //输出表中最后一个元素cout<<endl;}link *Locate(1ink *head,int x) ∥在单链表中查找第x个结点 {link *p;p=head;int j=0;while((p!=NULL)&&(j<x)){p=p->next; j++;}return p;}void delete I(1ink *head,elemtype x)//在head为头指针的单链表中,删除值为x的结点{link *p, *q;q=head;p=head->next;while((p!=NULL)&&(p->data!=x)){q=p;p=p->next;)if(p==NULL)cout<<”要删除的结点不存在“;else{q->next=p->next;delete(p);} }void insert(1ink *head,int x,elemtype y)//在头指针head所指单链表中,在第x个结点之后插入值为y的结点{link *p, *s;s=new link;s->data=y;if(head->next==NULL)//链表为空{head->next=s;s->next=NULL:}p=Locate(head,x); //调用查找算法if(p==NULL)cout<<”插入位置非法”;else{s->next=p->next;p->next=s;}}void change(1ink *p,elemtype x,elemtype y){∥将单链表P中所有值为x的元素改成值为ylink *q;q=p->next;while(q!=NULL){if(q->data==x)q->data=y;q=q->next;}}void count(1ink *h) //统计单链表中结点个数(1ink *p;int n=0;p=h->next;while(p!=NULL){n++;p=p->next;}retum n;}void main(){ int n;link p,q;p=rcreat();//尾插法建立链表print(p); //输出刚建立的单链表cout<<”请输入要删除的元素”;cin>>y;deletel(p,y);print(p); //输出删除后的结果cout<<”请输入插入位置”;cin>>x;cout<<”请输入待插元素值”;cin>>y;insert(p,x,y);print(p); //输出插入后的结果cout<<”请输入修改前、后的元素值”;cin>>x>>y;change(p,x,y);print(p);cout<<“请输入要查找的元素值”;cin>>x;q=Locate(p ,x);if(q==NULL)cout<<x<<”不在表中,找不到!”<<endl;else cout<<x<<”在表中,已找到!”<<endl;n=count(p);cout<<”链表中结点个数为:”<<n<endl;}六、选作实验试设计一元多项式相加(链式存储)的加法运算。
数据结构实验—图实验报告
数据结构实验报告目的要求1.掌握图的储藏思想及其储藏实现。
2.掌握图的深度、广度优先遍历算法思想及其程序实现。
3.掌握图的常有应用算法的思想及其程序实现。
实验内容1.键盘输入数据,建立一个有向图的毗邻表。
2.输出该毗邻表。
3.在有向图的毗邻表的基础上计算各极点的度,并输出。
4.以有向图的毗邻表为基础实现输出它的拓扑排序序列。
5.采用毗邻表储藏实现无向图的深度优先递归遍历。
6.采用毗邻表储藏实现无向图的广度优先遍历。
7.在主函数中设计一个简单的菜单,分别调试上述算法。
源程序:主程序的头文件:队列#include <stdio.h>#include <stdlib.h>#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define OVERFLOW -2typedef int QElemType;typedef struct QNode{//队的操作QElemType data;struct QNode *next;}QNode,*QueuePtr;typedef struct {QueuePtr front;QueuePtr rear;}LinkQueue;void InitQueue(LinkQueue &Q){//初始化队列Q.front =Q.rear =(QueuePtr)malloc(sizeof(QNode));if(!Q.front) exit(OVERFLOW);//储藏分配失败Q.front ->next =NULL;}int EnQueue(LinkQueue &Q,QElemType e) //插入元素 e 为 Q 的新的队尾元素{QueuePtr p;p=(QueuePtr)malloc(sizeof(QNode));if(!p) exit(OVERFLOW);p->data=e;p->next=NULL;Q.rear->next=p;Q.rear =p;return OK;}int DeQueue(LinkQueue &Q,QElemType &e) //删除 Q 的队头元素,用 e 返回其值{ if(Q.front ==Q.rear ) return ERROR;QueuePtr p;p=Q.front ->next;e=p->data;Q.front->next=p->next ;if(Q.rear==p) Q.rear =Q.front ;free(p);return OK;}主程序:#include <stdio.h>#include<stdlib.h>#include"duilie.h"#define TRUE 1#define FALSE 0#define Status int#define MAX_VERTEX_NUM 8/* 极点最大个数*/#define VertexType char /* 极点元素种类*/enum BOOlean {False,True};BOOlean visited[MAX_VERTEX_NUM];//全局变量——接见标志数组typedef struct ArcNode{int adjvex;struct ArcNode *nextarc;int weight; /* 边的权 */}ArcNode;/* 表结点 */typedef struct VNode{ int degree,indegree;/* 极点的度,入度*/VertexType data;ArcNode *firstarc;}VNode/* 头结点 */,AdjList[MAX_VERTEX_NUM];typedef struct{AdjList vertices;int vexnum,arcnum;/* 极点的本质数,边的本质数*/}ALGraph;//建立图的毗邻表void creat_link(ALGraph *G){int i,j; ArcNode*s;printf(" 请依次输入极点数、边数:");scanf("%d%d",&G->vexnum,&G->arcnum);for (i=0;i<G->vexnum;i++){G->vertices[i].data='A'+i; G->vertices[i].firstarc=NULL;}for (i=0;i<G->vexnum;){ printf(" 请输入极点的数组坐标 (若退出,请输入 -1) : ");scanf("%d",&i);if(i==-1) break;printf(" 请输入极点所指向下一个极点的数组坐标:");scanf("%d",&j);s=(ArcNode *)malloc(sizeof(ArcNode));s->adjvex=j;s->nextarc=G->vertices[i].firstarc;G->vertices[i].firstarc=s;}}//输出毗邻表void visit(ALGraph G){int i; ArcNode *p;printf("%4s%6s%18s\n","NO","data","adjvexs of arcs");for (i=0;i<G.vexnum;i++){printf("%4d%5c",i,G.vertices[i].data);for(p=G.vertices[i].firstarc;p;p=p->nextarc)printf("%3d",p->adjvex);printf("\n");}}//计算各极点的度及入度void cacu(ALGraph *G){ArcNode *p;int i;for (i=0;i<G->vexnum;i++){G->vertices[i].degree=0;G->vertices[i].indegree=0;}//度与初度初始化为零for (i=0;i<G->vexnum;i++)for(p=G->vertices[i].firstarc;p;p=p->nextarc){G->vertices[i].degree++;G->vertices[p->adjvex].degree++;G->vertices[p->adjvex].indegree++;}}void print_degree(ALGraph G){int i;printf("\n Nom data degree indegree\n");for (i=0;i<G.vexnum;i++)printf("\n%4d%5c%7d%8d",i,G.vertices[i].data,G.vertices[i].degree,G.vertices[i].indegree);printf("\n");}//拓扑排序Status TopologiSort(ALGraph G){int i,count,top=0,stack[50];ArcNode *p;cacu(&G);print_degree(G);printf("\nTopologiSort is \n");for(i=0;i<G.vexnum;i++)if(!G.vertices[i].indegree) stack[top++]=i;count=0;while(top!=0){i=stack[--top];if (count==0) printf("%c",G.vertices[i].data);else printf("-->%c",G .vertices[i].data);count++;for(p=G.vertices[i].firstarc;p;p=p->nextarc)if (!--G.vertices[p->adjvex].indegree)stack[top++]=p->adjvex;}if (count<G.vexnum)return(FALSE); else return(TRUE);}//在图 G 中搜寻第v 个极点的第一个毗邻极点int FirstAdjVex(ALGraph G ,int v){if(!G.vertices[v].firstarc) return 0;else return(G.vertices[v].firstarc->adjvex);}//在图 G 中搜寻第v 个极点的有关于u 的下一个毗邻极点int NextAdjVex(ALGraph G,int v,int u){ArcNode *p;p=G.vertices[v].firstarc;while(p->adjvex!=u) p=p->nextarc; //在极点v的弧链中找到极点u if(p->nextarc==NULL) return 0;// 若已经是最后一个极点,返回0else return(p->nextarc->adjvex);// 返回下一个毗邻极点的序号}//采用毗邻表储藏实现无向图的深度优先递归遍历void DFS(ALGraph G ,int i){int w;visited[i]=True;// 接见第 i 个极点printf("%d->",i);for(w=FirstAdjVex(G ,i);w;w=NextAdjVex(G,i,w))if(!visited[w]) DFS(G ,w); // 对还没有接见的毗邻极点w 调用 DFS}void DFSTraverse(ALGraph G){int i;printf("DFSTraverse:");for(i=0;i<G .vexnum;i++) visited[i]=False; //接见标志数组初始化for(i=0;i<G .vexnum;i++)if(!visited[i]) DFS(G ,i); // 对还没有接见的极点调用DFS}//按广度优先非递归的遍历图G,使用辅助队列Q 和接见标志数组visited void BFSTraverse(ALGraph G){int i,u,w;LinkQueue Q;printf("BFSTreverse:");for(i=0;i<G .vexnum;i++)visited[i]=False; // 接见标志数组初始化InitQueue(Q); //初始化队列for(i=0;i<G .vexnum;i++)if(!visited[i]){visited[i]=True;//接见极点iprintf("%d->",i);EnQueue(Q,i);// 将序号 i 入队列while(!(Q.front ==Q.rear)) //若队列不空,连续{DeQueue(Q,u);//将队头元素出队列并置为ufor(w=FirstAdjVex(G ,u);w;w=NextAdjVex(G ,u,w))if(!visited[w])//对 u 的还没有接见的毗邻极点w 进行接见并入队列{ visited[w]=True;printf("%d->",w);EnQueue(Q,w);}}}}void main(){ALGraph G;int select;printf("图的有关操作实验\n ");do{printf("\n1 创办一个有向图的毗邻表 2 输出该毗邻表\n");printf("3. 输出该有向图的度和入度 4.输出该有向图拓扑排序序列\n");printf("5. 创办一个无向图的毗邻表 6.深度优先递归遍历该无向图\n");printf("7. 广度优先遍历该无向图0.退出\n");printf(" 请输入选择:");scanf("%d",&select);switch(select){case 1:printf("\n 创办一个有向图的毗邻表:\n");creat_link(&G);break;case 2:printf("\n 输出该毗邻表:\n");visit(G);break;case 3:printf("\n 输出该有向图的度和入度:\n");cacu(&G);print_degree(G);break;case 4:printf("\n 输出该有向图拓扑排序序列:\n");if(!TopologiSort(G))printf("Toposort is not success!");break;case 5:printf("\n 创办一个无向图的毗邻表: \n");creat_link(&G);break;case 6:printf("\n深度优先递归遍历该无向图: \n");DFSTraverse(G);break;case 7:printf("\n 广度优先遍历该无向图:\n");BFSTraverse(G);break;case 0:break;default:printf(" 输入选项错误!重新输入!\n");}}while(select);}运行结果截图:1.主菜单界面:2.创办一个有向图的领接表3.输出该毗邻表4.在有向图的毗邻表的基础上计算各极点的度,并输出。
数据结构实验代码汇总
destptr->link = new LinkNode<T>(srcptr->link->data);
if(destptr->link == NULL) {
cerr << "存储分配失败!" << endl;
exit(1);
}
destptr = destptr->link;
srcptr = srcptr->link; } destptr->link = NULL; return *this; } }; #include "List.cpp" #endif
first = new LinkNode<T>; if(first == NULL) {
cerr << "存储分配失败!" << endl; exit(1); } } template <class T> List<T>::List(const T x) { first = new LinkNode<T>(x); if(first == NULL) { cerr << "存储分配失败!" << endl; exit(1); } } template <class T> List<T>::List(List<T>& L) { LinkNode<T> *srcptr = L.first; LinkNode<T> *destptr = first = new LinkNode<T>(srcptr->data); if(first == NULL) { cerr << "存储分配失败!" << endl; exit(1); } while(srcptr->link != NULL) { destptr->link = new LinkNode<T>(srcptr->link->data); if(destptr->link == NULL) {
数据结构图实验报告
1. 了解熟知图的定义和图的基本术语,掌握图的几种存储结构。
2. 掌握邻接矩阵和邻接表定义及特点,并通过实例解析掌握邻接矩阵和邻接表的类型定义。
3. 掌握图的遍历的定义、复杂性分析及应用,并掌握图的遍历方法及其基本思想。
1. 建立无向图的邻接矩阵2. 图的深度优先搜索3. 图的广度优先搜索建立无向图的邻接矩阵:源代码:#include "stdio.h"#include "stdlib.h"#define MAXSIZE 30typedef structchar vertex[MAXSIZE];//顶点为字符型且顶点表的长度小于MAXSIZEint edges[MAXSIZE][MAXSIZE];//边为整形且 edges 为邻近矩阵}MGraph;//MGraph 为采用邻近矩阵存储的图类型void CreatMGraph(MGraph *g,int e,int n){//建立无向图的邻近矩阵 g- >egdes,n 为顶点个数, e 为边数int i,j,k;printf("Input data of vertexs(0~n-1):\n");for(i=0;i<n;i++)g- >vertex[i]=i; //读入顶点信息for(i=0;i<n;i++)for(j=0;j<n;j++)g- >edges[i][j]=0; //初始化邻接矩阵for(k=1;k<=e;k++)//输入 e 条边{printf("Input edges of(i,j):");scanf("%d,%d",&i,&j);g- >edges[i][j]=1;g- >edges[j][i]=1;}void main(){int i,j,n,e;MGraph *g; //建立指向采用邻接矩阵存储图类型指针g=(MGraph*)malloc(sizeof(MGraph));//生成采用邻接举证存储图类型的存储空间printf("Input size of MGraph:"); //输入邻接矩阵的大小scanf("%d",&n);printf("Input number of edge:"); //输入邻接矩阵的边数scanf("%d",&e);CreatMGraph(g,e,n); //生成存储图的邻接矩阵printf("Output MGraph:\n");//输出存储图的邻接矩阵for(i=0;i<n;i++){for(j=0;j<n;j++)printf("%4d",g- >edges[i][j]);printf("\n");}}1) 源代码:#include "stdio.h"#include "stdlib.h"#define MAXSIZE 30typedef struct node//邻接表结点{int adjvex;//邻接点域struct node *next;//指向下一个邻接边结点的指针域}EdgeNode; //邻接表结点类型typedef struct vnode//顶点表结点{int vertex;//顶点域EdgeNode *firstedge; // 指向邻接表第一个邻接边节点的指针域}VertexNode;//顶点表结点类型void CreatAdjlist(VertexNode g[],int e,int n){//建立无向图的邻接表, n 为顶点数, e 为边数, g[]存储 n 个顶点表结点EdgeNode *p;int i,j,k;printf("Input data of vetex(0~n-1);\n");for(i=0;i<n;i++)//建立有 n 个顶点的顶点表{g[i].vertex=i; //读入顶点 i 信息g[i].firstedge=NULL; //初始化指向顶点 i 的邻接表表头指针}for (k=1;k<=e;k++)//输入 e 条边{printf("Input edge of(i,j):");scanf("%d,%d",&i,&j);p=(EdgeNode*)malloc(sizeof(EdgeNode));p- >adjvex=j; //在顶点 vi 的邻接表中添加邻接点为j 的结点p- >next=g[i].firstedge; //插入是在邻接表表头进行的g[i].firstedge=p;p=(EdgeNode*)malloc(sizeof(EdgeNode));p- >adjvex=i; //在顶点 vj 的邻接表中添加邻接点为 i 的结点p- >next=g[j].firstedge; //插入是在邻接表表头进行的g[j].firstedge=p;}}int visited[MAXSIZE]; //MAXSIZE 为大于或者等于无向图顶点个数的常量void DFS(VertexNode g[],int i){EdgeNode *p;printf("%4d",g[i].vertex); //输出顶点 i 信息,即访问顶点 i visited[i]=1;p=g[i].firstedge; //根据顶点 i 的指针 firstedge 查找其邻接表的第一个邻接边结点while(p!=NULL){if(!visited[p- >adjvex]) //如果邻接的这个边结点未被访问过DFS(g,p- >adjvex); //对这个边结点进行深度优先搜索p=p- >next; //查找顶点 i 的下一个邻接边结点}}void DFSTraverse(VertexNode g[],int n){//深度优先搜索遍历以邻接表存储的图,其中 g 为顶点数, n 为顶点个数int i;for(i=0;i<n;i++)visited[i]=0; //访问标志置 0for(i=0;i<n;i++)//对 n 个顶点的图查找未访问过的顶点并由该顶点开始遍历if(!visited[i]) //当 visited[i]等于 0 时即顶点 i 未访问过DFS(g,i); //从未访问过的顶点 i 开始遍历}void main(){int e,n;VertexNode g[MAXSIZE]; //定义顶点表结点类型数组 gprintf("Input number of node:\n");//输入图中节点个数边的个数scanf("%d",&n);printf("Input number of edge:\n");//输入图中边的个数scanf("%d",&e);printf("Make adjlist:\n");CreatAdjlist(g,e,n); //建立无向图的邻接表printf("DFSTraverse:\n");DFSTraverse(g,n); //深度优先遍历以邻接表存储的无向图printf("\n");}1) 源代码:#include "stdio.h"#include "stdlib.h"#define MAXSIZE 30typedef struct node1//邻接表结点{int adjvex; //邻接点域struct node1 *next;//指向下一个邻接边结点的指针域}EdgeNode; //邻接表结点类型typedef struct vnode//顶点表结点{int vertex;//顶点域EdgeNode *firstedge; // 指向邻接表第一个邻接边结点的指针域}VertexNode; //顶点表结点类型void CreatAdjlist(VertexNode g[],int e,int n){ //建立无向图的邻接表,n 为顶点数,e 为边数,g[]存储 n 个顶点表结点EdgeNode *p;int i,j,k;printf("Input data of vetex(0~n-1):\n");for(i=0;i<n;i++) //建立有 n 个顶点的顶点表{g[i].vertex=i; //读入顶点 i 信息g[i].firstedge=NULL; //初始化指向顶点 i 的邻接表表头指针}for(k=1;k<=e;k++) //输入 e 条边{printf("Input edge of(i,j):");scanf("%d,%d",&i,&j);p=(EdgeNode *)malloc(sizeof(EdgeNode));p- >adjvex=j;//在定点 vi 的邻接表中添加邻接点为 j 的结点p- >next=g[i].firstedge;//插入是在邻接表表头进行的g[i].firstedge=p;p=(EdgeNode *)malloc(sizeof(EdgeNode));p- >adjvex=i; //在顶点 vj 的邻接表中添加邻接点为 i 的结点p- >next=g[j].firstedge; //插入是在邻接表表头进行的g[j].firstedge=p;}}typedef struct node{int data;struct node *next;}QNode; //链队列结点的类型typedef struct{QNode *front,*rear; //将头、尾指针纳入到一个结构体的链队列}LQueue; //链队列类型void Init_LQueue(LQueue **q) //创建一个带头结点的空队列{QNode *p;*q=(LQueue *)malloc(sizeof(LQueue)); //申请带头、尾指针的链队列p=(QNode *)malloc(sizeof(QNode)); //申请链队列的头结点p- >next=NULL;//头结点的 next 指针置为空(*q)- >front=p; //队头指针指向头结点(*q)- >rear=p; //队尾指针指向头结点}int Empty_LQueue(LQueue *q) //判队空{if(q- >front==q- >rear) //队为空return 1;elsereturn 0;}void In_LQueue(LQueue *q,int x) //入队{QNode *p;p=(QNode *)malloc(sizeof(QNode)); //申请新链队列结点p- >data=x;p- >next=NULL; //新结点作为队尾结点时其 next 域为空q- >rear- >next=p; //将新结点*p 链到原队尾结点之后q- >rear=p; //使队尾指针指向新的队尾结点*p}void Out_LQueue(LQueue *q,int *x) //出队{QNode *p;if(Empty_LQueue(q))printf("Queue is empty!\n");//对空,出队失败else{p=q- >front- >next; //指针 p 指向链队列第一个数据结点(即对头结点)q- >front- >next=p- >next;//头结点的 next 指针指向链队列第二个数据结点(即删除第一个数据结点)*x=p- >data; //将删除的对头结点数据经由 x 返回free(p);if(q- >front- >next==NULL) //出队后队为空,则置为空q- >rear=q- >front;}}int visited[MAXSIZE]; //MAXSIZE 为大于或者等于无向图顶点个数的常量void BFS(VertexNode g[],LQueue *Q,int i){//广度优先搜索遍历邻接表存储的图,g 为顶点表,Q 为队指针,i 为第 i 个顶点int j,*x=&j;EdgeNode *p;printf("%4d",g[i].vertex); //输出顶点 i 信息,即访问顶点 i visited[i]=1; //置顶点 i 为访问过标志In_LQueue(Q,i); //顶点 i 入队 Qwhile(!Empty_LQueue(Q)) //当队 Q 非空时{Out_LQueue(Q,x); //对头顶点出队并送 j (暂记为顶点 j )p=g[j].firstedge;// 根据顶点 j 的表头指针查找其邻接表的第一个邻接边结点while(p!=NULL){if(!visited[p- >adjvex])//如果邻接的这个边结点未被{printf("%4d",g[p- >adjvex].vertex); // 输出这个邻接边结点的顶点信息visited[p- >adjvex]=1; //置该邻接边结点为访问过标志In_LQueue(Q,p- >adjvex); //将该邻接边结点送人队 Q}p=p- >next;//在顶点j 的邻接表中查找j 的下一个邻接边结点}}}void main(){int e,n;VertexNode g[MAXSIZE];//定义顶点表结点类型数组 gLQueue *q;printf("Input number of node:\n"); //输入图中结点个数scanf("%d",&n);printf("Input number of edge:\n");//输入图中边的个数scanf("%d",&e);printf("Make adjlist:\n ");CreatAdjlist(g,e,n);//建立无向图的邻接表Init_LQueue(&q);//队列 q 初始化printf("BFSTraverse:\n");BFS(g,q,0); //广度优先遍历以邻接表存储的无向图printf("\n");}1.通过本次试验让我对图的遍历以及图的深度和广度优先搜索有了更深刻的记忆和理解,将课本理论的知识得以实践。
实验报告数据结构课程设计源代码
表达式类型的实现——实习报告一.需求分析1. 编写一个程序,通过前缀表达式来构造一个与之对应的算术表达式并存入二叉树中,通过中序遍历二叉树输出表达式及对其进行变量赋值,通过后序遍历二叉树计算表达式的值。
2. 本程序功能有:存储表达式、对表达式进行赋值计算、求偏导、计算三角函数、合并常数及接受原书写形式的表达式。
3. 测试数据(1). 分别输入0 ; a ; -91 ; +a*bc ; +*5^x2*8x ; +++*3^x3*2^x2x6并输出。
(2). 每输入一个表达式,对其中的变量进行赋值,再对表达式求值。
二.概要设计按照要求,需要以二叉树来存储表达式,但在构造过程中还需要用到栈来实现前缀表达式与二叉树之间的转换。
1. 抽象数据类型栈的定义:ADT SqStack{数据对象:D={ai |ai为整型或字符型}数据关系:R={<ai , ai-1> |ai ,ai-1∈D}基本操作:Status InitStack(SqStack&S);此函数用于创建一个空栈Status StackEmpty(SqStack S);此函数用于判断栈是否为空Status StackFull(SqStack S);此函数用于判断栈是否已满Status Push(SqStack&S, SElemType e);将数据元素e入栈Status Pop(SqStack&S, SElemType&e);出栈,并以e返回出栈的元素Status GetTop(SqStack S, SElemType&e);若栈不空,则以e返回栈顶元素}ADT SqStack2. 二叉树表达式数据类型ATD BiTNode{数据对象:D= { a i | a i∈SqStack}数据关系:R= {<ai , ai-1> |ai ,ai-1∈D}基本操作:Status InputExpr(char*string,int flag);以字符串形式读取输入void JudgeValue(BiTree*E,char*string,int i);判断字符string[i],如果是'0'-'9'常量之间,二叉树结点存为整型;否则,存为字符型 Status ReadExpr(BiTree*E,char*exprstring);以正确的前缀表示式并构造表达式EStatus PriCmp(char c1,char c2);如果两个字符是运算符,比较两个运算符的优先级,c1比c2优先,返回OK,否则返回ERRORvoid WriteExpr(BiTree E);用带括弧的中缀表达式输出表达式void Assign(BiTree*E,char V,int c,int*flag);实现对表达式中的所有变量V的赋值(V=c),参数flag为表示是否赋值过的标志long Operate(int opr1,char opr,int opr2);运算符运算求值,参数opr1,opr2为常量,opr为运算符,根据不同的运算符,实现不同的运算,返回运算结果double Operate1(char opr,double opr1);三角函数运算求值,参数opr为常量,opr1为运算符,根据不同的运算符,实现不同的运算,返回运算结果Status Check(BiTree E);检查表达式是否还存在没有赋值的变量,以便求算数表达式的值long Value(BiTree E);对算术表达式求值void CompoundExpr(char P,BiTree&E1,BiTree E2);构造一个新的复合表达式Status ReadInorderExpr(char*string,char*pre_expr);以表达式的原书写形式输入,表达式的原书写形式字符串string变为字符串pre_expr,后调用reversal_string()函数反转得到前缀表达式pre_exprvoid ReversalString(char*exprstring);将字符串exprstring反转过来void MergeConst(BiTree*E);常数合并操作函数,合并表达式E中所有常数运算int IsOperator(char c);判断是否操作符void Diff(BiTree&E,char v);求偏导数}ADT BiTNode3. 主程序int main() {while(TRUE) {判断用户选择的操作;执行所选操作,并适时提示用户输入及输出运算结果;若用户选择退出,则执行exit(0)退出程序;};4. 程序调用关系:主程序模块三.详细设计1. 数据类型:二叉树数据类型:typedef enum{INT,CHAR}ElemTag;/*INT为整型数据num,CHAR为字符型数据c*/typedef struct TElemType{ElemTag tag;/*{INT,CHAR}指示是整型还是字符型*/int num;/*tag=INT时,为整型*/char c;/*tag=CHAR时,为字符型*/}TElemType;二叉树节点类型:typedef struct BiTNode{TElemType data;/* 二叉树存储的数据*/struct BiTNode*lchild,*rchild; /* 左右孩子指针*/}BiTNode,*BiTree;2. 函数实现:(以伪码表示)Status InputExpr(char *string,int flag) //此函数用于表达式的输入与存储{if(flag==0)cout<<"\n请输入正确的前缀表示式:";else cout<<"\n请以表达式的原书写形式输入正确表示式:";fflush(stdin);/*清理缓冲区*/gets(string);/*从键盘输入一串字符串作为表达式*/if(strlen(string)==1)/*输入的表达式字符串长度为1*/if(string[0]=='+'||string[0]=='-'||string[0]=='*'||string[0]=='/'||string[0]=='^')/*输入的表达式只有一个运算符*/{cout<<"\n表达式只有一个字符,为运算符,错误!";return ERROR;}else if((string[0]>='0'&&string[0]<'9')||(string[0]>='a'&&string[0]<='z')||(string[0]>='A'&&string[0]<='Z')) /*输入的表达式只有一个数字或字符*/{cout<<"\n表达式只有一个字符!";return OK;}else {cout<<"\n输入的字符不是运算符也不是变量常量,错误!";return ERROR;}return OK;}void JudgeValue(BiTree *E,char *string,int i) //此函数用于判断字符string[i],如果是'0'-'9'常量之间,二叉树结点存为整型;否则,存为字符型{if(string[i]>='0'&&string[i]<='9') {(*E)->data.tag=INT;(*E)->data.num=string[i]-'0';}//string[i]为常量else if(string[i]>='10'&&string[i]<='20') {(*E)->data.tag=INT;(*E)->data.num=SaveNumber[string[i]];} //string[i]为常量,存于数组save_number中else {(*E)->data.tag=CHAR;(*E)->data.c=string[i];} /*string[i]为变量,对数据进行变量标记}/*以正确的前缀表示式并构造表达式E*/Status ReadExpr(BiTree *E,char *exprstring){定义栈;为树的根结点分配空间;len=strlen(exprstring);/*len赋值为表达式的长度*/if(len==1) JudgeValue(E,exprstring,0);/*将exprstring[0]存入二叉树的结点中*/else {JudgeValue(E,exprstring,0);/*将exprstring[0]存入二叉树的结点中*/InitStack(S);/*初始化栈*/q=(*E);Push(S,q);/*入栈*/Push(S,q);/*入栈,根结点入栈两次是为判断先序输入的表达式是不是正确的表达式*/for(i=1;i<len&&!StackEmpty(S);i++){p=(BiTree)malloc(sizeof(BiTNode));JudgeValue(&p,exprstring,i);/*将exprstring[i]存入二叉树的结点中*/p->lchild=NULL;p->rchild=NULL;if(exprstring[i]=='+'||exprstring[i]=='-'||exprstring[i]=='*'||exprstring[i]=='/'||exprstring[i]=='^'){/*为运算符,运算符入栈,左孩子不空,向左孩子走,否则,如果右孩子不空,向右孩子走*/if(!q->lchild) {q->lchild=p;Push(S,p);q=p;}else {q->rchild=p;Push(S,p);q=p;}}else /*不是运算符,运算符出栈*/{if(!q->lchild) {q->lchild=p;Pop(S,q);}else {q->rchild=p;Pop(S,q);}}}if(StackEmpty(S)&&i>=len) return OK;/*栈空且i>=len,说明输入的表达式是正确的*/ else /*输入的表达式是错误的*/{cout<<"\n输入的表达式有误!";return ERROR;}}}//此函数用于比较两个运算符的优先级,若c1比c2优先,返回OK,否则返回ERROR Status PriCmp(char c1,char c2){if((c1=='^'||c1=='*'||c1=='-'||c1=='+'||c1=='/')&&(c2=='^'||c2=='*'||c2=='-'||c2=='+'||c2=='/')){/*c1和c2为运算符*/if(c1=='^'){/*c1为指数运算符,则当c2不为'^'时,c1比c2优先*/if(c2!='^') return OK;else return ERROR;}else if(c1=='*'||c1=='/'){/*c1为乘法或除法运算符,则当c2为'+'或'-',c1比c2优先*/if(c2=='^'||c2=='*'||c2=='/') return ERROR;else return OK;}else return ERROR;/*其余,c1不比c2优先*/}else return ERROR;/*c1和c2不是运算符*/}此函数递归实现用带括弧的中缀表达式输出表达式void WriteExpr(BiTree E){if(E)/*树不为空*/{ //先递归左子树if(E->lchild&&E->lchild->data.tag==CHAR)/*E的左孩子不为空,且左孩子为字符*/{if(PriCmp(E->data.c,E->lchild->data.c)){cout<<"(";WriteExpr(E->lchild);cout<<")";}/*带括弧输出左子树*/else WriteExpr(E->lchild);/*否则,不带括弧输出左子树*/}else WriteExpr(E->lchild);/*否则,输出左子树*//*访问输出根结点的值*/if(E->data.tag==INT){cout<<E->data.num;}else cout<<E->data.c;//后递归右子树if(E->rchild&&E->rchild->data.tag==CHAR){//E的右孩子不为空,且右孩子为字符if(PriCmp(E->data.c,E->rchild->data.c)){cout<<"(";WriteExpr(E->rchild);cout<<")";}/*带括弧输出右子树*/else WriteExpr(E->rchild);/*否则,不带括弧输出右子树*/}else WriteExpr(E->rchild);/*否则,输出右子树*/}}此函数递归实现对表达式中的所有变量V的赋值(V=c),参数flag为表示是否赋值过的标志void Assign(BiTree *E,char V,int c,int *flag){if(*E){if((*E)->data.tag==CHAR&&(*E)->data.c==V) {(*E)->data.tag=INT;(*E)->data.num=c;*flag=1;} /*如果找到要赋值的变量,赋值*/Assign(&((*E)->lchild),V,c,flag);/*递归左子树*/Assign(&((*E)->rchild),V,c,flag);/*递归左子树*/}}/*运算符运算求值,参数opr1,opr2为常量,opr为运算符,根据不同的运算符,实现不同的运算,返回运算结果*/long Operate(int opr1,char opr,int opr2){switch(opr){case '+':/*加法*/result=opr1+opr2;return result;break;case '-':/*减法*/result=opr1-opr2;return result;break;case '*':/*乘法*/result=opr1*opr2;return result;break;case '/':/*除法,除法是在整型类型上的除法*/result=opr1/opr2;return result;break;case '^':/*指数运算*/result=pow(opr1,opr2);return result;break;default:break;}}/*三角函数运算求值,参数opr为常量,opr1为运算符,根据不同的运算符,实现不同的运算,返回运算结果*/double Operate1(char opr,double opr1){switch(opr){case 's'://正弦运算result1=sin(opr1);return result1;break;case 'c'://余弦运算result1=cos(opr1);return result1;break;case 't'://正切运算result1=tan(opr1);return result1;break;default:break;}}/*检查表达式是否还存在没有赋值的变量,以便求算数表达式的值*/Status Check(BiTree E){if(E&&E->data.tag==CHAR){/*树不为空*/if(E->data.c!='*'&&E->data.c!='^'&&E->data.c!='-'&&E->data.c!='+'&&E->data.c!='/'){cout<<"\n表达式中仍存在变量没有赋值!没法求出表达式的值!";return ERROR;}/*存在变量,提示信息,后返回ERROR*/if(Check(E->lchild)) Check(E->rchild);}}/*对算术表达式求值*/long Value(BiTree E){if(E){/*树不为空*/if(!E->lchild&&!E->rchild&&E->data.tag==INT) return (E->data.num);/*结点的左孩子和右孩子为空,为叶子结点,返回结点的值*/return Operate(Value(E->lchild),E->data.c,Value(E->rchild));/*运算求值,后根遍历的次序对表达式求值,其中参数递归调用了Value()函数求左子树的值和右子树的值*/}}/*构造一个新的复合表达式*/void CompoundExpr(char P,BiTree &E1,BiTree E2){为结点E申请空间;E->data.tag=CHAR;E->data.c=P;/*申请到的结点值为P*/E->lchild=E1;/*结点的左孩子为E1*/E->rchild=E2;/*结点的右孩子为E2*/E1=E;/*(*E1)为根结点*/cout<<"\n表达式E复合成功!其表达式变为:\n";WriteExpr(E);/*输出复合好的表达式*/}/*此函数以表达式的原书写形式输入,表达式的原书写形式字符串string变为字符串pre_expr*//*后调用reversal_string()函数反转得到前缀表达式pre_expr*/Status ReadInorderExpr(char *string,char *PreExpr){int i,j,len,CharNumber=1;/*len表示字符串string的长度,char_number是记录数组save_number[]的个数*/int number;/*保存大于9的常量*/InitStack1(S);/*初始栈*/Push1(S,'#');/*先将字符'#'入栈,用来表示作为栈的最底一个元素*/len=strlen(string);/*len为字符串string的长度*/c=string[len-1];/*从字符串的最后一个字符开始向前扫描*/i=len-1;while(!StackEmpty1(S)&&i>=0){/*栈不为空且i大于等于0*/if(c=='('){/*字符为'('*/Pop1(S,c);/*出栈,赋值给c*/while(c!=')'){/*假如c不为')',出栈*/*PreExpr++=c;if(!StackEmpty1(S)&&GetTop1(S,c1)&&c1!='#') Pop1(S,c);else {cout<<"\n输入的表达式有误!";return ERROR;}}}else if(c==')'){Push1(S,c);} /*字符为')',入栈*/else if(c>='0'&&c<='9'){/*字符为'0'-'9'之间,循环扫描string前一个字符,后确定常量的大小*/number=c-'0';/*number为第一个常量字符的ASCII码-48*/for(c1=string[i-1],j=1;(c1>='0'&&c1<='9')&&i>=0;j++,i--){/*循环扫描string前一个字符,求出常量后赋给number*/number=(c1-'0')*pow(10,j)+number;/*number为扫描到的常量*/c1=string[i-2];}SaveNumber[CharNumber]=number;/*将number存入到数组save_number中,下标为char_number*/*PreExpr++=c;CharNumber++;}else if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){//string下一个字符不能为常量或变量,否则,出错if((string[i-1]>='0'&&string[i-1]<='9')||(string[i-1]>='A'&&string[i-1]<='Z')||(string[i-1]>='a'&&string[i-1]<='z')) {cout<<("\n输入的表达式有误!");return ERROR;}else *PreExpr++=c;}else if(c=='*'||c=='/'){/*字符为运算符'*'或'/'*/while(GetTop1(S,c1)&&(c1=='^')){Pop1(S,c1);*PreExpr++=c1;}/*如果c1比c优先,出栈*/Push1(S,c);/*入栈字符c*/}else if(c=='+'||c=='-'){/*字符为运算符'+'或'-'*/while(GetTop1(S,c1)&&(c1=='^'||c1=='*'||c1=='/')){Pop1(S,c1);*PreExpr++=c1;}/*如果c1比c优先,出栈*/Push1(S,c);/*入栈运算符c*/}else if(c=='^'){Push1(S,c);/*入栈运算符'^'*/}else {cout<<"\n输入的表达式有误!";return ERROR;}/*其他字符,错误,返回ERROR*/i--;/*下一个字符*/if(i>=0) c=string[i];/*i不小于0,c=string[i]循环下一个字符*/else /*否则,将清空栈*/while(!StackEmpty1(S)&&GetTop1(S,c1)&&c1!='#') {Pop1(S,c);*PreExpr++=c;} }Pop1(S,c);/*将'#'出栈*/*PreExpr='\0';/*字符串结束符*/if(i<0&&StackEmpty1(S)) return OK;else return ERROR;}/*将字符串exprstring反转过来*/void ReversalString(char *exprstring){len=strlen(exprstring);/*len为exprstring的长度*/for(i=0,j=len-1;i<j;i++,j--){/*字符串前后两个字符对换*/temp=exprstring[i];exprstring[i]=exprstring[j];exprstring[j]=temp;}}/*常数合并操作函数,合并表达式E中所有常数运算*/void MergeConst(BiTree *E){while((*E)->lchild&&(*E)->rchild){/*左右孩子不为空*/if((*E)->lchild->data.tag==INT&&(*E)->rchild->data.tag==INT){//假如左右孩子为常量,合并result=Operate((*E)->lchild->data.num,(*E)->data.c,(*E)->rchild->data.num);/*常数合并运算,调用Operate()函数求值*/(*E)->data.tag=INT;(*E)->data.num=result;/*修改之前的运算符为常量*/free((*E)->lchild);/*释放左孩子*/free((*E)->rchild);/*释放右孩子*/(*E)->lchild=(*E)->rchild=NULL;/*左右孩子置空*/}else{MergeConst(&((*E)->lchild));/*递归左孩子*/MergeConst(&((*E)->rchild));/*递归右孩子*/}}}//判断是否操作符int IsOperator(char c){switch(c){case '+': return TRUE;case '-': return TRUE;case '*': return TRUE;case '/': return TRUE;case '^': return TRUE;default: return FALSE;}}void Diff(BiTree &E,char v)//求偏导数{if((E->lchild)&&(E->rchild))//树不为空{if((E->rchild->data.c=='^')&&(E->rchild->lchild->data.c==v) )//若该变量为要求偏导的变量,则对其求偏导{E->lchild->data.num=(E->lchild->data.num)*(E->rchild->rchild->data.num);E->lchild->data.tag=INT;E->rchild->rchild->data.num=E->rchild->rchild->data.num-1;}else if(E->rchild->data.tag==INT&&(E->data.c=='+'||E->data.c=='-'))//若该变量不是要求偏导的变量,且为整数,则以0替换其中数据{E->rchild->data.num=0;E->rchild->data.tag=INT;}else if((E->rchild->data.c==v)&&(IsOperator(E->lchild->data.c)))//否则以1替换其中数据{E->rchild->data.num=1;E->rchild->data.tag=INT;}else if((E->rchild->data.c==v)&&E->lchild->data.tag==INT){E->data.num=E->lchild->data.num;E->data.tag=INT;free(E->lchild);free(E->rchild);E->lchild=E->rchild=NULL;}Diff(E->lchild,v);//递归执行左子树Diff(E->rchild,v);//递归执行右子树}else return;}3.主程序和其他函数:char menu()//主菜单{char choice;cout<<"\n\t****************************************";cout<<"\n\t***********9.表达式类型的实现***********";cout<<"\n\t 1 >>>输入正确的前缀表达式";cout<<"\n\t 2 >>>带括弧的中缀表示式输出";cout<<"\n\t 3 >>>对变量进行赋值";cout<<"\n\t 4 >>>对算数表达式求值";cout<<"\n\t 5 >>>构造一个新的复合表达式";cout<<"\n\t 6 >>>以表达式的原书写形式输入(选作)";cout<<"\n\t 7 >>>合并表达式中所有常数运算(选作)";cout<<"\n\t 8 >>>三角函数操作 (选作)";cout<<"\n\t 9 >>>求偏导数 (选作)";cout<<"\n\t 0 >>>退出";cout<<"\n\t****************************************";cout<<"\n\t请输入你的选择(数字)>>>>>";cin >> choice;return choice;}int main(){BiTree E,E1;//两个表达式E和E1int flag=0;//表达式E构造标志,为0表示未构造,为1表示已构造char V,P;//V被赋值,P为符合表达式运算符char string[30],ExprString[30];//字符串while(TRUE){system("cls");//清屏switch(menu()) {case '1':/*1 >>>输入正确的前缀表达式*/cout<<"\n\t*************************输入提示信息************************";cout<<"\n\t输入正确的前缀表达式的要求:";cout<<"\n\t\t【变量】 a-z或A-Z";cout<<"\n\t\t【常量】 0-9,不能超过9";cout<<"\n\t\t【运算符】 +,-,*,/,^";cout<<"\n\t请输入正确的前缀表达式,后按回车键存入缓冲区,否则可能会出错!";cout<<"\n\t*************************************************************";if(InputExpr(ExprString,0))//在flag=0时,初始输入if(ReadExpr(&E,ExprString)){//前缀读入并构造Eflag=1;cout<<"\n表达式构造成功!请按任意键返回菜单";}getchar();break;case '2':/*2 >>>带括弧的中缀表示式输出*/if(flag==1){cout<<("\n\t带括弧的中缀表达式为:");WriteExpr(E);}else cout<<("\n\t表达式未构造成功!请重新构造成功的表达式!");getchar();getchar();break;case '3':/*3 >>>对变量进行赋值*/cout<<("\n\t********************赋值操作说明信息***********************************");cout<<("\n\t赋值操作:实现对表达式中的某一个变量V的赋值,即使V=C,C为一整数");cout<<("\n\t 【1】根据输出的表达式,输入要赋值的变量V,只能输入一个字符,否则出错");cout<<("\n\t 【2】输入要将变量V赋值为的整数C,只能是整数,否则出错");cout<<("\n\t 【注】如果表达式未构造,请回到主菜单选择构造表达式");cout<<("\n\t***********************************************************************");if(flag==1){int AssignFlag=0;cout<<"\n表达式E为:";WriteExpr(E);fflush(stdin);/*清理缓冲区*/cout<<"\n请输入要赋值的字符:";V=getchar();cout<<"请输入要将赋值为:";cin>>c;Assign(&E,V,c,&AssignFlag);//赋值并改变标志if(AssignFlag){cout<<"\n赋值成功!\n赋值后的表达式为:";WriteExpr(E);}else cout<<"\n表达式里没有%c这个变量!",V;}else cout<<"\n表达式未构造成功!请构造成功的表达式!";getchar();getchar();break;case '4':/*4 >>>对算数表达式求值*/cout<<"\n\t********************算数表达式求值说明信息************************";cout<<"\n\t 【注】如果表达式还有变量未赋值,即表达式不是算数表达式";cout<<"\n\t 不能求出表达式的值,请回到主菜单选择赋值操作,后再求值";cout<<"\n\t******************************************************************";if(flag==1){cout<<"\n算数表达式:";WriteExpr(E);if(Check(E)){ //检查是否全赋值result=Value(E);cout<<"\n求算数表达式的值:\t";WriteExpr(E);cout<<"="<<result;}}else cout<<"\n表达式未构造成功!请构造成功的表达式!";getchar();getchar();break;case '5':/*5 >>>构造一个新的复合表达式*/cout<<"\n\t*****************构造新的复合表达式说明信息***************************";cout<<"\n\t 【1】构造一个新的表达式E1,采用表达式的原书写形式输入";cout<<"\n\t 【2】构造表达式E1成功后,输入要复合表达式E和E1的操作运算符(+,-,*,/,^)";cout<<"\n\t 【注】如表达式E未构造,不能复合表达式;如构造表达式E1错误,复合失败";cout<<"\n\t***********************************************************************";if(flag==1){cout<<"\n表达式E1为:";WriteExpr(E);cout<<"\n请构造新的表达式E2:";fflush(stdin);/*清理缓冲区*/if(InputExpr(string,1)){//标志为1,输入字符串if(ReadInorderExpr(string,ExprString)){//入栈ReversalString(ExprString);//反转if(ReadExpr(&E1,ExprString)){flag=1;cout<<("\n表达式E2构造成功!");WriteExpr(E1);cout<<("\n请输入要构造新的复合表达式的操作运算符>>>");P=getchar();while(P!='*'&&P!='/'&&P!='+'&&P!='-'&&P!='^'){fflush(stdin);/*清理缓冲区*/cout<<"\n输入的操作运算符有误!请重新输入>>>";P=getchar();}CompoundExpr(P,E,E1);}else cout<<"\n复合新的表达式失败!请按任意键返回主菜单!";}}}else cout<<"\n表达式未构造成功!请构造成功的表达式!";getchar();getchar();break;case '6':/*6 >>>以表达式的原书写形式输入*/cout<<"\n\t*************以表达式的原书写形式输入说明信息************************";cout<<"\n\t输入正确的原书写形式表达式";cout<<"\n\t 【变量】 a-z或A-Z";cout<<"\n\t 【常量】大于等于0的正整数";cout<<"\n\t 【运算符】 +,-,*,/,^(乘幂)";cout<<"\n\t 【括弧】左括弧 ( ,右括弧 ) ";cout<<"\n\t 【注】表示式中常量最多只能是30个,超过30个,出错!";cout<<"\n\t按原书写形式输入中,请按照正确的方式输入,否则可能会出错!";cout<<"\n\t**********************************************************************";if(InputExpr(string,1))if(ReadInorderExpr(string,ExprString)){ReversalString(ExprString);if(ReadExpr(&E,ExprString)){flag=1;cout<<"\n表达式构造成功!\n输入的带括弧的中缀表达式:";WriteExpr(E);}}getchar();getchar();break;case '7':/*7 >>>合并表达式中所有常数运算*/cout<<"\n***************合并表达式中的所有常数运算*******************************";cout<<"\n 【注】合并表达式中的所有常数运算并不能一次性将常数都合并!";cout<<"\n例如:表达式'1+2*(3+3*4+9/3)'的常数合并,选择7进行合并,结果变为\n'1+2*(3+12+3)',";cout<<"根据优先级先后合并的,如果要合并到最后,需多次选择7\n进行合并,又合并一次'1+2*(15+3)',";cout<<"再次合并'1+2*18',再次合并'1+36',\n再次合并'37',后无法合并!";cout<<"\n************************************************************************";if(flag==1) {cout<<"\n原表达式为:";WriteExpr(E);MergeConst(&E);//常数合并操作cout<<"\n合并表达式中所有的常数运算后的表达式:";WriteExpr(E);}else cout<<"\n表达式未构造成功!请构造成功的表达式!";getchar();getchar();break;case '8'://三角函数操作cout<<"\t***************************三角函数操作(选作)***************************";cout<<"\n";cout<<"\n\t[注] 请按要求输入其中 s代表sin c代表cos t代表tan ";cout<<"\n\t角度用弧度表示,例如~1 即表示sin 1";cout<<"\n\t本操作只可求三角函数值,如需其他操作请将结果带入其它操作中";cout<<"\n\t输入一个字符请按回车,确保正确录入";cout<<"\n\t************************************************************************";double opr1,result1;char opr;cout<<"\n请按要求输入";cin>>opr;cin>>opr1;result1=Operate1(opr,opr1);cout<<"结果为:"<<result1;getchar();getchar();break;case '9'://求导getchar();char h;cout<<"输入需要求偏导的变量字符\n";cin>>h;Diff(E,h);WriteExpr(E);getchar();getchar();break;case '0':/*0 >>>退出*/cout<<"\n请按任意键退出!";getchar();getchar();exit(0);break;default :cout<<"\n输入有误!请按任意键回到主菜单重新选择!";getchar();getchar();getchar();//Sleep(5000);break;}}return 0;}(部分代码较长,故在word文档中较难整理格式,请参见附录源代码查看)函数调用关系:四.调试分析1.合并表达式所有常数运算功能一开始只能实现一次合并,即:1+4*6=1+24 或者8+3*2^4=8+3*16。
数据结构实验报告--图
.数据结构实验报告图一、实验目的1、熟悉图的结构和相关算法。
二、实验内容及要求1、编写创建图的算法。
2、编写图的广度优先遍历、深度优先遍历、及求两点的简单路径和最短路径的算法。
三、算法描述1、图的邻接表存储表示:对图的每个顶点建立一个单链表,第i个单链表表示所有依附于第i个点的边(对于有向图表示以该顶点为尾的弧);链表的每个节点存储两个信息,该弧指向的顶点在图中的位置(adjvex)和指向下一条弧的指针(nextarc)。
每个连表的头结点存储顶点的数据:顶点信息(data)和指向依附于它的弧的链表域。
存储表示如下:typedef struct ArcNode {int adjvex; // 该弧所指向的顶点的位置struct ArcNode *nextarc;// 指向下一条弧的指针// InfoType *info; // 该弧相关信息的指针} ArcNode;typedef struct VNode {char data; // 顶点信息int data2;int sngle;ArcNode *firstarc;// 指向第一条依附该顶点的弧} VNode, AdjList[MAX_NUM];typedef struct {AdjList vertices;int vexnum, arcnum;int kind; // 图的种类标志} ALGraph;2、深度优先搜索:假设初始态是图中所有定点未被访问,从图中的某个顶点v开始,访问此顶点,然后依次从v的未访问的邻接点出发深度优先遍历,直至途中所有和v有相同路径的点都被访问到;若图中仍有点未被访问,则从图中另选一个未被访问的点作为起点重复上述过程,直到图中所有点都被访问到。
为了便于区分途中定点是否被访问过,需要附设一个访问标致数组visited [0..n-1],将其初值均设为false,一旦某个顶点被访问,将对应的访问标志赋值为true。
2、广度优先搜索:假设初始态是图中所有顶点未被访问,从图中的某个顶点v开始依次访问v的各个未被访问的邻接点,然后分别从这些邻接点出发以此访问他们的邻接点,并使“先被访问的邻接顶点”先于“后被访问的邻接顶点”被访问,直至图中所有已被访问过的顶点的邻接顶点都被访问。
数据结构实验报告有代码和截图
本科生实验报告二〇一九年九月二〇一九年十二月一、实验11、实验题目:顺序表综合练习2、实验目的:(1)掌握线性表的定义;(2)掌握线性表的顺序存储;(3)掌握线性表的基本操作,如建立、查找、插入和删除等。
3、实验内容:定义一个包含学生信息(学号,姓名,成绩)的线性表,进行综合运算(如遍历、显示、查找、取值、插入、删除等)4、实验代码#include <iostream>#include <fstream>#include <iomanip>#include <string>using namespace std;#define OK 1#define ERROR 0typedef int Status;#define OVERFLOW -2#define MAXSIZE 100struct Student{char no[8];char name[80];int price;};typedef struct{Student *elem;int length;} SqList;//--------------------------------------------------------------------------------------------Status InitList(SqList &L){L.elem=new Student[MAXSIZE];if(!L.elem) exit(OVERFLOW);L.length=0;return OK;}//--------------------------------------------------------------------------------------------Status DestroyList(SqList &L){if (L.elem)delete[]L.elem;L.length=0;return OK;}//--------------------------------------------------------------------------------------------Status CreatList(SqList &L){int n,j;if(!L.elem) exit(OVERFLOW);cout<<"请输入学生个数:"<<endl;cin>>n;for( j=0;j<n;j++){cout<<"输入第"<<j+1<<"个学生的学号,姓名,成绩:"<<endl;scanf("%s %s %d",L.elem[j].no,L.elem[j].name,&L.elem[j].price);L.length++;}return OK;}//--------------------------------------------------------------------------------------------Status TraverseList(SqList L){for(int i=0;i<L.length;i++)cout<<L.elem[i].no<<" "<<L.elem[i].name<<""<<L.elem[i].price<<endl;return OK;}//--------------------------------------------------------------------------------------------Status LocateElem(SqList L,char*name){for(int i=0;i<L.length;i++){if(!strcmp(name,L.elem[i].name)) cout<<L.elem[i].no<<" "<< L.elem[i].price<<endl;}return OK;}//--------------------------------------------------------------------------------------------Status GetElem(SqList L,int i){if(i<1||i>L.length) return ERROR;cout<<L.elem[i-1].no<<" "<<L.elem[i-1].name<<" "<<L.elem[i-1].price<<endl;return OK;}//--------------------------------------------------------------------------------------------Status ListInsert(SqList &L,int i,Student e){if(i<1||i>L.length+1) return ERROR;if(L.length>=MAXSIZE) return ERROR;for(int j=L.length-1;j>=i-1;j--)L.elem[j+1]=L.elem[j];L.elem[i-1]=e;++L.length;return OK;}//--------------------------------------------------------------------------------------------Status ListDelete(SqList &L,int i){if(i<1||i>L.length+1) return ERROR;for(int j=i;j<=L.length-1;j++)L.elem[j-1]=L.elem[j];L.length--;return OK;}//--------------------------------------------------------------------------------------------Status ListLength(SqList L){cout<<L.length<<endl;return OK;}//--------------------------------------------------------------------------------------------void main(){SqList L;int i,choose;char name[80];Status InitList(SqList &L);Status CreatList(SqList &L);Status DestroyList(SqList &L);Status TraverseList(SqList L);Status LocateElem(SqList L,char*name);Status GetElem(SqList L,int i);Status ListInsert(SqList &L,int i,Student e);Status ListDelete(SqList &L,int i);Status ListLength(SqList L);cout<<"---------------"<<endl;cout<<"1. 初始化顺序表"<<endl;cout<<"2. 输入学生信息"<<endl;cout<<"3. 显示学生个数"<<endl;cout<<"4. 显示全部学生信息"<<endl;cout<<"5. 查找学生信息"<<endl;cout<<"6. 获取学生信息"<<endl;cout<<"7. 插入学生信息"<<endl;cout<<"8. 删除学生信息"<<endl;cout<<"9. 销毁顺序表"<<endl;cout<<"10. 退出"<<endl;cout<<"---------------"<<endl;cout<<endl;choose=-1;while(choose!=0){cout<<"请选择:";cin>>choose;switch(choose){case 1:if(InitList(L))cout<<"success"<<endl;elsecout<<"fail"<<endl;break;case 2:CreatList(L);break;case 3:ListLength(L);break;case 4:TraverseList(L);break;case 5:cout<<"please enter the name of student"<<endl;cin>>name;LocateElem(L,name);break;case 6:cout<<"please enter the number of student"<<endl;cin>>i;GetElem(L,i);break;case 7:cout<<"please enter the number of student"<<endl;cin>>i;Student e;cout<<"please enter the imformation of inserting"<<endl;cin>>e.no>> >> e.price;ListInsert(L,i,e);break;case 8:cout<<"please enter the number of student"<<endl;cin>>i;ListDelete(L,i);break;case 9:if(DestroyList(L))cout<<"success"<<endl;elsecout<<"fail"<<endl;break;case 10:exit(OVERFLOW);break;}}}5、实验结果截图二、实验21、实验题目:单链表综合练习2、实验目的:(1)掌握线性表的定义;(2)掌握线性表的链式存储;(3)掌握线性表的基本操作,如建立、查找、插入和删除等;3、实验内容:定义一个包含学生信息(学号,姓名,成绩)的线性表,进行综合运算(如遍历、显示、查找、取值、插入、删除等)4、实验代码#include<iostream>#include<string>#include<iomanip>#include<fstream>using namespace std;#define OK 1#define ERROR 0#define OVERFLOW -2typedef int Status;struct Student {string no;char name[80];double price;};typedef struct LNode {Student data;struct LNode *next;} LNode, *LinkList;int length;Status InitList_L(LinkList &L) {L = new LNode;L->next = NULL;return OK;}Status GetElem_L(LinkList L, int i, Student &e) {int j;LinkList p;p = L->next;j = 1;while (j < i && p) {p = p->next;++j;}if (!p || j > i)return ERROR;e = p->data;return OK;}LNode *LocateElem_L(LinkList L, char *e) {LinkList p;p = L->next;while (p && strcmp(p->,e)!=0){p = p->next;}if(p == NULL)cout<<"can't find"<<endl;elsecout<<p->data.no<<" "<<p-><<" "<<p->data.price<<endl;return p;}Status ListInsert_L(LinkList &L, int i, Student &e) {int j;LinkList p, s;p = L;j = 0;while (p && j < i - 1) {p = p->next;++j;}if (!p || j > i - 1)return ERROR;s = new LNode;s->data = e;s->next = p->next;p->next = s;++length;return OK;}Status ListDelete_L(LinkList &L, int i) {LinkList p, q;int j;p = L;j = 0;while ((p->next) && (j < i - 1)){p = p->next;++j;}if (!(p->next) || (j > i - 1))return ERROR;q = p->next;p->next = q->next;delete q;--length;return OK;}void CreateList_R(LinkList &L) {LinkList p, r;int n;L = new LNode;L->next = NULL;r = L;length = 0;cout<<"请输入要输入同学的个数:";cin>>n;for(int i=0;i<n;i++){p=new LNode;cout<<"请输入第"<<i+1<<"个同学的学号,姓名和成绩:";cin>>p->data.no>>p->>>p->data.price;p->next=NULL;r->next=p;r=p;}length++;}int main() {int a,choose;Student e;LinkList L, p;cout << "1. 建立单链表\n";cout << "2. 输入同学信息\n";cout << "3. 取值\n";cout << "4. 输入同学姓名查找\n";cout << "5. 插入\n";cout << "6. 删除\n";cout << "7. 输出学生信息\n";cout << "0. 退出\n\n";choose = -1;while (choose != 0) {cout << "请选择:";cin >> choose;switch (choose) {case 1: //建立一个单链表if (InitList_L(L))cout << "成功建立链表!\n\n";break;case 2: //使用后插法创建单链表CreateList_R(L);cout << "输入同学信息完毕\n\n";break;case 3:cout << "请输入一个位置用来取值:";cin >> a;if (GetElem_L(L, a, e)) {cout << "查找成功\n";cout << "第" << a << "个同学的信息是:\n";cout << left << setw(15) << e.no << "\t" << left << setw(50)<< << "\t" << left << setw(5) << e.price << endl<< endl;} elsecout << "查找失败\n\n";break;case 4:char name[80];cout << "请输入所要查找同学的姓名:";cin >>name;if(LocateElem_L(L, name)) cout<<"查找成功!"<<endl;break;case 5:cout << "请输入插入的位置:";cin >> a;cout<<"请输入插入同学的信息,包括:no name price(用空格隔开):";cin >> e.no >> >> e.price;if (ListInsert_L(L, a, e))cout << "插入成功.\n\n";elsecout << "插入失败!\n\n";break;case 6:cout << "请输入所要删除的同学的位置:";cin >> a;if (ListDelete_L(L, a))cout << "删除成功!\n\n";elsecout << "删除失败!\n\n";break;case 7:cout << "当前同学信息(链表)读出:\n";p = L->next;while (p) {cout << left << setw(15) << p->data.no << "\t" << left << setw(50) << p-> << "\t" << left << setw(5)<< p->data.price << endl;p = p->next;}cout << endl;break;}}return 0;}5、实验结果截图三、实验31、实验题目:栈应用综合练习2、实验目的:(1)掌握栈的定义及实现;(2)掌握利用栈求解算术表达式的方法。
数据结构实验与实训教程源代码
i
第一部分 预备知识
预备知识
例 1.1 #include <stdio.h> int sumabc(int a, int b, int c) /* 求三个整数之和*/ { int s; a=b+c; s=a+b+c; return s; } void displayLine(void) { printf(”----------------------\n“); } void main( ) { int x,y, z ,sabc; x=y=z=8; display(); /* 画一条线 */ printf(“\n sum=%d”,sumabc(x,y,z)); /* 在输出语句中直接调用函数 sumabc( ) */ printf(“\n %6d%6d%6d”,x,y,z); display();/* 画一条线 */ x=2; y=4; z=6; sabc =sumabc(x, y, z); /* 在赋值语句中调用函数 sumabc( ) */ printf(“\n “ sum=%d”, sabc); printf(“\n %6d%6d%6d”,x,y,z); display();/* 画一条线 */ } 例 1.2 int sumabc(int *a, int b, int c) { int s; *a=b+c; s=*a+b+c;
2
}//while(1) }//main
3
第二部分 基础实验
实验 1 线性表的基本操作
四、参考程序
程序 1:题 1 线性表基本操作函数 #include<stdio.h> #include<stdlib.h> #include<alloc.h> struct LinearList /*定义线性表结构*/ { int *list; /* 存线性表元素 */ int size; /* 存线性表长度 */ int MaxSize; /* 存 list 数组元素个数 */ }; typedef struct LinearList LIST; void InitList( LIST *L, int ms ) /* 初始化线性表 */ { if( (L->list = 1 ) == NULL ) { printf( "内存申请错误!\n" ); exit( 1 ); } 2 L->MaxSize = ms; } int InsertList( LIST *L, int /* item:记录值 rc:插入位置 { int i; if( 3 ) return -1; if( rc < 0 ) item, int rc ) */备知识实验
数据结构-拓扑排序-实验报告与代码
实验报告七----拓扑排序一.需求分析1、采用邻接表法的存储结构来定义有向图2、实现有向图的创建、遍历3、实现栈的创建及其基本操作(进栈、退栈、判空)4、求图中顶点的入度二.算法设计本程序中采用的数据模型,用到的抽象数据类型的定义,程序的主要算法流程及各模块之间的层次调用关系拓扑排序的基本思想是以下两点:1、在有向图中选一个没有前驱的顶点且输出之。
2、从图中删除该顶点何所有以它为尾的弧。
3、查邻接表中入度为零的顶点,并进栈。
当栈为空时,进行拓扑排序。
(a)退栈,输出栈顶元素V。
(b)在邻接表中查找Vj的直接后继Vk,将Vk的入度减一,并令入度减至零的顶点进栈。
4、重复上述两步,直至全部顶点均已输出。
如每输出完,则证明有环。
程序基本结构:设定栈的抽象数据类型定义:ADT Stack {数据对象:D={i a |i a ∈CharSet ,i=1,2,3,…..,n,n>=0;}数据关系:R={<1-i a ,i a >|1-i a ,i a ∈D,i=2,…,n}存储结构:(1)表结点typedef struct ArcNode{i nt adjvex;s truct ArcNode *nextarc;}ArcNode;(2)链表的存储结构typedef struct VNode{i nt data;A rcNode *firstarc;}VNode,AdjList[MAX_VEXTEX_NUM];(3)图的存储结构typedef struct{A djList vertices;i nt vexnum, arcnum;}ALGraph;(4)栈的存储结构typedef struct{E lemType *base;E lemType *top;i nt stacksize;}SqStack;三.程序设计根据算法设计中给出的有关数据和算法,选定物理结构,详细设计需求分析中所要求的程序。
数据结构课程设计报告及源代码
printf("\t1.车辆到达--1 2.车辆离开--2 3.车辆信息--3 4.退出程序--4\n");
printf("\t**********************************************************\n");
4、要求栈以顺序结构实现,队列以链表实现
三、设计要求
1、独立完成全部代码的设计、编写、调试与部署,运行正确无误
2、编写设计报告书
设计报告书应包括:
(1)问题描述和系统要求
(2)系统主要功能模块设计
(3)设计中遇到的问题及其解决方法
(4)系统运行报告
(5)总结
问题描述:
设有一个可以停放n辆汽车的狭长停车场,它只有一个大门可以供车辆进出。车辆按到达停车场时间的早晚依次从停车场最里面向大门口处停放(最先到达的第一辆车放在停车场的最里面)。如果停车场已放满n辆车,则后来的车辆只能在停车场大门外的便道上等待,一旦停车场内有车开走,则排以便道上的第一辆车就进入停车场。停车场内如有某辆车要开走,在它之后进入停车场的车都必须先退出停车场为它让路,待其开出停车场后,这些辆再依原来的次序进场。每辆车在离开停车场时,都应根据它在停车场内停留的时间长短交费。如果停留在便道上的车未进停车场时,允许其离去,不收停车费,并且仍然保持在便道上等待的车辆的次序。编制一程序模拟该停车场的管理。
typedef struct node
{ int num;
int reachtime;
int leavetime;
(完整版)数据结构实验报告全集
数据结构实验报告全集实验一线性表基本操作和简单程序1.实验目的(1)掌握使用Visual C++ 6.0上机调试程序的基本方法;(2)掌握线性表的基本操作:初始化、插入、删除、取数据元素等运算在顺序存储结构和链表存储结构上的程序设计方法。
2.实验要求(1)认真阅读和掌握和本实验相关的教材内容。
(2)认真阅读和掌握本章相关内容的程序。
(3)上机运行程序。
(4)保存和打印出程序的运行结果,并结合程序进行分析。
(5)按照你对线性表的操作需要,重新改写主程序并运行,打印出文件清单和运行结果实验代码:1)头文件模块#include iostream.h>//头文件#include<malloc.h>//库头文件-----动态分配内存空间typedef int elemtype;//定义数据域的类型typedef struct linknode//定义结点类型{elemtype data;//定义数据域struct linknode *next;//定义结点指针}nodetype;2)创建单链表nodetype *create()//建立单链表,由用户输入各结点data域之值,//以0表示输入结束{elemtype d;//定义数据元素dnodetype *h=NULL,*s,*t;//定义结点指针int i=1;cout<<"建立一个单链表"<<endl;while(1){cout <<" 输入第"<< i <<"结点data域值:";cin >> d;if(d==0) break;//以0表示输入结束if(i==1)//建立第一个结点{h=(nodetype*)malloc(sizeof(nodetype));//表示指针hh->data=d;h->next=NULL;t=h;//h是头指针}else//建立其余结点{s=(nodetype*) malloc(sizeof(nodetype));s->data=d;s->next=NULL;t->next=s;t=s;//t始终指向生成的单链表的最后一个节点}i++;}return h;}3)输出单链表中的元素void disp(nodetype*h)//输出由h指向的单链表的所有data域之值{nodetype *p=h;cout<<"输出一个单链表:"<<endl<<" ";if(p==NULL)cout<<"空表";while(p!=NULL){cout<<p->data<<" ";p=p->next;}cout<<endl;}4)计算单链表的长度int len(nodetype *h)//返回单链表的长度{int i=0;nodetype *p=h;while(p!=NULL){p=p->next;i++;}return i;}5)寻找第i个节点nodetype *find(nodetype *h,int i)//返回第i个节点的指针{nodetype *p=h;int j=1;if(i>len(h)||i<=0)return NULL;//i上溢或下溢celse{while (p!=NULL&&j<1)//查找第i个节点,并由p指向该节点{j++;p=p->next;}return p;} }6)单链表的插入操作nodetype *ins(nodetype *h,int i,elemtype x)//在单链表head中第i个节点//(i>=0)之后插入一个data域为x的节点{nodetype *p,*s;s=(nodetype*)malloc(sizeof(nodetype));//创建节点ss->data=x;s->next=NULL;if(i==0)//i=0:s作为该单链表的第一个节点{s->next=h;h=s;}else{p=find(h,i);//查找第i个节点,并由p指向该节点if(p!=NULL){s->next=p->next;p->next=s;}return h;}}7)单链表的删除操作nodetype *del(nodetype *h,int i)//删除第i个节点{nodetype *p=h, *s;int j=1;if(i==1)//删除第1个节点{h=h->next;free(p);}else{p=find(h,i-1);//查找第i-1个节点,并由p指向该节点 if(p!=NULL&&p->next!=NULL){s=p->next;//s指向要删除的节点p->next=s->next;free(s);}else cout<<"输入i的值不正确"<<endl;}return h;}8)释放节点空间void dispose(nodetype *h)//释放单链表的所有节点占用的空间{nodetype *pa=h,*pb;if(pa!=NULL){pb=pa->next;if(pb==NULL)//只有一个节点的情况free(pa);else{while (pb!=NULL)//有两个及以上节点的情况{free(pa);pa=pb;pb=pb->next;}free(pa);}}}9)主程序模块:#include"slink.h"//包含头文件slinkvoid main(){nodetype *head;//定义节点指针变量head=create();//创建一个单链表disp(head);//输出单链表cout<<"单链表长度:"<<len(head)<<endl;ins(head, 2,0);//在第二个节点之后插入以0为元素的节点 disp(head);//输出新链表del(head,2);//删除第二个节点disp(head);//输出新链表}5.实验结果建立一个单链表:输入第1结点data域值:1输入第2结点data域值:2输入第3结点data域值:3输入第4结点data域值:4输入第5结点data域值:5输入第6结点data域值:6输入第7结点data域值:7输入第8结点data域值:8输入第9结点data域值:9输入第10结点data域值0:输出一个单链表:1 2 3 4 5 6 7 8 9单链表长度:9输出一个单链表:1 02345678 9输出一个单链表:1 2 3 4 5 6 7 8实验二顺序栈的实现1.实验目的掌握顺序栈的基本操作:初始化栈、判栈空否、入栈、出栈、取栈顶数据元素等运算以及程序实现方法。
数据结构 图实验 实验代码
1.邻接矩阵作为存储结构:#include <stdio.h>#include <stdlib.h>#define MaxVertexNum 100typedef struct{char verxs[MaxVertexNum];int edges[MaxV ertexNum][MaxVertexNum];int n,e;}MGraph;void creatMGraph(MGraph *G){int i,j,k;char a;printf("Input VertexNum(n)andEdgesNum(e):");scanf("%d,%d",&G->n,&G->e);scanf("%c",&a);printf("Input Vertex string");for(i=0;i<G->n;i++){scanf("%c",&a);G->verxs[i]=a;}for(i=0;i<G->n;i++)for(j=0;j<G->n;j++)G->edges[i][j]=0;printf("Input edges,Creat Adjacency Matrix\n");for(k=0;k<G->e;k++){scanf("%d%d",&i,&j);G->edges[i][j]=1;G->edges[j][i]=1;}}typedef enum{FALSE,TRUE}Boolean;Boolean visited[MaxVertexNum];void DFSM(MGraph*G,int i){int j;printf("%c",G->verxs[i]);visited[i]=TRUE;for(j=0;j<G->n;j++)if(G->edges[i][j]==1&&!visited[j])DFSM(G,j);}void DFS(MGraph*G){int i;for(i=0;i<G->n;i++)visited[i]=FALSE;for(i=0;i<G->n;i++)if(!visited[i])DFSM(G,i);}void BFS(MGraph*G,int k){int i,j,f=0,r=0;int cq[MaxVertexNum];for(i=0;i<G->n;i++)visited[i]=FALSE;for(i=0;i<G->n;i++)cq[i]=-1;printf("%c",G->verxs[k]);visited[k]=TRUE;cq[r]=k;while(cq[f]!=-1){ i=cq[f];f=f+1;for(j=0;j<G->n;j++)if(G->edges[i][j]==1&&!visited[j]){printf("%c",G->verxs[j]);visited[j]=TRUE;r=r+1;cq[r]=j;}}}void main(){int i;MGraph*G;G=(MGraph*)malloc(sizeof(MGraph));creatMGraph(G);printf("Print Graph DFS:");DFS(G);printf("\n");printf("Print Graph BFS:");BFS(G,3);printf("\n");}2.邻接链表作为存储结构:#include"stdio.h"#include"stdlib.h"#define MaxVertexNum 50 /*定义最大顶点数*/typedef struct node{ /*边表结点*/int adjvex; /*邻接点域*/struct node *next; /*链域*/}EdgeNode;typedef struct vnode{ /*顶点表结点*/char vertex; /*顶点域*/EdgeNode *firstedge; /*边表头指针*/}VertexNode;typedef VertexNode AdjList[MaxVertexNum]; /*AdjList是邻接表类型*/ typedef struct {AdjList adjlist; /*邻接表*/int n,e; /*图中当前顶点数和边数*/} ALGraph; /*图类型*//* 建立图的邻接表*/void CreatALGraph(ALGraph *G){int i,j,k;char a;EdgeNode *s; /*定义边表结点*/printf("Input VertexNum(n)andEdgesNum(e): ");scanf("%d,%d",&G->n,&G->e); /*读入顶点数和边数*/scanf("%c",&a);printf("Input Vertex string:");for(i=0;i<G->n;i++) /*建立边表*/{scanf("%c",&a);G->adjlist[i].vertex=a; /*读入顶点信息*/G->adjlist[i].firstedge=NULL; /*边表置为空表*/}printf("Input edges,Creat Adjacency Matrix\n");for(k=0;k<G->e;k++) { /*建立边表*/scanf("%d%d",&i,&j); /*读入边(Vi,Vj)的顶点对序号*/s=(EdgeNode *)malloc(sizeof(EdgeNode)); /*/生成边表结点*/s->adjvex=j; /*邻接点序号为j*/s->next=G->adjlist[i].firstedge;G->adjlist[i].firstedge=s; /*将新结点*S插入顶点Vi的边表头部*/s=(EdgeNode *)malloc(sizeof(EdgeNode));s->adjvex=i; /*邻接点序号为i*/s->next=G->adjlist[j].firstedge;G->adjlist[j].firstedge=s; /*将新结点*S插入顶点Vj的边表头部*/}}/* 定义标志向量,为全局变量*/typedef enum{FALSE,TRUE} Boolean;Boolean visited[MaxVertexNum];/* DFS:深度优先遍历的递归算法*/void DFSM(ALGraph *G,int i){ /*以Vi为出发点对邻接链表表示的图G进行DFS搜索*/ EdgeNode *p;printf("%c ",G->adjlist[i].vertex); /*访问顶点Vi*/visited[i]=TRUE; /*标记Vi已访问*/p=G->adjlist[i].firstedge; /*取Vi边表的头指针*/while(p) { /*依次搜索Vi的邻接点Vj,这里j=p->adjvex*/if(! visited[p->adjvex]) /*若Vj尚未被访问*/DFSM(G,p->adjvex); /*则以Vj为出发点向纵深搜索*/ p=p->next; /*找Vi的下一个邻接点*/}}void DFS(ALGraph *G){int i;for(i=0;i<G->n;i++)visited[i]=FALSE; /*标志向量初始化*/for(i=0;i<G->n;i++)if(!visited[i]) /*Vi未访问过*/DFSM(G,i); /*以Vi为源点开始DFS搜索*/}/* BFS:广度优先遍历*/void BFS(ALGraph *G,int k){ /*以Vk为源点对用邻接链表表示的图G进行广度优先搜索*/int i,f=0,r=0;EdgeNode *p;int cq[MaxVertexNum]; /*定义FIFO队列*/for(i=0;i<G->n;i++)visited[i]=FALSE; /*标志向量初始化*/for(i=0;i<=G->n;i++)cq[i]=-1; /*初始化标志向量*/printf("%c ",G->adjlist[k].vertex); /*访问源点Vk*/visited[k]=TRUE;cq[r]=k; /*Vk已访问,将其入队。
数据结构二叉树实验报告(附代码)
一、【实验构思(Conceive)】(10%)(本部分应包括:描述实验实现的基本思路,包括所用到的离散数学、工程数学、程序设计、算法等相关知识)首先构造二叉树的存储结构,用data存储当前节点的值,分别用*lchild,*rchild 表示该节点的左右孩子。
然后应用BiTree Create函数,根据用户的输入构造二叉树,当输入#时表示没有孩子。
采用递归的思想构造Preorder,Inorder,Postorder函数,分别实现二叉树的先序,中序,和后序的遍历。
然后编写了Sumleaf,Depth函数,来求叶子节点的数目和二叉树的深度。
二、【实验设计(Design)】(20%)(本部分应包括:抽象数据类型的功能规格说明、主程序模块、各子程序模块的伪码说明,主程序模块与各子程序模块间的调用关系)二叉树的存储结构:typedef struct BiTNode{char data;struct BiTNode *lchild,*rchild;}BiTNode,*BiTree;子程序模块:BiTree Create(BiTree T){char ch;ch=getchar();if(ch=='#')T=NULL;else{if(!(T=(BiTNode *)malloc(sizeof(BiTNode))))printf("Error!");T->data=ch;T->lchild=Create(T->lchild);T->rchild=Create(T->rchild);}return T;}void Preorder(BiTree T){if(T){printf("%c",T->data);Preorder(T->lchild);Preorder(T->rchild);}}int Sumleaf(BiTree T){int sum=0,m,n;if(T){if((!T->lchild)&&(!T->rchild)) sum++;m=Sumleaf(T->lchild);sum+=m;n=Sumleaf(T->rchild);sum+=n;}return sum;}void Inorder(BiTree T) {if(T){Inorder(T->lchild); printf("%c",T->data); Inorder(T->rchild); }}void Postorder(BiTree T) {if(T){Postorder(T->lchild); Postorder(T->rchild); printf("%c",T->data); }}int Depth(BiTree T){int dep=0,depl,depr;if(!T)dep=0;else{depl=Depth(T->lchild);depr=Depth(T->rchild);dep=1+(depl>depr?depl:depr);}return dep;}主程序模块:int main(){BiTree T = 0;int sum,dep;printf("请输入你需要建立的二叉树\n");printf("例如输入序列ABC##DE#G##F###(其中的#表示空)\n并且输入过程中不要加回车\n输入完之后可以按回车退出\n");T=Create(T);printf("先序遍历的结果是:\n");Preorder(T);printf("\n");printf("中序遍历的结果是:\n");Inorder(T);printf("\n");printf("后序遍历的结果是:\n");Postorder(T);printf("\n");printf("统计的叶子数:\n");sum=Sumleaf(T);printf("%d",sum);printf("\n统计树的深度:\n");dep=Depth(T);printf("\n%d\n",dep);}三、【实现描述(Implement)】(30%)(本部分应包括:抽象数据类型具体实现的函数原型说明、关键操作实现的伪码算法、函数设计、函数间的调用关系,关键的程序流程图等,给出关键算法的时间复杂度分析。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
附件2:北京理工大学珠海学院实验报告ZHUHAI CAMPAUS OF BEIJING INSTITUTE OF TECHNOLOGY 实验题目图及其应用实验时间 2011.5.10一、实验目的、意义(1)熟悉图的邻接矩阵(或邻接表)的表示方法;(2)掌握建立图的邻接矩阵(或邻接表)算法;(3)掌握图的基本运算,熟悉对图遍历算法;(4)加深对图的理解,逐步培养解决实际问题的编程能力二、实验内容及要求说明1:学生在上机实验时,需要自己设计出所涉及到的函数,同时设计多组输入数据并编写主程序分别调用这些函数,调试程序并对相应的输出作出分析;修改输入数据,预期输出并验证输出的结果,加深对有关算法的理解。
具体要求:(1)建立图的邻接矩阵(或邻接表);(2)对其进行深度优先及广度优先遍历。
三、实验所涉及的知识点1.创建一个图: CreateUDN(MGraph &G)2.查找v顶点的第一个邻接点: FirstAdjVex(MGraph G,int v)3. 查找基于v顶点的w邻接点的下一个邻接点: NextAdjVex(MGraph G,int v,int w)4.图的矩阵输出: printArcs(MGraph G)5:顶点定位: LocateVex(MGraph G,char v)6. 访问顶点v输出: printAdjVex(MGraph G,int v)7. 深度优先遍历: DFSTraverse(MGraph G,Status (*Visit)(MGraph G,int v))8. 广度优先遍历BFSTraverse(MGraph G,Status (*Visit)(MGraph G,int v))9. DFS,从第v个顶点出发递归深度优先遍历图G: DFS(MGraph G,int v)四、实验记录1.对顶点的定位其数组下标,利用了找到之后用return立即返回,在当图顶点多的情况下节省了搜索时间,程序如下//对顶点v定位,返回该顶点在数组的下标索引,若找不到则返回-1int LocateVex(MGraph G,char v){for (int i=0;i<G.vexnum;i++){if(v == G.vexs[i])return i;}return -1;}2,定义里一个全局的函数指针变量,同时在深度优先遍历中加入一个函数指针参,调用时,将传如的函数赋值给全局的函数指针,这样在之后循环调用DFS的时候就不用将函数传给DFS函数了,程序如下://深度优先遍历void DFSTraverse(MGraph G,Status (*Visit)(MGraph G,int v)){//将函数复制给全局的函数指针变量,待调用DFS时使用VisitFunc = Visit;int v;//将访问标记初始化为falsefor (v=0;v<G.vexnum;v++)visited[v] = false;for (v=0;v<G.vexnum;v++)//对尚未访问即访问标记为false的顶点调用DFSif (!visited[v]) DFS(G,v);}五、实验结果及分析预备输入的图结构如下:顶点为:a ,b ,c ,d ,e弧及其权值为:a,b,2a,c,3 b,d,4 b,e,2 d,e,1结果如下:1.图的创建,先输入顶点个数与边数,如图 4.1.1,接着输入各顶点的值,如图4.1.2,最后输入三条边依附的顶点以及权值,当输入的顶点不在图中时,会提示重新输入,如图4.1.3图4.1.1图4.1.2图4.1.3 abc d e2 31 422.图的矩阵输出,如图4.2图4.23.深度优先遍历图,输出序列,如图4.3图4.34.广度优先遍历图,输出序列,如图4.4图4.4六、总结与体会图,是一种较线性表和树更为复杂的数据结构将其用深度遍历后,可以变成一棵树,或者一个森林。
和树的遍历相类似,都利用了递归的方法,逐个搜索输出。
用邻接矩阵表示图,形象地体现出顶点与顶点之间的紧密关系。
七、程序清单(包含注释)#include "stdio.h"#include "limits.h" //INT_MAX头文件#include "windows.h" //boolean头文件#define INFINITY INT_MAX#define MAX_VERTEX_NUM 20#define OVERFLOW -1#define OK 1#define ERROR 0typedef int Status;typedef enum {DG,DN,UDG,UDN} GraphKind;typedef int VRType;typedef char VertexType;typedef char* InfoType;typedef int QElemType;//边信息typedef struct ArcCell{VRType adj; //1或0表示是否邻接,对带权图,则为权值类型InfoType *info;}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//图结构typedef struct {VertexType vexs[MAX_VERTEX_NUM]; //定点向量AdjMatrix arcs; //邻接矩阵,为一二维数组int vexnum,arcnum; //图的当前顶点数和弧数GraphKind kind; //图的种类标志}MGraph;//辅助队列typedef struct QNode{QElemType data; //数值域struct QNode *next; //指针域}QNode, *QueuePtr;typedef struct{QueuePtr front; //队头QueuePtr rear; //队尾}LinkQueue;//初始化队列Status InitQueue(LinkQueue &Q){Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));if (!Q.front){printf("内存分配失败!");exit(OVERFLOW);}Q.front->next = NULL;return OK;}//插入元素到队尾Status EnQueue(LinkQueue &Q,QElemType e){QueuePtr p = (QueuePtr)malloc(sizeof(QNode));if (!p){printf("\n内存分配失败!");exit(OVERFLOW);}p->data = e;p->next = NULL;Q.rear->next = p;Q.rear = p;return OK;}//队列判空Status QueueEmpty(LinkQueue Q){return Q.front == Q.rear;}//销毁队列Status DestroyQueue(LinkQueue &Q){while (Q.front){Q.rear = Q.front->next;free(Q.front);Q.front = Q.rear;}return OK;}//删除队头元素Status DeQueue(LinkQueue &Q,QElemType &e){if (QueueEmpty(Q)){printf("\n队列为空!");return ERROR;}QueuePtr p = Q.front->next;e = p->data;Q.front->next = p->next;if(Q.rear==p) Q.rear = Q.front;free(p);return OK;}//对顶点v定位,返回该顶点在数组的下标索引,若找不到则返回-1 int LocateVex(MGraph G,char v){for (int i=0;i<G.vexnum;i++){if(v == G.vexs[i])return i;}return -1;}//create a graphStatus CreateUDN(MGraph &G){G.kind = UDN;printf("输入顶点个数和边数(如:4,3):");scanf("%d,%d",&G.vexnum,&G.arcnum);//判断是否超过顶点最大个数while(G.vexnum>MAX_VERTEX_NUM){printf("最大顶点为20,重新输入(如:4,3):");scanf("%d,%d",&G.vexnum,&G.arcnum);}printf("\n依次输入顶点向量值\n");int i;for (i=0;i<G.vexnum;i++){//清空缓冲区fflush(stdin);printf("第%d个:",i+1);scanf("%c",&G.vexs[i]);}//初始化邻接矩阵for (i=0;i<G.vexnum;i++){for (int j=0;j<G.vexnum;j++){G.arcs[i][j].adj = INFINITY;G.arcs[i][j].info = NULL;}}char front,rear;int values;printf("\n输入依附两个顶点的边及其权值<如,a,b,1>\n");for(i=0;i<G.arcnum;i++){printf("第%d条:",i+1);//清空缓冲区fflush(stdin);scanf("%c,%c,%d",&rear,&front,&values);int m,n;//定位两顶点在vexs数组中的索引m = LocateVex(G,rear);n = LocateVex(G,front);if(m==-1||n==-1){printf("输入顶点或不在此图中,请重新输入!\n");i--;continue;}//赋予对应矩阵位置的权值,以及对称弧的权值G.arcs[m][n].adj = values;G.arcs[n][m].adj = values;}return OK;} //CreateUDG//矩阵输出void printArcs(MGraph G){int i;printf(" ");//输出第一行的顶点向量for (i=0;i<G.vexnum;i++){printf(" %c",G.vexs[i]);}for (i=0;i<G.vexnum;i++){printf("\n\n%c",G.vexs[i]);for (int j=0;j<G.vexnum;j++){if(G.arcs[i][j].adj==INFINITY)printf(" ∞");elseprintf(" %d",G.arcs[i][j].adj);}}printf("\n");}//访问顶点v输出Status printAdjVex(MGraph G,int v){printf("%c ",G.vexs[v]);return OK;}//查找v顶点的第一个邻接点Status FirstAdjVex(MGraph G,int v){//查找与顶点v的第一个邻接点,找到后立即返回其索引,若找不到,则返回-1 for (int i=1;i<G.vexnum;i++){if(G.arcs[v][i].adj!=INFINITY)return i;}return -1;}//查找基于v顶点的w邻接点的下一个邻接点Status NextAdjVex(MGraph G,int v,int w){//查找基于顶点v的w邻接点的下一个邻接点,找到之后立即返回其索引,若找不到,则返回-1for (int i=w+1;i<G.vexnum;i++){if (G.arcs[v][i].adj!=INFINITY)return i;}return -1;}//创建访问标志全局变量boolean visited[MAX_VERTEX_NUM];//函数指针变量Status (* VisitFunc)(MGraph G,int v);//DFS,从第v个顶点出发递归深度优先遍历图Gvoid DFS(MGraph G,int v){visited[v] = TRUE;//访问第v个顶点VisitFunc(G,v);for (int w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w)){if (!visited[w])DFS(G,w);}}//深度优先遍历void DFSTraverse(MGraph G,Status (*Visit)(MGraph G,int v)){//将函数复制给全局的函数指针变量,待调用DFS时使用VisitFunc = Visit;int v;//将访问标记初始化为falsefor (v=0;v<G.vexnum;v++)visited[v] = false;for (v=0;v<G.vexnum;v++)//对尚未访问即访问标记为false的顶点调用DFSif (!visited[v]) DFS(G,v);}//广度优先遍历void BFSTraverse(MGraph G,Status (*Visit)(MGraph G,int v)){//按广度优先非递归遍历图G,使用辅助队列Q和访问标志数组Visitedint v;int u;//将访问标记数组初始化为falsefor (v = 0;v<G.vexnum;v++)visited[v] = FALSE;//创建辅助队列QLinkQueue Q;InitQueue(Q);for (v = 0;v<G.vexnum;v++)//判断顶点V是否被访问if (!visited[v]){//将第一次访问的顶点对应的访问标记数组位置赋值为TRUEvisited[v] = TRUE;//输出顶点vVisit(G,v);EnQueue(Q,v);while (!QueueEmpty(Q)){//按入队序列取出顶点,便于查找此顶点的邻接点DeQueue(Q,u);//查找当前顶点邻接点for (int w=FirstAdjVex(G,u);w>=0;w = NextAdjVex(G,u,w))if (!visited[w]){visited[w] =TRUE;Visit(G,w);EnQueue(Q,w);}}}//销毁队列DestroyQueue(Q);}void main(){printf("====图的创建及其应用====\n");//创建一个图MGraph G;CreateUDN(G);//用邻接矩阵输出图printf("\n图的邻接矩阵输出如下:\n");printArcs(G);//深度优先遍历printf("\n深度优先遍历序列:\n");DFSTraverse(G,printAdjVex);printf("\n");//广度优先遍历printf("\n广度优先遍历序列:\n");BFSTraverse(G,printAdjVex);printf("\n");}11。