第一篇:数据结构实验报告-最小生成树
电 子 科 技 大 学
实
验
报
告
学生姓名:XXX 学 号:
20***
指导教师:刘峤 实验地点:信软楼306
实验时间:5月17日
一、实验室名称:软件实验室
二、实验项目名称:数据结构与算法—图
三、实验学时:4
四、实验原理:
Kruskal 算法是一种按照图中边的权值递增的顺序构造最小生成树的方法。其基本思想是:设无向连通网为G=(V,E),令G 的最小生成树为T,其初态为T=(V,{}),即开始时,最小生成树T 由图G 中的n 个顶点构成,顶点之间没有一条边,这样T 中各顶点各自构成一个连通分量。然后,按照边的权值由小到大的顺序,考察G 的边集E 中的各条边。若被考察的边的两个顶点属于T 的两个不同的连通分量,则将此边作为最小生成树的边加入到T 中,同时把两个连通分量连接为一个连通分量;若被考察边的两个顶点属于同一个连通分量,则舍去此边,以免造成回路,如此下去,当T 中的连通分量个数为1 时,此连通分量便为G 的一棵最小生成树。
如教材153页的图4.21(a)所示,按照Kruskal 方法构造最小生成树的过程如图4.21 所示。在构造过程中,按照网中边的权值由小到大的顺序,不断选取当前未被选取的边集中权值最小的边。依据生成树的概念,n 个结点的生成树,有n-1 条边,故反复上述过程,直到选取了n-1 条边为止,就构成了一棵最小生成树。
五、实验目的:
本实验通过实现最小生成树的算法,使学生理解图的数据结构存储表示,并能理解最小生成树Kruskal 算法。通过练习,加强对算法的理解,提高编程能力。
六、实验内容:
(1)假定每对顶点表示图的一条边,每条边对应一个权值;
(2)输入每条边的顶点和权值;
(3)输入每条边后,计算出最小生成树;
(4)打印最小生成树边的顶点及权值。
七、实验器材(设备、元器件):
八、数据结构及程序
#include
struct {
int
vex;
int
gno;}TVex,*TpVex;
typedef
struct {
int
vhead, vtail;
int
wght;
int
flag;}TEdge,*TpEdge;
typedef struct{
TpVex VexList;
TpEdge EdgeList;
int nvex, nedge;}TGraph, *TpGraph;
void begin(TpGraph G){ int i;for(i=1;i<=G->nvex;i++){
G->VexList[i-1].gno=i;
G->EdgeList[i-1].flag=0;} } int findmin(TpGraph G){ int i,j;int minwght=G->EdgeList[0].wght;for(i=0,j=-1;i
if(G->EdgeList[i].wght
minwght=G->EdgeList[i].wght;
j=i;
} }
return j;}
void create(TpGraph G){
int i,j,minEdge;
for(i=0;i
minEdge=findmin(G);
if(G->VexList[G->EdgeList[minEdge].vhead].gno== G->VexList[G->EdgeList[minEdge].vtail].gno)
G->EdgeList[minEdge].flag=-1;
else{
G->EdgeList[minEdge].flag=1;
G->VexList[G->EdgeList[minEdge].vtail].gno= G->VexList[G->EdgeList[minEdge].vhead].gno;
for(j=0;j
if
(G->VexList[j].gno==G->VexList[G->EdgeList[minEdge].vtail].gno)
G->VexList[j].gno=G->VexList[G->EdgeList[minEdge].vhead].gno;
}
printf(“head:%d tail:%d
weight:%dn”,G->EdgeList[minEdge].vhead,G->EdgeList[minEdge].vtail,G->EdgeList[minEdge].wght);
i++;
}
}
} void read_file(char *filename,char *message,TpGraph
G){ int a = 0,b,c,i,j,vexlist[20]={0},m,k=0;FILE *pfile=NULL;pfile=fopen(filename,“r”);if(!pfile){
printf(“Open file failn”);
exit(0);} else
printf(“Open file success!n”);
G->EdgeList=(TpEdge)malloc(sizeof(TpEdge)*21);G->VexList=(TpVex)malloc(sizeof(TpVex)*7);for(i = 0;i < 20;++i){
fscanf(pfile , “%dt%dt%dn” , &a, &b, &c);
G->EdgeList[i].vhead=a;
G->EdgeList[i].vtail=b;
G->EdgeList[i].wght=c;
printf(“%dt%dt%dn”, a, b, c);
vexlist[k]=a;
k++;
for(m=0;m if(vexlist[m]==vexlist[k-1]) k--; } vexlist[k]=b; k++; for(m=0;m if(vexlist[m]==vexlist[k-1]) k--; } } for(j=0;j<6;j++) G->VexList[j].vex=j+1; G->nedge=20;G->nvex=j;} int main(){ char *filename=“/Users/pro/Desktop/实验/数据结构实验3/graph.txt”; TGraph G; int Edges[20][3] = {0}; read_file(filename,Edges,&G); begin(&G); create(&G); return 0;} 九、程序运行结果: 运行程序: 实验成功。 十、实验结论: 克鲁斯卡尔算法是一种能够体现“贪心”的精髓的贪心算法,它所使用的贪婪准则是:从剩下的边中选择一条不会产生环路的具有最小耗费的边加入已选择的边的集合中。 十一、总结及心得体会: 克鲁斯卡尔算法的时间复杂度为O(eloge),因此它相对于普里姆算法而言,适合于求边稀疏的网的最小生成树。 数据结构 课程设计报告 设计题目:最小生成树 专业:xxxxxx 院系:计算机学院 姓名:xxxxxxxxx 学号:xxxxxx 时间:2013年10月7日 数据结构课程设计报告 最小生成树 目 录 一、设计目的……………………………………………………………….-2- 二、算法思想分析………………………………………………………-2-1.算法思想………………………………………………………………..-3-1)普里姆(Prim)算法思想……………………………………………………….-3-2)克鲁斯卡尔(Kruskal)算法思想..........................................-3-2.系统采用的数据结构和算法………………………………-3- 三、算法的描述与实现……………………………………………….-4- 四、用户手册………………………………………………………………-7- 五、总结…………………………………………………………………….-10- 六、参考文献…………………………………………………………….-10- 七、附录(源代码)………………………………………………...-10- 数据结构课程设计报告 最小生成树 1.算法思想 1)普里姆(Prim)算法思想 a)选择从0节点开始,并选择0节点相关联的最小权值边,将与这条边相关联的另一顶点出列; b)在出列的节点中相关联的所有边中选择一条不与另一个已出列的节点相关联的权值最小的边,并将该边相关联的节点出列; c)重复b)直到所有的节点出列。2)克鲁斯卡尔(Kruskal)算法思想 为了使生成树上总的权值之和最小,应该使每一条边上的权值尽可能的小,所以应从权值最小的边选起,直至选出n-1条不能构成回路的权值最小的边位置。 具体做法如下:首先构造一个含n个顶点的森林,然后按权值从小到大从连通图中选择不使森林中产生回路的边加入到森林中去,直至该森林变成一棵树为止,这棵树便是连通图的最小生成树。 由于生成树上不允许有回路,因此并非每一条居当前最小的边都可选。从生成树的构造过程可见,初始态为n个顶点分属n棵树,互不连通,每加入一条边,就将两棵树合并为一棵树,在同一棵树上的两个顶点之间自然相连通,由此判别当前权值最小边是否可取只要判别它的两个顶点是否在同一棵树上即可。 2.系统采用的数据结构和算法 1)数据结构 Typedef int Vertextype;Typedef int adimatrix[MaxVertexNum][MaxVertexNum];Typedef int Vertextype vexlist[MaxVertexNum];Typedef int VexType; 数据结构课程设计报告 最小生成树 1.Great_adjmatrix()和Great_adjmatrix2()是两种建立图的方法; 2.克鲁斯卡尔算法(Kruskal): Void kruskal(GraphMatrix * pgraph,Edge mst[]){int i,j,min,vx,vy;int weight,minweight;Edge edge;for(i=0;i n-1;i++){mst[i].start_vex = 0;Mst[i].stop_vex = i+1;Mst[i].weight = pgraph->arcs[0][i+1];} for(i=0;i n-1;i++)//共n-1条边 {minweight = MAX;min = i;for(j=i;j n-1;j++)//从所有(vx,vy)(vx∈U,vy∈V-U)中选出最短的边 if(mst[j].weight for(j=i+1;j n-1;j++) 数据结构课程设计报告 最小生成树 j=MST[k-1].endvex;//定位于权值最小边的尾顶点 for(i=k;i 4.out_edgeset()功能为显示最小生成树。 四、用户手册 1.运行程序,得到如下窗口: 2.输入顶点数,选择算法: 1)当输入的顶点数小于10时,选择Kruskal算法,如下图 数据结构课程设计报告 最小生成树 五、总结 该程序实现了在n个城市之间建设网络,既保证了连通性,也成为了最经济的架设方法。程序中应用了普里姆算法和克鲁斯卡尔算法,实现了矩阵的输出以及最小生成树的输出。不过,该程序仍有不足之处,图的输入数据过大,易出错,不易返回,仍需完善。 六、参考文献 [1]《数据结构程序设计题典》 李春葆编 清华大学出版社 [2]《数据结构(C语言版)》 严蔚敏 吴伟民编 清华大学出版社 [3]《数据结构课程设计》 苏仕华编 机械工业出版社 七、附录:(源代码) #include 数据结构课程设计报告 最小生成树 { scanf(“%d%d%d”,&i,&j,&w);GA[i][j]=GA[j][i]=w;//对称 } } void Creat_adjmatrix2(vexlist GV,adjmatrix GA,int m,int e,GraphMatrix &graph){ int i,j,k,w,x,y; printf(“输入%d个顶点序号(0-m-1),序号从0开始。”,m);for(i=0;i GA[i][j]=MaxValue;printf(“请输入有多少条边。n”);scanf(“%d”,&e);printf(“输入%d条无向带权边(序号 序号 权值):n”,e);for(k=0;k 数据结构课程设计报告 最小生成树 /* mst[min]是最短的边(vx,vy)(vx∈U, vy∈V-U),将mst[min]加入最小生成树 */ edge = mst[min];mst[min] = mst[i];mst[i] = edge;vx = mst[i].stop_vex;/* vx为刚加入最小生成树的顶点的下标 */ for(j = i+1;j < pgraph->n-1;j++){ /* 调整mst[i+1]到mst[n-1] */ vy=mst[j].stop_vex;weight = pgraph->arcs[vx][vy];if(weight < mst[j].weight){ mst[j].weight = weight;mst[j].start_vex = vx;} } } } void out_edgeset(edgeset MST,int e)//显示最小生成树 { int k;printf(“最小的消耗路线为n”);for(k=0;k printf(“(%d %d %d)n”,MST[k].fromvex,MST[k].endvex,MST[k].weight);} void prim(adjmatrix GA,edgeset MST,int n)//利用prim算法从0点出发求图的最小生成树 数据结构课程设计报告 最小生成树 int a;system(“color 71”);//改变屏幕颜色 printf(“ ┏━━━━━━━━━━━━━━━━━━━━━━━━━┓n”);printf(“ ┃㊣ 必做题:最小生成树 ㊣┃n”);printf(“ ┃ 姓名:xxxx ┃n”);printf(“ ┃ 学号:xxxxxxxxx ┃n”);printf(“ ┗━━━━━━━━━━━━━━━━━━━━━━━━━┛n”);vexlist GV;//顶点表 adjmatrix GA;//边表 edgeset MST;//最小生成树 do{ printf(“输入图的顶点数n,我们将根据您输入的数据大小选择合适的算法。n”);scanf(“%d”,&n);if(n>=10)//大于10用prim算法来实现,否则kruskal算法来实现 { printf(“用prim算法从0点出发求图的最小生成树为:n”);printf(“请输入图的边数。n”);canf(“%d”,&e);Creat_adjmatrix(GV, GA, n, e);//创建图 prim(GA,MST,n);//生成最小生成树 out_edgeset(MST, n-1);//输出最小生成树 } else{ printf(“用kcuskal算法的最小生成树为:n”);GraphMatrix graph;//定义一个结构体来表示存储结构 Creat_adjmatrix2(GV,GA,n,e,graph);//创建图 kruskal(&graph,mst);//生成最小生成树 rintf(“最小的消耗路线为n”);for(i = 0;i < graph.n-1;i++) 注意:实验结束后提交一份实验报告电子文档 电子文档命名为“学号+姓名”,如:E01214058宋思怡 《数据结构》实验报告 (一)学号:姓名:专业年级: 实验名称:线性表 实验日期:2014年4月14日 实验目的: 1、熟悉线性表的定义及其顺序和链式存储结构; 2、熟练掌握线性表在顺序存储结构上实现基本操作的方法; 3、熟练掌握在各种链表结构中实现线性表基本操作的方法; 4、掌握用 C/C++语言调试程序的基本方法。 实验内容: 一、编写程序实现顺序表的各种基本运算,并在此基础上设计一个主程序完成如下功能: (1)初始化顺序表L; (2)依次在L尾部插入元素-1,21,13,24,8; (3)输出顺序表L; (4)输出顺序表L长度; (5)判断顺序表L是否为空; (6)输出顺序表L的第3个元素; (7)输出元素24的位置; (8)在L的第4个元素前插入元素0; (9)输出顺序表L; (10)删除L的第5个元素; (11)输出顺序表L。 源代码 调试分析(给出运行结果界面) 二、编写程序实现单链表的各种基本运算,并在此基础上设计一个主程序完成如下功能: „„„„ „„„„ 小结或讨论: (1)实验中遇到的问题和解决方法 (2)实验中没有解决的问题 (3)体会和提高 南京信息工程大学实验(实习)报告 实验(实习)名称数据结构实验(实习)日期 2011-11-2得分指导教师周素萍 系公共管理系专业信息管理与信息系统年级10级班次1姓名常玲学号2010230700 3实验一顺序表的基本操作及C语言实现 【实验目的】 1、顺序表的基本操作及 C 语言实现 【实验要求】 1、用 C 语言建立自己的线性表结构的程序库,实现顺序表的基本操作。 2、对线性表表示的集合,集合数据由用户从键盘输入(数据类型为整型),建立相应的顺序表,且使得数据按从小到大的顺序存放,将两个集合的并的结果存储在一个新的线性表集合中,并输出。 【实验内容】 1、根据教材定义的顺序表机构,用 C 语言实现顺序表结构的创建、插入、删除、查找等操作; 2、利用上述顺序表操作实现如下程序:建立两个顺序表表示的集合(集合中无重 复的元素),并求这样的两个集合的并。 【实验结果】 [实验数据、结果、遇到的问题及解决] 一. Status InsertOrderList(SqList &va,ElemType x) { } 二. Status DeleteK(SqList &a,int i,int k) {//在非递减的顺序表va中插入元素x并使其仍成为顺序表的算法 int i;if(va.length==va.listsize)return(OVERFLOW);for(i=va.length;i>0,x } //注意i的编号从0开始 int j;if(i<0||i>a.length-1||k<0||k>a.length-i)return INFEASIBLE;for(j=0;j<=k;j++)a.elem[j+i]=a.elem[j+i+k];a.length=a.length-k;return OK; 三.// 将合并逆置后的结果放在C表中,并删除B表 Status ListMergeOppose_L(LinkList &A,LinkList &B,LinkList &C) { LinkList pa,pb,qa,qb;pa=A;pb=B;qa=pa;qb=pb;// 保存pa的前驱指针 // 保存pb的前驱指针 pa=pa->next;pb=pb->next;A->next=NULL;C=A;while(pa&&pb){} while(pa){} qa=pa;pa=pa->next;qa->next=A->next;A->next=qa;if(pa->data data){} else{} qb=pb;pb=pb->next;qb->next=A->next;//将当前最小结点插入A表表头 A->next=qb;qa=pa;pa=pa->next;qa->next=A->next;//将当前最小结点插入A表表头 A->next=qa; } } pb=B;free(pb);return OK;qb=pb;pb=pb->next;qb->next=A->next;A->next=qb; 顺序表就是把线性表的元素存储在数组中,元素之间的关系直接通过相邻元素的位置来表达。 优点:简单,数据元素的提取速度快; 缺点:(1)静态存储,无法预知问题规模的大小,可能空间不足,或浪费存储空间;(2)插入元素和删除元素时间复杂度高——O(n) 求两个集合的并集 该算法是求两个集合s1和s2的并集,并将结果存入s引用参数所表示的集合中带回。首先把s1集合复制到s中,然后把s2中的每个元素依次插入到集合s中,当然重复的元素不应该被插入,最后在s中就得到了s1和s2的并集,也就是在s所对应的实际参数集合中得到并集。 数据结构实验报告 一. 题目要求 1)编程实现二叉排序树,包括生成、插入,删除; 2)对二叉排序树进行先根、中根、和后根非递归遍历; 3)每次对树的修改操作和遍历操作的显示结果都需要在屏幕上用树的形状表示出来。4)分别用二叉排序树和数组去存储一个班(50人以上)的成员信息(至少包括学号、姓名、成绩3项),对比查找效率,并说明在什么情况下二叉排序树效率高,为什么? 二. 解决方案 对于前三个题目要求,我们用一个程序实现代码如下 #include typedefintElemType; //数据类型 typedefint Status; //返回值类型 //定义二叉树结构 typedefstructBiTNode{ ElemType data; structBiTNode *lChild, *rChild;//左右子树域 }BiTNode, *BiTree;intInsertBST(BiTree&T,int key){//插入二叉树函数 if(T==NULL){ T =(BiTree)malloc(sizeof(BiTNode)); T->data=key; T->lChild=T->rChild=NULL; return 1;} else if(key InsertBST(T->rChild,key);} else return 0;} BiTreeCreateBST(int a[],int n){//创建二叉树函数 BiTreebst=NULL;inti=0;while(i //数据域 InsertBST(bst,a[i]); i++;} returnbst;} int Delete(BiTree&T) { BiTreeq,s; } if(!(T)->rChild){ //右子树为空重接它的左子树 q=T;T=(T)->lChild;free(q);}else{ if(!(T)->lChild){ //若左子树空则重新接它的右子树 q=T;T=(T)->rChild;}else{ q=T;s=(T)->lChild;while(s->rChild){ q=s;s=s->rChild;} (T)->data=s->data;//s指向被删除结点的前驱 if(q!=T) q->rChild=s->lChild; else q->lChild=s->lChild; free(s);} } return 1; //删除函数,在T中删除key元素 intDeleteBST(BiTree&T,int key){ if(!T)return 0;else{ if(key==(T)->data)return Delete(T); else{ if(key<(T)->data) returnDeleteBST(T->lChild,key); else returnDeleteBST(T->rChild,key); } } } intPosttreeDepth(BiTree T){//求深度 inthr,hl,max;if(!T==NULL){ hl=PosttreeDepth(T->lChild);hr=PosttreeDepth(T->rChild);max=hl>hr?hl:hr;return max+1;} else return 0; } void printtree(BiTreeT,intnlayer){//打印二叉树 if(T==NULL)return;printtree(T->rChild,nlayer+1);for(inti=0;i ”);} printf(“%dn”,T->data);printtree(T->lChild,nlayer+1);} void PreOrderNoRec(BiTree root)//先序非递归遍历 { BiTree p=root;BiTreestack[50];intnum=0;while(NULL!=p||num>0){ while(NULL!=p) { printf(“%d ”,p->data); stack[num++]=p; p=p->lChild; } num--; p=stack[num]; p=p->rChild;} printf(“n”);} void InOrderNoRec(BiTree root)//中序非递归遍历 { BiTree p=root; } intnum=0;BiTreestack[50];while(NULL!=p||num>0){ while(NULL!=p){ stack[num++]=p; p=p->lChild;} num--;p=stack[num];printf(“%d ”,p->data);p=p->rChild;} printf(“n”);void PostOrderNoRec(BiTree root)//后序非递归遍历 { BiTree p=root;BiTreestack[50];intnum=0;BiTreehave_visited=NULL; while(NULL!=p||num>0){ while(NULL!=p) { stack[num++]=p; p=p->lChild; } p=stack[num-1]; if(NULL==p->rChild||have_visited==p->rChild) { printf(“%d ”,p->data); num--; have_visited=p; p=NULL; } else { p=p->rChild; } } printf(“n”);} int main(){//主函数 printf(“ ---------------------二叉排序树的实现-------------------”);printf(“n”);int layer;inti;intnum;printf(“输入节点个数:”);scanf(“%d”,&num);printf(“依次输入这些整数(要不相等)”);int *arr=(int*)malloc(num*sizeof(int));for(i=0;i scanf(“%d”,arr+i);} BiTreebst=CreateBST(arr,num);printf(“n”);printf(“二叉树创建成功!”);printf(“n”);layer=PosttreeDepth(bst);printf(“树状图为:n”);printtree(bst,layer);int j;int T;int K;for(;;){ loop: printf(“n”);printf(“ ***********************按提示输入操作符************************:”);printf(“n”);printf(“ 1:插入节点 2:删除节点 3:打印二叉树 4:非递归遍历二叉树 5:退出”);scanf(“%d”,&j); switch(j){ case 1: printf(“输入要插入的节点:”); scanf(“%d”,&T); InsertBST(bst,T); printf(“插入成功!”);printf(“树状图为:n”); printtree(bst,layer); break; case 2: } printf(“输入要删除的节点”);scanf(“%d”,&K);DeleteBST(bst,K);printf(“删除成功!”);printf(“树状图为:n”);printtree(bst,layer);break;case 3: layer=PosttreeDepth(bst);printtree(bst,layer);break;case 4: printf(“非递归遍历二叉树”);printf(“先序遍历:n”);PreOrderNoRec(bst);printf(“中序遍历:n”);InOrderNoRec(bst); printf(“后序遍历:n”); PostOrderNoRec(bst); printf(“树状图为:n”); printtree(bst,layer); break;case 5: printf(“程序执行完毕!”); return 0;} goto loop;} return 0;对于第四小问,要储存学生的三个信息,需要把上面程序修改一下,二叉树结构变为 typedefintElemType; //数据类型 typedefstring SlemType; typedefint Status; //返回值类型 //定义二叉树结构 typedefstructBiTNode{ SlemType name;ElemType score;ElemType no; //数据域 structBiTNode *lChild, *rChild;//左右子树域 }BiTNode, *BiTree;参数不是key,而是另外三个 intInsertBST(BiTree&T,intno,intscore,string name){//插入二叉树函数 if(T==NULL){ T =(BiTree)malloc(sizeof(BiTNode)); T->no=no;T->name=name;T->score=score; T->lChild=T->rChild=NULL; return 1;} else if(no InsertBST(T->rChild,no,score,name);} else return 0;} 其他含参函数也类似 即可完成50个信息存储 用数组存储50个信息,查看以往代码 #include int main(){ cout<<“ 欢迎来到学生管理系统”< cout<<“该学号信息已经存在,添加失败”< break;} cout<<“重新输入添加的学号”< for(int n=m+1;n<20;n++){ if(ptr[m].average() student a; a=ptr[m]; ptr[m]=ptr[n]; ptr[n]=a; }} ptr[m].show();} break;case 4: cout<<“谢谢使用”< 二叉排序树储存数据界面(储存学生信息略) 创建二叉树: 插入节点: 删除节点: 非递归遍历: 退出: 数组储存学生信息界面 分析查找效率: 因为二叉树查找要创建二叉树,而数组查找只创建一个数组,二叉树的创建时间比较长,所以对于数据量较少的情况下数组的查找效率比较高。但当数据量增加时,二叉树的查找优势就显现出来。所以数据量越大的时候,二叉树的查找效率越高。 四. 总结与改进 这个实验工作量还是很大的,做了很久。树状图形输出还是不美观,还需要改进。 一开始打算用栈实现非递归,但是根据书里面的伪代码发现部分是在C++编译器里运行不了的(即使补充了头文件和数据的定义),所以之后参考了网上的数组非递归,发现其功能和栈相似。 递归遍历的实现比非递归的遍历真的简单很多。 开始时只看到前三问,所以没有写到储存学生数据的代码,里面还可以用clock()函数加一个计算查找所要数据时间的代码,让二叉树查找与数组查找到效率比较更加直观。第二篇:数据结构课程设计-最小生成树
第三篇:数据结构实验报告
第四篇:数据结构实验报告
第五篇:数据结构实验报告