数据结构实验五矩阵的压缩存储与运算学习资料
数据结构实验五矩阵的压缩存储与运算
第五章矩阵的压缩存储与运算
【实验目的】
1. 熟练掌握稀疏矩阵的两种存储结构(三元组表和十字链表)的实现;
2. 掌握稀疏矩阵的加法、转置、乘法等基本运算;
3. 加深对线性表的顺序存储和链式结构的理解。
第一节知识准备
矩阵是由两个关系(行关系和列关系)组成的二维数组,因此对每一个关系上都可以用线性表进行处理;考虑到两个关系的先后,在存储上就有按行优先和按列优先两种存储方式,所谓按行优先,是指将矩阵的每一行看成一个元素进行存储;所谓按列优先,是指将矩阵的每一列看成一个元素进行存储;这是矩阵在计算机中用一个连续存储区域存放的一般情形,对特殊矩阵还有特殊的存储方式。
一、特殊矩阵的压缩存储
1. 对称矩阵和上、下三角阵
若n阶矩阵A中的元素满足= (0≤i,j≤n-1 )则称为n阶对称矩阵。对n阶对称矩阵,我们只需要存储下三角元素就可以了。事实上对上三角矩阵(下三角部分为零)和下三角矩阵(上三角部分为零),都可以用一维数组ma[0.. ]来存储A的下三角元素(对上三角矩阵做转置存储),称ma为矩阵A的压缩存储结构,现在我们来分析以下,A和ma之间的元素对应放置关系。
问题已经转化为:已知二维矩阵A[i,j],如图5-1,
我们将A用一个一维数组ma[k]来存储,它们之间存在着如图5-2所示的一一对应关系。
任意一组下标(i,j)都可在ma中的位置k中找到元素m[k]= ;这里:
k=i(i+1)/2+j (i≥j)
图5-1 下三角矩阵
a00 a10 a11 a20 … an-1,0 … an-1,n-1
k= 0 1 2 3 …n(n-
1)/2 …n(n+1)/2-1
图5-2下三角矩阵的压缩存储
反之,对所有的k=0,1,2,…,n(n+1)/2-1,都能确定ma[k]中的元素在矩阵A中的位置(i,j)。这里,i=d-1,(d是使sum= > k的最小整数),j= 。
2. 三对角矩阵
在三对角矩阵中,所有的非零元素集中在以主对角线为中心的带内状区域中,除了主对角线上和直接在对角线上、下方对角线上的元素之外,所有其它的元素皆为零,见图5-3。
图5-3 三对角矩阵A
与下三角矩阵的存储一样,我们也可以用一个一维数组ma[0..3n-2]来存放三对角矩阵A,其对应关系见图5-4。
a00 a01 a10 a11 a12 … an-1,n-2 an-1,n-1
k= 0 1 2 3 4 …
3n-3 3n-2
图5-4下三角矩阵的压缩存储
A中的一对下标(i,j)与ma中的下标k之间有如下的关系:
公式中采用了C语言的符号,int()表示取整,‘%’表示求余。
二、稀疏矩阵
在m×n的矩阵中,有t个非零元。令δ=,称δ矩阵的稀疏因子,常认为δ≤0.05时称为稀疏矩阵。稀疏矩阵在工程中有着大量的应用,不少工程问题都可以转化为对稀疏矩阵的计算问题。如何进行稀疏矩阵的压缩存储呢?
为节省存储空间,应只存储非零元素。除了存储非零元的值之外,还必须记下所在行和列的位置
(i,j),即一个三元组(i,j, )唯一确定了矩阵A的一个非零元素。
1. 三元组顺序表
以顺序存储结构来表示三元组表,则可称稀疏矩阵的一种压缩存储方式。
//稀疏矩阵的三元组顺序表存储表示。
#define MaxSize 10 //用户自定义
typedef int Datatype; //用户自定义
typedef struct{ //定义三元组
int i; //非零元的行下标
int j; //非零元的列下标
Datatype v; //非零元的数据值
}TriTupleNode;
typedef struct{
TriTupleNode data[MaxSize]; //非零元的三元组表
int m,n,t; //矩阵行,列及三元组表长度
}TriTupleTable;
2. 十字链表
当矩阵的非零元个数和位置在操作过程中变化较大时,就不宜采用顺序存储结构来表示三元组的线性表,采用纵横交叉的十字链表就比较好。
在十字链表中,每个非零元可用一个含五个域的结点表示,其中i, j和e三个域分别表示该非零元所在的行、列和非零元的值,向右域right用以链接同一行中下一个非零元。向下域down用以链接同一列中下一个非零元。同一行中的非零元通过right域链接成一个线性链表,每个非零元既是某个行链表中的一个结点,又是某个列链表中的一个结点,整个矩阵构成了一个十字交叉的链表,故称这样的存储结构为十字链表,如图5-5所示。
图5-5 稀疏矩阵M的十字链表
typedef int Datatype; //用户自定义
typedef struct OLNode{
int i,j; //该非零元的行和列下标
Datatype v;
Struct OLNode *right,*down //该非零元所在行表和列表的后继链域
}OLNode;*OLink;
typedef struct {
OLink *rhead,*chead
int mu,nu,tu;
}CrossList;
第二节用三元组表实现稀疏矩阵的基本操作
【问题描述】用三元组表实现稀疏矩阵的按列转置。
【数据描述】
typedef int Datatype; //用户自定义
typedef struct
{ //定义三元组
int i,j; // 非零元素的行下标和列下标
Datatype v;
}TriTupleNode;
typedef struct{ //定义三元组表
TriTupleNode data[MaxSize];
int m,n,t; //矩阵行,列及三元组表长度
}TriTupleTable;
【算法描述】
按照列序来进行转置。为了找到每一列中所有的非零元素,需要对其三元组表从第一行起整个扫描一遍。Status TransposeSMatrix(TriTupleTable a, TriTupleTable &b){
b.m=a.n;b.n=a.m;b.t=a.t;
if(b.t){
q=0;
for(col=1;col<=a.n;++col)
for(p=0;p<=a..t;++p)
if(a.data[p].j==col){
b.data[q].i=a.data[p].j;b.data[q].j=a.data[p].i;
b.data[q].v=a.data[p].v;++q;}
}
return OK;
}
【C源程序】
#include
#include
#define Ok 1
#define Maxsize 10 //用户自定义三元组最大长度typedef struct{ /*定义三元组表*/
int i,j;
int v;
}TriTupleNode;
typedef struct{ /*定义三元组表*/ TriTupleNode data[Maxsize];
int m;
int n;
int t; /*矩阵行,列及三元组表长度*/
}TriTupleTable;
void InitTriTupleNode (TriTupleTable *a){ /*输入三元组表*/ int i,j,k,val,maxrow,maxcol;
char contiue;
maxrow=0;
maxcol=0;
i=j=0;
k=0;
while(i!=-1&&j!=-1){ /*rol=-1&&col=-1结束输入*/
printf("input row \n");
scanf("%d",&i);
printf("input col \n");
scanf("%d",&j);
printf("input value\n");
scanf("%d",&val);
a->data[k].i=i;
a->data[k].j=j;
a->data[k].v=val;
if (maxrow
if (maxcol k++; } a->m=maxrow;a->n=maxcol;a->t=k-1; } void showMatrix(TriTupleTable *a){ /*输出稀疏矩阵*/ int p,q; int t=0; for(p=1;p<=a->m;p++) {for(q=1;q<=a->n;q++) { if (a->data[t].i==p&&a->data[t].j==q) {printf("%d ",a->data[t].v); t++; } else printf("0 "); } printf("\n" ); } } TransposeSMatrix(TriTupleTable *a,TriTupleTable *b) {int q,col,p; b->m=a->n;b->n=a->m;b->t=a->t; if(b->t) {q=0; for(col=1;col<=a->n;++col) for(p=0;p if(a->data[p].j==col) { b->data[q].i=a->data[p].j; b->data[q].j=a->data[p].i; b->data[q].v=a->data[p].v;++q; } } } void main( void) {TriTupleTable *a,*b; InitTriTupleNode(a); showMatrix(a); /*转置前*/ TransposeSMatrix(a,b); showMatrix(b); /*转置后*/ } 【测试数据】 输入:输出: 1 2 0 0 1 4 0 4 3 0 7 2 3 0 0 0 0 8 0 0 0 0 7 8 【说明】 分析算法,主要的工作是在p和col的两重循环中完成,算法的时间复杂度为O(n*t)。如果非零元素个数t和m*n同数量级时,算法的时间复杂度变为O(m*n2)。 【实验题】 1. 稀疏矩阵按行序进行转置。 2. 两个稀疏矩阵的相加运算。 第三节十字链表表示稀疏矩阵的基本操作 【问题描述】两个相同行数和列数的稀疏矩阵用十字链表实现加法运算 【数据描述】 typedef struct ele {/* 十字链表结点类型*/ int row, col; double val; struct ele *right, *down; }eleNode; 【算法描述】 (1) 若q->j>v->j,则需要在C矩阵的链表中插入一个值为bij的结点,,修改v=v->right。 (2) 如q->j (3) 若q->j = = v->j且q->e + v->e ! = 0,则需要在C矩阵的链表中插入一个值为aij+bij 的结点,修改q=q->right,v=v->right。 重复(1)--(3)完成一行的操作。修改p=p->down,u=u->down后,再继续下一行。【C源程序】 #include #include typedef struct ele {/* 十字链表结点类型*/ int row,col; int val; struct ele *right,*down; }eleNode; /*建立一个元素全为零的稀疏矩阵的十字链表*/ eleNode *createNullMat(int m,int n) / * m行n列*/ {eleNode *h,*p; int k; h=(eleNode *)malloc(sizeof(eleNode)); /*十字链表头结点*/ h->row=m;h->col=n;h->val=0; / * 行数、列数和非零元素个数*/ h->right=(eleNode *)malloc(sizeof(eleNode)*n); h->down=(eleNode *)malloc(sizeof(eleNode)*m); for(p=h->down,k=0;k p->col=1000; / * 设矩阵不会超过1000列*/ p->right=p; / * 每个行链表是一个环* / p->down=k } for(p=h->right,k=0;k p->row=1000; / * 设矩阵不会超过1000行* / p->down = p; / * 每个列链表是一个环* / p->right = k<n-1 ? p+1 : h->right; / *使全部列链表头结点构成环* / } return h; } // int insertNode(eleNode *a ,int row,int col,double val){ /* 在十字链表中插入一个结点*/ eleNode *p,*q,*r,*u,*v; if(row>=a->row||col>=a->col) return -2; / * 不合理的行列号* / r=(eleNode *)malloc(sizeof(eleNode)); r->row=row;r->col=col;r->val=val; p=a->down+row;q=p->right; while(q->col if(q->col==col) return -1; / * 该行已有col列元素* / u=a->right+col;v=u->down; while(v->row if(v->row==row) return -1; / * 该列已有row行元素* / p->right = r; r->right = q; / * 插入到行链中* / u->down = r; r->down = v; / * 插入到列链中* / a->val=val; return 0; / * 插入成功* / } eleNode *readMat(){ /*输入数据建立十字链表*/ eleNode *h; int i,j,m,n; int v; printf("输入稀疏矩阵的行数和列数"); scanf("%d%d",&m,&n); h=createNullMat(m,n); printf("输入有非零元素的行号"); scanf("%d",&i); while(i>=0) / * 逐行输入非零元素* / { printf("输入非零元素的列号"); scanf("%d",&j); while(j>=0) / * 输入一行非零元素* / { printf("输入非零元素的值"); scanf("%d",&v); insertNode(h,i,j,v); printf("输入当前行下一个非零元素的列号(-1表示当前行一组数据结束)");scanf("%d",&j); } printf("输入下一行有非零元素的行号(-1表示输入结束)"); scanf("%d",&i); } return h; } void showMat(eleNode *a) {int row,col,i,j; eleNode *p; row=a->row; col=a->col; for (i=0;i { p=a->down+i; p=p->right; for(j=0;j { if(p->row==i&&p->col==j) {printf("%d ",p->val);p=p->right;} else printf("0 "); } printf("\n"); } } eleNode *matAdd(eleNode *a,eleNode *b) {eleNode *r,*p,*q,*u,*v; r=createNullMat(a->row,a->col); p=a->down;u=b->down; do { / * 逐行相加* / q=p->right;v=u->right; while(q!=p||v!=u) / * 两矩阵中有一个一行未结束循环*/ if(q->col==v->col){ / * 有相同列的元素* / if(q->val+v->val!=0) / * 和非零插入* / insertNode(r,q->row,q->col,q->val+v->val); q=q->right;v=v->right; } else if(q->col insertNode(r,q->row,q->col,q->val); q=q->right; } else{ / * 插入b的元素* / insertNode(r,v->row,v->col,v->val); v=v->right; } p=p->down;u=u->down; }while(p!=a->down); return r; } void main() { eleNode *a,*b,*c; a=readMat(); printf("a\n"); showMat(a); b=readMat(); printf("b\n"); showMat(b); c= matAdd(a,b); printf("c\n"); showMat(c); } 【测试数据】 输入a 矩阵: 4 0 0 0 输入b矩阵: 0 1 0 1 输出:4 1 0 1 0 5 0 9 0 – 5 0 0 0 0 0 9 0 0 1 0 1 0 9 0 1 0 10 0 输入数据注意事项: (1)如上面a矩阵,应输入3行4列 (2)若某行有非零元素,则按下列格式(三元组格式)输入: 行号列号值列号值…列号值-1,如a矩阵的第0行,应输入 0 0 4 -1,最后的-1表示该行的一组数据输入结束。 (3)按以上格式逐行地输入数据,直到输入的行号的值为-1时,表示稀疏矩阵的全部数据输入结束。 【说明】 从一个结点来看,进行比较、修改指针所需的时间是一个常数;整个运算过程在于对A和B的十字链表逐行扫描,其循环次数主要取决于A和B矩阵中非零元素的个数ta和tb;由此算法的时间复杂度为 O(ta+tb)。 【实验题】 1. 设矩阵采用十字链表存结构,试编写下列程序实现下列运算: del(hm,i,j,x) 删除第i行第j列的结点。 revise(hm,i,j) 修改第i行第j列的结点的数据值。 2. 上述例子采用的是新开辟c十字链表存放a矩阵和b矩阵之和,试用a存放a矩阵和b矩阵之和,改写上述例子。 第四节思考题 1. 假设稀疏矩阵A的大小是m×n,稀疏矩阵B的大小是n×1(一维向量),A和B均采用三元组表示,编程实现C=A×B,其结果C也采用三元组表形式输出。 【简要分析】本题的关键是要确定i行j列的元素在三元组表中的位置,由于B是一个一维向量,在用三元组表进行矩阵相乘时并不方便,可以先将B做转置存放后,一遍扫描A就可以实现乘法。 2.如果矩阵A中存在这样的一个元素A[i][j]满足以下条件:A[i][j]是第i行中值最小的元素,且又是第j列中值最大的元素,则称A[i][j]为矩阵A的一个鞍点;假设稀疏矩阵A(大小是m×n)已经用三元组表存放,编程实现求鞍点的算法,如果没有鞍点,也给出相应信息。 【简要分析】如果A采用二维数组存放,本题的解法是很容易的,只需要求出每行的最小元素,放入 min[0..m-1]中,再求出每列的最大元,放入max[0..n-1]之中,如果某元素A[i][j],既在min[i]中,又在max[j]中,则A[i][j]必是鞍点。对三元组存放的A,在求max数组时会有一些困难,可参考教材,增设一个cpot数组和一个num数组,用来记录A的列元素。 Chapter Five Compressed storage for Matrix and its algorithms Objectives 1. To understand implementation of two structures of sparse matrix, For example, Triple _Tuple_Table and Cross-List. 2. To understand basic computation of addition, transformation, and multiplication for s parse matrix. 数据结构实验指导书 一、实验目的 《数据结构》是计算机学科一门重要的专业基础课程,也是计算机学科的一门核心课程。本课程较为系统地论述了软件设计中常用的数据结构以及相应的存储结构与实现算法,并做了相应的性能分析和比较,课程内容丰富,理论系统。本课程的学习将为后续课程的学习以及软件设计水平的提高打下良好的基础。 由于以下原因,使得掌握这门课程具有较大的难度: 1)理论艰深,方法灵活,给学习带来困难; 2)内容丰富,涉及的知识较多,学习有一定的难度; 3)侧重于知识的实际应用,要求学生有较好的思维以及较强的分析和解决问题的能力,因而加大了学习的难度; 根据《数据结构》课程本身的特性,通过实验实践内容的训练,突出构造性思维训练的特征,目的是提高学生分析问题,组织数据及设计大型软件的能力。 课程上机实验的目的,不仅仅是验证教材和讲课的内容,检查自己所编的程序是否正确,课程安排的上机实验的目的可以概括为如下几个方面: (1)加深对课堂讲授内容的理解 实验是对学生的一种全面综合训练。是与课堂听讲、自学和练习相辅相成的必不可少的一个教学环节。通常,实验题中的问题比平时的习题复杂得多,也更接近实际。实验着眼于原理与应用的结合点,使学生学会如何把书上学到的知识用于解决实际问题,培养软件工作所需要的动手能力;另一方面,能使书上的知识变" 活" ,起到深化理解和灵活掌握教学内容的目的。 不少学生在解答习题尤其是算法设计时,觉得无从下手。实验中的内容和教科书的内容是密切相关的,解决题目要求所需的各种技术大多可从教科书中找到,只不过其出 现的形式呈多样化,因此需要仔细体会,在反复实践的过程中才能掌握。 (2) 培养学生软件设计的综合能力 平时的练习较偏重于如何编写功能单一的" 小" 算法,而实验题是软件设计的综合训练,包括问题分析、总体结构设计、用户界面设计、程序设计基本技能和技巧,多人合作,以至一整套软件工作规范的训练和科学作风的培养。 通过实验使学生不仅能够深化理解教学内容,进一步提高灵活运用数据结构、算法和程序设计技术的能力,而且可以在需求分析、总体结构设计、算法设计、程序设计、上机操作及程序调试等基本技能方面受到综合训练。实验着眼于原理与应用的结合点,使学生学会如何把书本上和课堂上学到的知识用于解决实际问题,从而培养计算机软件工作所需要的动手能力。 (3) 熟悉程序开发环境,学习上机调试程序一个程序从编辑,编译,连接到运行,都要在一定的外部操作环境下才能进行。所谓" 环境" 就是所用的计算机系统硬件,软件条件,只有学会使用这些环境,才能进行 程序开发工作。通过上机实验,熟练地掌握程序的开发环境,为以后真正编写计算机程序解决实际问题打下基础。同时,在今后遇到其它开发环境时就会触类旁通,很快掌握新系统的使用。 完成程序的编写,决不意味着万事大吉。你认为万无一失的程序,实际上机运行时可能不断出现麻烦。如编译程序检测出一大堆语法错误。有时程序本身不存在语法错误,也能够顺利运行,但是运行结果显然是错误的。开发环境所提供的编译系统无法发现这种程序逻辑错误,只能靠自己的上机经验分析判断错误所在。程序的调试是一个技巧性很强的工作,尽快掌握程序调试方法是非常重要的。分析问题,选择算法,编好程序,只能说完成一半工作,另一半工作就是调试程序,运行程序并得到正确结果。 二、实验要求 常用的软件开发方法,是将软件开发过程划分为分析、设计、实现和维护四个阶段。虽然数据结构课程中的实验题目的远不如从实际问题中的复杂程度度高,但为了培养一个软件工作者所应具备的科学工作的方法和作风,也应遵循以下五个步骤来完成实验题目: 1) 问题分析和任务定义 在进行设计之前,首先应该充分地分析和理解问题,明确问题要求做什么?限制条件是什么。本步骤强调的是做什么?而不是怎么做。对问题的描述应避开算法和所涉及的数据类型,而是对所需完成的任务作出明确的回答。例如:输入数据的类型、值的范围以及输入的 暨南大学本科实验报告专用纸 课程名称数据结构实验成绩评定 实验项目名称习题6.37 6.38 6.39 指导教师孙世良 实验项目编号实验8 实验项目类型实验地点实验楼三楼机房学生姓名林炜哲学号2013053005 学院电气信息学院系专业软件工程 实验时间年月日午~月日午温度℃湿度(一)实验目的 熟悉和理解二叉树的结构特性; 熟悉二叉树的各种存储结构的特点及适用范围; 掌握遍历二叉树的各种操作及其实现方式。 理解二叉树线索化的实质是建立结点与其在相应序列中的前去或后继之间的直接联系,熟练掌握二叉树的线索化的过程以及在中序线索化树上找给定结点的前驱和后继的方法。 (二)实验内容和要求 6.37试利用栈的基本操作写出先序遍历的非递归形式的算法。 6.38同题6.37条件,写出后序遍历的非递归算法(提示:为分辨后序遍 历时两次进栈的不同返回点需在指针进栈时同时将一个标志进栈)。 6.39假设在二叉链表的结点中增设两个域:双亲域以指示其双亲结点; 标志域以区分在遍历过程中到达该结点时应继续向左或向右或访问该节点。试以此存储结构编写不用栈进行后序遍历的递推形式的算法。(三)主要仪器设备 实验环境:Microsoft Visual Studio 2012 (四)源程序 6.37: #include 第四章串 一.选择题 1.若串S='software',其子串的数目是() A.8 B.37 C.36 D.9 2.设有两个串p和q,求q在p中首次出现的位置的运算称作() A.连接B.模式匹配C.求串长D.求子串 3.设字符串S1=“ABCDEFG”,S2=“PQRST”,则运算: S=CONCAT(SUBSTR(S1,2,LEN(S2));SUBSTR(S1,LEN(S2),2));后的串值为() A.A BCDEF B.BCDEFG C.BCDPQRST D. BCDEFEF 4.下面的说法中,只有()是正确的 A.串是一种特殊的线性表B.串的长度必须大于零 C.串中元素只能是字母D.空串就是空白串 5.两个字符串相等的条件是() A.两串的长度相等 B.两串包含的字符相同 C.两串的长度相等,并且两串包含的字符相同 D.两串的长度相等,并且对应位置上的字符相同 二.填空题 1.串“ababcbaababd”的next函数值为,nextval函数值为。2.子串的长度为。 第五章数组和广义表 一.选择题 1.设有数组A[i,j],数组的每个元素长度为3字节,i的值为1 到8 ,j的值为1 到10,数组从内存首地址BA开始顺序存放,当用以列为主存放时,元素A[5,8]的存储首地址为( ) A. BA+141 B. BA+180 C. BA+222 D. BA+225 2.假设以行序为主序存储二维数组A=array[1..100,1..100],设每个数据元素占2个存储单元,基地址为10,则LOC[5,5]=() A. 808 B. 818 C. 1010 D. 1020 3.对稀疏矩阵进行压缩存储目的是() A.便于进行矩阵运算B.便于输入和输出C.节省存储空间D.降低运算的时间复杂度 4.假设以三元组表表示稀疏矩阵,则与如图所示三元组表对应的4×5的稀疏矩阵是(注:矩阵的行列下标均从1开始)() 线性表 代码一 #include "stdio.h" #include "malloc.h" #define OK 1 #define ERROR 0 #define OVERFLOW -2 #define LIST_INIT_SIZE 100 #define LISTINCREMENT 10 typedef struct { int * elem; int length; int listsize; }SqList; int InitList_Sq(SqList *L) { L->elem = (int*)malloc(LIST_INIT_SIZE*sizeof(int)); if (!L->elem) return ERROR; L->length = 0; L->listsize = LIST_INIT_SIZE; return OK; } int ListInsert_Sq(SqList *L, int i,int e) { int *p,*newbase,*q; if (i < 1 || i > L->length+1) return ERROR; if (L->length >= L->listsize) { newbase = (int *)realloc(L->elem,(L->listsize+LISTINCREMENT)*sizeof (int)); if (!newbase) return ERROR; L->elem = newbase; L->listsize += LISTINCREMENT; } q = &(L->elem[i-1]); //插入后元素后移for(p=&(L->elem[L->length-1]);p>=q;p--) *(p+1)=*p; *q=e; L->length++; return OK; } int ListDelete_Sq(SqList *L, int i, int *e) { 实验报告 课程名称数据结构实验名称查找与排序的实现 系别专业班级指导教师11 学号实验日期实验成绩 一、实验目的 (1)掌握交换排序算法(冒泡排序)的基本思想; (2)掌握交换排序算法(冒泡排序)的实现方法; (3)掌握折半查找算法的基本思想; (4)掌握折半查找算法的实现方法; 二、实验内容 1.对同一组数据分别进行冒泡排序,输出排序结果。要求: 1)设计三种输入数据序列:正序、反序、无序 2)修改程序: a)将序列采用手工输入的方式输入 b)增加记录比较次数、移动次数的变量并输出其值,分析三种序列状态的算法时间复杂 性 2.对给定的有序查找集合,通过折半查找与给定值k相等的元素。 3.在冒泡算法中若设置一个变量lastExchangeIndex来标记每趟排序时经过交换的最后位置, 算法如何改进? 三、设计与编码 1.本实验用到的理论知识 2.算法设计 3.编码 package sort_search; import java.util.Scanner; public class Sort_Search { //冒泡排序算法 public void BubbleSort(int r[]){ int temp; int count=0,move=0; boolean flag=true; for(int i=1;i #include return q; } void Delete_m(Link &L, Link p, Link q)//删除第m个{ p->next = q->next; free(q); } void main() { Link L, p, q; int n, m; L = NULL; InitList(L);//构造出一个只有头结点的空链表 printf("请输入初始密码人数每个人的密码:\n"); scanf("%d", &m);//初始密码为m scanf("%d", &n);// Creatlinklist(n, L);//构建 p = L; for (int i = 1; i <= n; i++) { q = Locate_m(p, m);//找到第m个 printf("%d", q->num); Delete_m(L, p, q);//删除第m个 } system("pause"); } 数据结构实验报告 一.题目要求 1)编程实现二叉排序树,包括生成、插入,删除; 2)对二叉排序树进行先根、中根、和后根非递归遍历; 3)每次对树的修改操作和遍历操作的显示结果都需要在屏幕上用树的形状表示出来。 4)分别用二叉排序树和数组去存储一个班(50人以上)的成员信息(至少包括学号、姓名、成绩3项),对比查找效率,并说明在什么情况下二叉排序树效率高,为什么? 二.解决方案 对于前三个题目要求,我们用一个程序实现代码如下 #include 《数据结构》实验报告 班级: 学号: 姓名: 实验四二叉树的基本操作实验环境:Visual C++ 实验目的: 1、掌握二叉树的二叉链式存储结构; 2、掌握二叉树的建立,遍历等操作。 实验内容: 通过完全前序序列创建一棵二叉树,完成如下功能: 1)输出二叉树的前序遍历序列; 2)输出二叉树的中序遍历序列; 3)输出二叉树的后序遍历序列; 4)统计二叉树的结点总数; 5)统计二叉树中叶子结点的个数; 实验提示: //二叉树的二叉链式存储表示 typedef char TElemType; typedef struct BiTNode{ TElemType data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; 一、程序源代码 #include } void Create_BiTree(BiTree *T){ char ch; ch = getchar(); //当输入的是"#"时,认为该子树为空 if(ch == '#') *T = NULL; //创建树结点 else{ *T = (BiTree)malloc(sizeof(struct TNode)); (*T)->data = ch; //生成树结点 //生成左子树 Create_BiTree(&(*T)->lchild); //生成右子树 Create_BiTree(&(*T)->rchild); } } void TraverseBiTree(BiTree T) { //先序遍历 if(T == NULL) return; 顺序表的基本操作 #include int j=0; while(L.data[j]!=x) j++; if(j==https://www.360docs.net/doc/0b437694.html,st) { cout<<"所查找值不存在!"< 1. 实验步骤: 先定义顺序表的结点: typedef struct { KeyType key; InfoType otherinfo; }ElemType; typedef struct { ElemType *R; int length; }SqList; 然后定义一个随机取数的函数,存到顺序表中: void CreateList(SqList &L,int n) 然后定义一个显示顺序表的函数,将顺序表中的数据显示出来: void ListTraverse(SqList L) 然后通过排序函数,将所有的数据按照从大到小的顺序排列: void BubbleSort(SqList &L) 实验结果: 测试数据: 38 86 9 88 29 18 58 27 排序后: 9 18 27 29 38 58 86 88 BubbleSort排序方法中数据的比较次数为:27 疑难小结: 这个程序的难点在于排序函数,总是把从第几个数开始排序以及怎样循环弄错。 源代码: #include 实验六:二叉树及其应用 一、实验目的 树是数据结构中应用极为广泛的非线性结构,本单元的实验达到熟悉二叉树的存储结构的特性,以及如何应用树结构解决具体问题。 二、问题描述 首先,掌握二叉树的各种存储结构和熟悉对二叉树的基本操作。其次,以二叉树表示算术表达式的基础上,设计一个十进制的四则运算的计算器。 如算术表达式:a+b*(c-d)-e/f 三、实验要求 如果利用完全二叉树的性质和二叉链表结构建立一棵二叉树,分别计算统计叶子结点的个数。求二叉树的深度。十进制的四则运算的计算器可以接收用户来自键盘的输入。由输入的表达式字符串动态生成算术表达式所对应的二叉树。自动完成求值运算和输出结果。四、实验环境 PC微机 DOS操作系统或 Windows 操作系统 Turbo C 程序集成环境或 Visual C++ 程序集成环境 五、实验步骤 1、根据二叉树的各种存储结构建立二叉树; 2、设计求叶子结点个数算法和树的深度算法; 3、根据表达式建立相应的二叉树,生成表达式树的模块; 4、根据表达式树,求出表达式值,生成求值模块; 5、程序运行效果,测试数据分析算法。 六、测试数据 1、输入数据:*(+)3 正确结果: 2、输入数据:(1+2)*3+(5+6*7); 正确输出:56 七、表达式求值 由于表达式求值算法较为复杂,所以单独列出来加以分析: 1、主要思路:由于操作数是任意的实数,所以必须将原始的中缀表达式中的操作数、操作符以及括号分解出来,并以字符串的形式保存;然后再将其转换为后缀表达式的顺序,后缀表达式可以很容易地利用堆栈计算出表达式的值。 例如有如下的中缀表达式: a+b-c 转换成后缀表达式为: ab+c- 然后分别按从左到右放入栈中,如果碰到操作符就从栈中弹出两个操作数进行运算,最后再将运算结果放入栈中,依次进行直到表达式结束。如上述的后缀表达式先将a 和b 放入栈中,然后碰到操作符“+”,则从栈中弹出a 和b 进行a+b 的运算,并将其结果d(假设为d)放入栈中,然后再将c 放入栈中,最后是操作符“-”,所以再弹出d和c 进行d-c 运算,并将其结果再次放入栈中,此时表达式结束,则栈中的元素值就是该表达式最后的运算结果。当然将原始的中缀表达式转换为后缀表达式比较关键,要同时考虑操作符的优先级以及对有括号的情况下的处理,相关内容会在算法具体实现中详细讨论。 2、求值过程 一、将原始的中缀表达式中的操作数、操作符以及括号按顺序分解出来,并以字符串的 形式保存。 二、将分解的中缀表达式转换为后缀表达式的形式,即调整各项字符串的顺序,并将括 号处理掉。 三、计算后缀表达式的值。 3、中缀表达式分解 DivideExpressionToItem()函数。分解出原始中缀表达式中的操作数、操作符以及括号,保存在队列中,以本实验中的数据为例,分解完成后队列中的保存顺序如下图所示: 数据结构实验报告全集 实验一线性表基本操作和简单程序 1.实验目的 (1)掌握使用Visual C++ 上机调试程序的基本方法; (2)掌握线性表的基本操作:初始化、插入、删除、取数据元素等运算在顺序存储结构和链表存储结构上的程序设计方法。 2.实验要求 (1)认真阅读和掌握和本实验相关的教材内容。 (2)认真阅读和掌握本章相关内容的程序。 (3)上机运行程序。 (4)保存和打印出程序的运行结果,并结合程序进行分析。 (5)按照你对线性表的操作需要,重新改写主程序并运行,打印出文件清单和运行结果 实验代码: 1)头文件模块 #include >验目的 掌握顺序栈的基本操作:初始化栈、判栈空否、入栈、出栈、取栈顶数据元素等运算以及程序实现方法。 2.实验要求 (1)认真阅读和掌握和本实验相关的教材内容。 (2)分析问题的要求,编写和调试完成程序。 (3)保存和打印出程序的运行结果,并分析程序的运行结果。 3.实验内容 利用栈的基本操作实现一个判断算术表达式中包含圆括号、方括号是否正确配对的程序。具体完成如下: (1)定义栈的顺序存取结构。 (2)分别定义顺序栈的基本操作(初始化栈、判栈空否、入栈、出栈等)。 (3)定义一个函数用来判断算术表达式中包含圆括号、方括号是否正确配对。其中,括号配对共有四种情况:左右括号配对次序不正确;右括号多于左括号;左括号多于右括号;左右括号匹配正确。 (4)设计一个测试主函数进行测试。 (5)对程序的运行结果进行分析。 实验代码: #include < > #define MaxSize 100 typedef struct { ??? int data[MaxSize]; ??? int top; }SqStack; void InitStack(SqStack *st) 验目的 (1)进一步掌握指针变量的用途和程序设计方法。 (2)掌握二叉树的结构特征,以及链式存储结构的特点及程序设计方法。 (3)掌握构造二叉树的基本方法。 (4)掌握二叉树遍历算法的设计方法。 3.实验要求 (1)认真阅读和掌握和本实验相关的教材内容。 (2)掌握一个实际二叉树的创建方法。 (3)掌握二叉链存储结构下二叉树操作的设计方法和遍历操作设计方法。 4.实验内容 (1)定义二叉链存储结构。 《数据结构与算法分析》 实验报告书 学期:2014 - 2015 学年第 2 学期 班级:信息管理与信息系统2班 学号: 1310030217 姓名:田洪斌 实验类别:(★)基础型()设计型 实验时间: 成绩: 信息管理系 一、实验内容 实现程序,按满二叉树给元素编号并输入的方式构造二叉树。 二、实验目的 1、掌握二叉树的静态及操作特点; 2、掌握二叉树的各种遍历方法; 3、掌握二叉树的存储、线索化等在C语言环境中的实现方法; 4、掌握哈夫曼树的构造方法及编码方法。 三、需求分析 用二叉树结构表示来完成输入、编辑、调试、运行的全过程。并规定: a.手动输入数字建立二叉树 b.程序可以输入、调试、运行、显示、遍历 c.测试数据:用户手动输入的数据 四、系统设计 1.数据结构设计 在本程序中对二叉树的存储主要用的是顺序存储结构,将二叉树存储在一个一维数组中。数据的输入输出都是采用整型数据进行。在主函数中只是定义数据类型,程序的实现功能化主要是在主函数中通过给要调用的函数参数来实现程序要求的功能。 2.程序结构设计 (1)程序中主要函数功能: main()/////////////////////////////////////////////主函数 menu()/////////////////////////////////////////////菜单 BiTree CreateBiTree()///////////////////////先序建立二叉树 (2)函数调用关系 见图4-1。 图4-1 函数关系图 五、 调试分析 1.算法和函数中出现了一些系统无法识别的变量,照成程序出现了错 误。原因是没有注意算法与源程序的区别。算法是简单的对源程序进行描述 的,是给人阅读的,所以有些变量没有定义我们就能看懂。而程序中的变量一定要先定义才能够被引用,才能被计算机识别。 2.在调试过程中遇到问题是利用C++程序进行调试的,找出错误并改正。 3.数据输出函数运行不正常,经检查程序,发现是定义错误,更改后错误排除; 六、 测试结果 1.运行时输入正确密码进入主界面,系统根据输入的数字选项来调用相应的函数。主要实现“功能选择”的界面,在这个界面里有显示系统的五大功能,根据每个功能前面的序号进行选择。以下为该界面: main BiTree CreateB iTree() meun() 数据结构与算法课程实验报告实验五:图的相关算法应用 姓名:cll 班级: 学号: 【程序运行效果】 一、实验内容: 求有向网络中任意两点之间的最短路 实验目的: 掌握图和网络的定义,掌握图的邻接矩阵、邻接表和十字链表等存储表示。掌握图的深度和广度遍历算法,掌握求网络的最短路的标号法和floyd算法。 二、问题描述: 对于下面一张若干个城市以及城市间距离的地图,从地图中所有可能的路径中求出任意两个城市间的最短距离及路径,给出任意两个城市间的最短距离值及途径的各个城市。 三、问题的实现: 3.1数据类型的定义 #define MAXVEX 50 //最大的顶点个数 #define MAX 100000 typedef struct{ char name[5]; //城市的名称 }DataType; //数据结构类型 typedef struct{ int arcs[MAXVEX][MAXVEX]; //临接矩阵 DataType data[MAXVEX]; //顶点信息 int vexs; //顶点数 }MGraph,*AdjMetrix; //邻接矩阵表示图 3.2主要的实现思路: 用邻接矩阵的方法表示各城市直接路线的图,之后用Floyd算法求解两点直接的最短距离,并用递归的方法求出途经的城市。 主要源程序代码: #include #include 数据结构课程实验报告-实验5 HUNAN UNIVERSITY 课程实习报告 题目:四则运算表达式求值 学生姓名康小雪 学生学号 20090810310 专业班级计科三班 指导老师李晓鸿 完成日期2010-10-24 一、需求分析 1.该程序可以从通过从键盘输入一个中缀表达式,判断该表达式是否合法,若合法将 其转化为后缀表达式,并计算其结果,否则说明该表达式错误 2..输入的表达式包含数字和运算符及括号,之间用空格隔开 3.数字可以为整数和小数 4.运算结果保留两位小数 输入输出举例 输入:21+23*(12-6) 输出:21 23 12 6 -*+ 二、概要设计 在表达式中每个运算符应对应两个操作数,与二叉树中非叶子结点和叶子结点之间的关系刚好相同,于是,本题可采用二叉树来将中缀表达式变为后缀表达式。 最后用堆栈来实现后缀表达式的计算。 抽象数据类型 二叉树 ADT BiTree { 数据对象D:D是具有相同特性的数据元素集合 数据关系R: 若D为空集,则R为空集,则称BinaryTree 为空二叉树; 若D不为空集,否则R={H},H是如下二元关系: (1)在D中存在唯一的称为根的数据元素root,它在关系H下无前驱; (2)若D-{root}≠空集,则存在D-{root}的一个划分{D1,Dr} 且D1∩Dr=空集; (3)若D1≠空集,则D1中存在唯一元素x1, 三题目:哈夫曼编/译码器 班级:姓名:学号:完成日期:15.11.14 一、题目要求 描述:写一个哈夫曼码的编/译码系统,要求能对要传输的报文进行编码和解码。构造哈夫曼树时,权值小的放左子树,权值大的放右子树,编码时右子树编码为1,左子树编码为0. 输入:输入表示字符集大小为n(n <= 100)的正整数,以及n个字符和n个权值(正整数,值越大表示该字符出现的概率越大); 输入串长小于或等于100的目标报文。 输出:经过编码后的二进制码,占一行; 以及对应解码后的报文,占一行; 最后输出一个回车符。 输入样例: 5 a b c d e 12 40 15 8 25 bbbaddeccbbb 输出样例: 00011111110111010110110000 bbbaddeccbbb 提示:利用编码前缀性质。 二、概要设计 1.设计需要的数据结构:树型结构 2.需要的抽象数据类型: ADT Tree{ 数据对象D:D是具有相同特性的数据元素的集合。 数据关系R:若D为空集,则称为空树; 若D仅含有一个数据元素,则R为空集,否则R={H},H是如下二元关系: (1) 在D中存在唯一的称为根的数据元素root,它在关系H下无前驱; (2) 若D-{root}≠NULL,则存在D-{root}的一个划分D1,D2,D3,…,Dm(m>0),对于任意j≠k(≤j,k≤m)有Dj∩Dk=NULL,且对任意的i(1≤i≤m),唯一存在数据元素xi?Di有 1、直接插入排序 2、希尔排序 3、2-路归并排序 4、折半插入排序 5、冒泡排序 6、快速排序 7、堆排序 /*---------------------------------------- * 07_排序.cpp -- 排序的相关操作 * 对排序的每个基本操作都用单独的函数来实现 * 水上飘2011年写 ----------------------------------------*/ // ds07.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "stdio.h" #include int i, j; for (i = dk + 1; i <= L.length; i++) { if (L.arr[i].key 数据结构课程实验指导书
数据结构实验8实验报告
数据结构习题(456章)
数据结构实验报告代码
数据结构实验五-查找与排序的实现
数据结构实验一的源代码
数据结构实验报告
数据结构实验报告(四)
数据结构实验程序
数据结构实验五
数据结构实验二叉树
数据结构实验报告全集
数据结构实验五A
数据结构-实验五-图
数据结构上机实验线性表单链表源代码
数据结构课程实验报告-实验5
数据结构实验三实验报告
数据结构实验(七种排序算法的实现)题目和源程序