c/c++抽象数据类型实验


前言

作为新手,模仿+理解+运用是学习的三个阶段

本文以理解代码段为学习目标


一、数据类型描述

三元组Triplet的定义:
ADT Triplet{
数据对象:D={e1, e2, e3|e1, e2, e3属于ElemType(定义了关系的某个集合)}
数据关系:R={<e1, e2>|<e2, e3>}
基本操作:
initTriplet(&T, v0, v1, v2)
初始条件:
操作结果:构造三元组T,元素e1, e2和e3分别被赋予参数v1, v2, v3的值。
destroyTriplet(Triplet T)
初始条件:三元组T已经存在。
操作结果:销毁三元组T。
printTriplet(T)
初始条件:三元组T已经存在。
操作结果:显示三元组T。
getElem(T, i, &e)
初始条件:三元组T已经存在, 1 <= i <= 3。
操作结果:用e返回三元组T的第i(1~3)个元素的值。
putElem(&T, I, e)
初始条件:三元组T已经存在, 1 <= i <= 3。
操作结果:用e的值取代三元组T的第i(1~3)个元素的值。 
getMax(T, &e)
初始条件:三元组T已经存在。
操作结果:用e返回三元组T的最大值。
getMin(T, &e)
初始条件:三元组T已经存在。
操作结果:用e返回三元组T的最小值。
isAscending(T)
初始条件:三元组T已经存在。
操作结果:如果T的三个元素按升序排序,则返回OK,否则返回ERROR。
isDescending(T)
初始条件:三元组T已经存在。
操作结果:如果T的三个元素按降序排序,则返回OK,否则返回ERROR。
Add(T1, &T2)
初始条件:存在三元组T1, T2。
操作结果:用T2带回操作结果。
mulCoef(&T1, coef)
初始条件:三元组T1已经存在。
操作结果:用T1带回乘系数之后都结果。
}ADT Triplet

二、源代码(扩展名.cpp)

1.引入库

代码如下(示例):

# include<stdio.h> //标准的输入输出函数库 
# include<stdlib.h> //使用动态分配内存必须引入的函数库 
# define OK 1 //宏定义,下同 
# define ERROR 0
# define OVERFLOW -2 
typedef int Status; //给int起了个别名(Status),下同 
typedef float ElemType;
typedef ElemType *Triplet; //声明Triplet为指向任意类型(此处为ElemType)的指针 
//三元组的初始化//
void initTriplet(Triplet &T, ElemType v0, ElemType v1, ElemType v2)
{
	//动态分配内存
	T = (ElemType *)malloc(3*sizeof(ElemType)); 
/*
说明:malloc函数后的()给指针分配大小;
	  malloc函数前的()给指针分配方向。
	  (类型说明符 *)表示将返回值强制转化为该类型的指针,
	  而此时需要指向ElemType类型,而Triplet为指向ElemType的指针
	  所以也可写为T = (Triplet)malloc(3*sizeof(ElemType)); 
*/
	if (!T)  
	{
		printf("分配内存失败!");
		exit(OVERFLOW);
	}
	T[0] = v0;
	T[1] = v1;
	T[2] = v2;
}
//销毁三元组//
void destroyTriplet(Triplet &T)
{
	free(T);
	printf("分配内存已释放!");
	exit(0);
}
//销毁三元组//
void destroyTriplet_2(Triplet &T)
{
	 delete []T; 
	 printf("分配内存已释放!");
	 exit(0);
}
//显示三元组
void printTriplet(Triplet T)
{
	printf("调用初始化函数后,T的三个值为:%.1f,%.1f,%.1f\n", T[0], T[1], T[2]);
}
// 用e获取T的第i(1~N)个元素的值// 
Status getElem(Triplet T, int i, ElemType &e)
{
	if (i < 1 || i > 3)
		return ERROR;
	else e = T[i-1]; 
	return OK;
}
// 置T的第i元的值为e 
Status putElem(Triplet &T, int i, ElemType e)
{
	if (i < 1 || i > 3)
		return ERROR;
	else T[i-1] = e; 
	return OK;
}
//用e返回值指向T的最大元素的值
ElemType getMax(Triplet T,  ElemType &e)
{
	if (T[0] > T[1])
		e = T[0];
	else
		e = T[1];
	if (T[2] > e)
		e = T[2];
	printf("三元组T的最大元素的值为:%4.2f\n",e);
	return e; 
} 
//用e返回值指向T的最小元素的值
ElemType getMin(Triplet T, ElemType &e)
{
	if (T[0] < T[1])
		e = T[0];
	else
		e = T[1];
	if (T[2] < e)
		e = T[2];
	printf("三元组T的最小元素的值为:%4.2f\n",e);
	return e;
} 
//如果T的三个元素按升序排序,则返回1,否则返回0//
void isAscending(Triplet T)
{
	if (((T[0] <= T[1]) && (T[1] <= T[2] )) != ERROR)
		printf("T的三个元素按升序排序\n");
	else printf("T的三个元素不是按升序排序");
} 
//如果T的三个元素按降序排序,则返回1,否则返回0//
void isDescending(Triplet T)
{
	if (((T[0] >= T[1]) && (T[1] >= T[2])) != ERROR)
		printf("T的三个元素按降序排序\n"); 
	else printf("T的三个元素不是按降序排序");
} 
//两个三元组相加
void add(Triplet T, Triplet &T2)
{
	int i;
	for (i = 0; i < 3; i++)
		T2[i] += T[i]; 
} 
//三元组的各分量同乘比例系数
void mulCoef(Triplet &T, float coef)
{
	int i;
	for (i = 0; i < 3; i++)
		T[i] *= coef;
} 
int main()
{
	Triplet T, T2;
	ElemType v0, v1, v2, e, coef;
	int funNum, i;
	printf("----三元组操作主菜单----\n");
	printf("----1.三元组初始化----\n"); 
	printf("----2.显示三元组----\n");
	printf("----3.用e获取T的第i(1~N)个元素的值----\n");
	printf("----4.置T的第i个元素的值为e----\n");
	printf("----5.是否升序排列----\n");
	printf("----6.是否降序排列----\n");
	printf("----7.取最大值----\n");
	printf("----8.取最小值----\n");
	printf("----9.输入另一个三元组相加----\n");
	printf("----10.三元组的各分量同乘比例系数----\n");
	printf("----11.退出系统----\n");
	while (1)
	{
		printf("请输入你想完成的功能编号:\n"); 
		scanf("%d", &funNum);
		switch (funNum)
		{
			case 1: printf("请输入三元组的每个元素:\n");
					scanf("%f %f %f", &v0, &v1, &v2);
					initTriplet(T, v0, v1, v2);
					break;
			case 2: printTriplet(T);
					break;
			case 3: printf("请输入要获取第几个元素的值:\n");
					scanf("%d", &i);
					getElem(T, i, e);
					printf("第%d个元素的值为:%4.2f\n", i, e);
					break;
			case 4: printf("请输入要更改的位置和要输入的值:\n");
					scanf("%d %f", &i, &e);
					putElem(T, i, e);
					printf("新的三元组为:\n");
					printTriplet(T);
					break;
			case 5: isAscending(T);
					break;
			case 6: isDescending(T);
					break;
			case 7: getMax(T, e);
					break;
			case 8: getMin(T, e);
					break;
			case 9: printf("请输入另一个三元组的每个元素\n");
					scanf("%f %f %f", &v0, &v1, &v2);
					initTriplet(T2, v0, v1, v2);
					add(T, T2);
					printf("相加之后的三元组的值为:\n");
					printTriplet(T2);
					break;
			case 10: printf("请输入所乘的系数\n");
					scanf("%f", &coef);
					mulCoef(T, coef);
					printf("每项乘系数之后的三元组为:\n");
					printTriplet(T);
					break;
			case 11: destroyTriplet(T);
					destroyTriplet(T2);
					break;
			default: printf("没有你想完成的功能\n");break;
		}
	}
	return 0;
}

2.读入数据

代码如下:


代码段的理解

上文的源代码中,基本每段代码之后都有程序注释,作为新手,程序注释更是我们检验理解能力的"一杆秤“。

除程序注释,以下方面是对整片代码的理解:

1.指针问题

c中指针内容没掌握好的同学,(例如我),刚开始会对上述代码会有疑惑,全文中只有开头typedef ElemType *Triplet;中带有出现指针定义的间接访问运算符”*“,好像与下面代码显得格格不入

而理解代码的话,你会惊奇的发现,下面代码基本全部使用了指针,每一个变量T都是指针型变量,“指针无处不在”。

上面指出typedef ElemType *Triplet;是在声明Triplet为指向任意类型(此处为ElemType)的指针,所以,下面每一个Triplet数据类型的变量,全都是指向ElemType类型的指针变量,

在子函数中,会发现许多T[0]的用法,其实这就是指针的便捷之处,如果我们用结构体的话,必须 使用类似T.e[0]的形式,才能做一系列操作,但如果上面定义指针类型的话,直接使用T[0]即可。

T[0]的用法有些类似数组,对于数组而言,数组名[]可对数组中的元素操作,而对于指针变量同样适用,指针变量名T[]即可对指针指向的内容操作。(注意,不是指针本身的内容(或者说指针指向的方向))。

2.引用问题

上述代码我们使用了c++中的“引用”,(这也就是为什么源代码的扩展名要为.cpp),引用通俗来讲,就是给变量a又取了一个名字为变量b,所以引用并没有给b分配内存空间,而是让b与a共用同一块内存空间,此处与指针不同

在上述代码的参数传递中,我们多次使用了引用"&T",对于什么时候需要使用来说,如果你要改变某个实参的值,就对某个实参使用引用,反之,则不用。

3.针对上文使用的动态内存分配问题

本实验要求动态内存分配,其实对于三元组来说,并没有把动态内存分配的功能发挥的淋漓精致,但也简单的让我们看到了其强大功能的一二。

动态内存分配需要使用指针,指针的强大上文已经略有细说,我们慢慢体会。

动态分配内存要养成及时把需要释放的内存给释放掉的好习惯,对于大量的程序代码段,有助于提升系统的效率,减少所占内存。

写在最后

上文多次写了我对指针的理解,比如说两个特性,方向与大小,

但只是配和理解,真正应该以配合理解去使理解专业化,而不应该停留在配合理解或者被其框架所束缚。

浮游乎万物之祖,物物而不物于物。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值