大二上期数据结构实验记录(一)【修改增删版】C实现简单复数计算器(能力有限还不能实现有界面的计算器,会努力争取在在本学期末写出)

想要记录自己编程思维的成长所以发到博客,欢迎并且感激大家指出缺点和错误! 

 一、【实验构思(Conceive)】

简单复数计算器,顾名思义,实现复数简单四则运算,要实现运算,那么就要有数据输入,数据处理,最后就是结果输出(包括错误处理啥的,体现鲁棒性容错性)。

二、【实验设计(Design)】

输入则是复数,复数个数可以是大于等于两个复数,在这个程序我只做了两个复数的运算。然后,我对复数的准确概念忘得差不多了,我就百度了一下复数的概念,如下流程图,复数的结构是由虚部和实部两个部分组成,特别地,当虚部等于0时,这个复数可以视为实数,又当虚部不等于零实部等于0时,这个复数常称为纯虚数。所以,输入程序的数据可分为两个部分,实部和虚部,根据数据结构知识,我们可以把这两部分抽象出来用结构体存储。完成了对数据的存储之后,接下来就是,第二步,处理,对数据的处理,本程序中对数据的处理可分为5种吧,№1,将输入的两个部分的数据初始化为一个整体复数(存入结构体)并打印出来正确的复数形式,№2-№5就分别是四种基础运算的实现了,我将这5(实则6)种数据处理用主函数调用几种功能函数来实现。最后,结果输出,用返回函数值或者函数过程实现。

三、【实现(Implement)】 

抽象数据类型实现代码:

typedef struct {  
	double _real; 
	double _imag;  
} cpxNum; //定义结构体类型cpxNum表示“复数” 

 函数实现输入数据的复数初始化 :

//此函数实现输入数据的复数初始化 
cpxNum cpnInit(cpxNum c , double r , double i){
	c._real = r;
	c._imag = i;
	
	return c;
}

实现复数的打印(增加虚部打印时的正负号输出显示问题)

void cpnDisp(cpxNum c){
	printf("请确认您输入后的复数或者结果是否为: ");
	if(c._imag < 0)
		printf("%fi%f\n\n",c._real, c._imag);
	else
		printf("%fi+%f\n\n", c._real, c._imag);//增加虚部正负判别输出
}

 实现加减乘除(时间复杂度都为O(1))(修改除法验证 之前是错的 在测试中发现无法达到预期结果 就回头看代码 发现if()语句条件是错的)

//加法
cpxNum cpnplus(const cpxNum c1 , const cpxNum c2 ) /*实现两个复数c1, c2的减法, 差作为函数cmilus的返回值*/
{
	cpxNum result;

	double r, i;
	r = c1._real + c2._real;
	i = c1._imag + c2._imag;

	result._real = r;
	result._imag = i;

	return result;
}
//减法
cpxNum cpnmilus(const cpxNum c1 , const cpxNum c2 )
{
	cpxNum result;

	double r, i;
	r = c1._real - c2._real;
	i = c1._imag - c2._imag;

	result._real = r;
	result._imag = i;

	return result;

}

//乘法:(a + bi)*(c + di)=(ac - bd)+(ad + bc)i

cpxNum cpnmultiply(const cpxNum c1 , const cpxNum c2 )
{
	cpxNum result;

	double r, i;
	r =  c1._real * c2._real  -  c1._imag * c2._imag ;
	i =  c1._real * c2._imag  +  c1._imag * c2._real ;

	result._real = r;
	result._imag = i;

	return result;
}
//除法
cpxNum cpndivide( cpxNum c1 ,  cpxNum c2 )
{
	if(pow(c2._imag,2) + pow(c2._real,2)==0){ //纠错
		double r,i;
		cpxNum  result2;
		printf("第二个复数的实部与虚部平方和不能为0 \n");
		printf("请重新输入 \n");
		printf("请输入第二个复数的实部\n");
		scanf("%lf", &r );
		printf("请输入第二个复数的虚部\n");
		scanf("%lf", &i );
		c2 = cpnInit(c2 , r , i );
		cpnDisp(c2);
	}

	cpxNum result;

	double r, i, d;
	d = pow( c2._real, 2.0 ) + pow( c2._imag, 2.0 );
	r = ( c1._real * c2._real + c1._imag * c2._imag ) / d;
	i = ( c1._imag * c2._real - c1._real * c2._imag ) / d;

	result._real = r;
	result._imag = i;
	return result;
}

最后也是最重要的主函数

通过scanf()函数接收数据,用switch开关选择函数来判断四则运算,然后调用处理函数得出结果。

特别地,我再除法函数种加入了容错性判断,根据复数除法计算公式,分母不能为零,为零地话重新输入正确的第二个复数,不会崩溃。(如果没错的话)

哈哈哈,在测试结果的时候,我又发现在输入计算代码那儿可能会出错,于是又在主函数里加了一个容错判断。

【在后续的测试中,又增加了输入数据有效性的检验】

利用了scanf()函数的返回值的判断来判别是否为有效数据,并且在过程中发现使用while()会出现死循环,经过百度,知道%*c并且要fflush(stdin)及时清理缓存,可以控制不用死循环。(因为系统不会自动清理缓存中的数据,所以,在读入错误数据时,要及时清理缓存,以免造成死循环)

资料来源有效数据判断

//主函数 程序入口
int main(){

	printf("************欢迎使用复数计算器**********\n");
	printf("******本计算器可执行复数的四则运算******\n");
	printf("*************即加减乘除运算*************\n");
	printf("****************************************\n");

	//可循环使用计算器
	while(1){
	cpxNum c1, c2, result1,result2;
	double r;
	double i;
	int flag;

	printf("请输入第一个复数的实部\n");
	flag = scanf("%lf%*c", &r );
	while(flag!=1){
		fflush(stdin);                                       //加入有效数据判断
		printf("您输入的数据类型不正确,请重新输入!\n");
		flag = scanf("%lf%*c", &r);
	//	fflush(stdin);
	}
	printf("请输入第一个复数的虚部\n");
	flag = scanf("%lf%*c", &i);
	while(flag!=1){
		fflush(stdin);
		printf("您输入的数据类型不正确,请重新输入!\n");
		flag = scanf("%lf%*c", &i);
	}
	result1 = cpnInit(c1 , r , i );
	cpnDisp(result1);

	printf("请输入第二个复数的实部\n");
	flag = scanf("%lf%*c", &r );
	while(flag!=1){
		fflush(stdin);
		printf("您输入的数据类型不正确,请重新输入!\n");
		flag = scanf("%lf%*c", &r );
	}
	printf("请输入第二个复数的虚部\n");
	flag = scanf("%lf%*c", &i );
	while(flag!=1){
		fflush(stdin);
		printf("您输入的数据类型不正确,请重新输入!\n");
		flag = scanf("%lf%*c", &i );
	}
	result2 = cpnInit(c2 , r , i );
	cpnDisp(result2);

	printf("请选择您要执行的运算\n");
	printf("运算1:复数加法\n");
	printf("运算2:复数减法\n");
	printf("运算3:复数乘法\n");
	printf("运算4:复数除法\n");

	int s = 0;
	printf("请输入您要执行的运算代码\n");
	flag = scanf("%d%*c", &s);

	while( flag!=1 ){
        fflush(stdin);
		printf("代码不正确,请重新输入\n");
		flag = scanf("%d%*c", &s);
	}

	cpxNum result;
	switch(s){
		case 1:
			{
			result = cpnplus( result1, result2 );
			printf("结果是:\n");
			cpnDisp(result);
			break;
			}
		case 2:
			{
			result = cpnmilus( result1, result2 );
			printf("结果是:\n");
			cpnDisp(result);
			break;
			}
		case 3:
			{
			result = cpnmultiply( result1, result2 );
			printf("结果是:\n");
			cpnDisp(result);
			break;
			}
		case 4:
			{
			result = cpndivide( result1, result2  );
			printf("结果是:\n");
			cpnDisp(result);
			break;
			}

	}

	if(result._imag == 0)//特殊情况
		printf("此复数可以视为实数\n");
	}
	return 0;
}

 

四、【测试结果(Testing)】 

 

五、【实验总结】

设计程序思维很重要,在看了贺老师的文章后更是这样认为,每一次设计走一次这个过程,就会在脑袋里形成这种思维方式,思维只会越来越快。然后画流程图也帮助我清晰理出思路,不会想出下一步就忘了上一步,并且更具逻辑性。 设计程序最重要的阶段就是构思和设计了吧,实现和运作都是其次。程序写好后的调试修改非常重要,程序写好能运行但还是可能会出错,这时自然就会设计鲁棒性代码了,但是我认为以后应该在程序设计时就应该想到这些会出错的地方,不至于程序写好了,运行了,出错了!?然后再返回去添加容错性代码,这是不太好的,bug可以有,再者设计的时候考虑应该周全,这个错了比bug更难改正。

、思考题或【项目运作描述(Operate)】 

 七、【源代码】

/**
author:Cyan
data:2018/10/13
**/
#include <stdio.h>
#include <math.h>


typedef struct {
	double _real;
	double _imag;
} cpxNum; //定义结构体类型cpxNum表示“复数”

cpxNum cpnInit(const cpxNum , double , double );  //将输入数字复数初始化
void cpnDisp(const cpxNum ); //打印所输入复数
cpxNum cpnplus(const cpxNum , const cpxNum );   //实现两个复数c1, c2的加法, 和作为函数cplus的返回值//
cpxNum cpnmilus(const cpxNum , const cpxNum );   //实现两个复数c1, c2的减法, 差作为函数cmilus的返回值//
cpxNum cpnmultiply(const cpxNum , const cpxNum );  //实现两个复数c1, c2的乘法, 积作为函数cmultiply的返回值//
cpxNum cpndivide( cpxNum,  cpxNum );  //实现两个复数c1, c2的乘法, 商作为函数cdivide的返回值//


//主函数 程序入口
int main(){

	printf("************欢迎使用复数计算器**********\n");
	printf("******本计算器可执行复数的四则运算******\n");
	printf("*************即加减乘除运算*************\n");
	printf("****************************************\n");

	//可循环使用计算器
	while(1){
	cpxNum c1, c2, result1,result2;
	double r;
	double i;
	int flag;

	printf("请输入第一个复数的实部\n");
	flag = scanf("%lf%*c", &r );
	while(flag!=1){
		fflush(stdin);                                       //加入有效数据判断
		printf("您输入的数据类型不正确,请重新输入!\n");
		flag = scanf("%lf%*c", &r);
	//	fflush(stdin);
	}
	printf("请输入第一个复数的虚部\n");
	flag = scanf("%lf%*c", &i);
	while(flag!=1){
		fflush(stdin);
		printf("您输入的数据类型不正确,请重新输入!\n");
		flag = scanf("%lf%*c", &i);
	}
	result1 = cpnInit(c1 , r , i );
	cpnDisp(result1);

	printf("请输入第二个复数的实部\n");
	flag = scanf("%lf%*c", &r );
	while(flag!=1){
		fflush(stdin);
		printf("您输入的数据类型不正确,请重新输入!\n");
		flag = scanf("%lf%*c", &r );
	}
	printf("请输入第二个复数的虚部\n");
	flag = scanf("%lf%*c", &i );
	while(flag!=1){
		fflush(stdin);
		printf("您输入的数据类型不正确,请重新输入!\n");
		flag = scanf("%lf%*c", &i );
	}
	result2 = cpnInit(c2 , r , i );
	cpnDisp(result2);

	printf("请选择您要执行的运算\n");
	printf("运算1:复数加法\n");
	printf("运算2:复数减法\n");
	printf("运算3:复数乘法\n");
	printf("运算4:复数除法\n");

	int s = 0;
	printf("请输入您要执行的运算代码\n");
	flag = scanf("%d%*c", &s);

	while( flag!=1 ){
        fflush(stdin);
		printf("代码不正确,请重新输入\n");
		flag = scanf("%d%*c", &s);
	}

	cpxNum result;
	switch(s){
		case 1:
			{
			result = cpnplus( result1, result2 );
			printf("结果是:\n");
			cpnDisp(result);
			break;
			}
		case 2:
			{
			result = cpnmilus( result1, result2 );
			printf("结果是:\n");
			cpnDisp(result);
			break;
			}
		case 3:
			{
			result = cpnmultiply( result1, result2 );
			printf("结果是:\n");
			cpnDisp(result);
			break;
			}
		case 4:
			{
			result = cpndivide( result1, result2  );
			printf("结果是:\n");
			cpnDisp(result);
			break;
			}

	}

	if(result._imag == 0)//特殊情况
		printf("此复数可以视为实数\n");
	}
	return 0;
}
//此函数实现输入数据的复数初始化
cpxNum cpnInit(cpxNum c , double r , double i){
	c._real = r;
	c._imag = i;

	return c;
}
//此函数实现复数的打印
void cpnDisp(cpxNum c){
	printf("请确认您输入后的复数或者结果是否为: ");
	if(c._imag < 0)
		printf("%fi%f\n\n",c._real, c._imag);
	else
		printf("%fi+%f\n\n", c._real, c._imag);//增加虚部正负判别输出
}
//加法
cpxNum cpnplus(const cpxNum c1 , const cpxNum c2 ) /*实现两个复数c1, c2的减法, 差作为函数cmilus的返回值*/
{
	cpxNum result;

	double r, i;
	r = c1._real + c2._real;
	i = c1._imag + c2._imag;

	result._real = r;
	result._imag = i;

	return result;
}
//减法
cpxNum cpnmilus(const cpxNum c1 , const cpxNum c2 )
{
	cpxNum result;

	double r, i;
	r = c1._real - c2._real;
	i = c1._imag - c2._imag;

	result._real = r;
	result._imag = i;

	return result;

}

//乘法:(a + bi)*(c + di)=(ac - bd)+(ad + bc)i

cpxNum cpnmultiply(const cpxNum c1 , const cpxNum c2 )
{
	cpxNum result;

	double r, i;
	r =  c1._real * c2._real  -  c1._imag * c2._imag ;
	i =  c1._real * c2._imag  +  c1._imag * c2._real ;

	result._real = r;
	result._imag = i;

	return result;
}
//除法
cpxNum cpndivide( cpxNum c1 ,  cpxNum c2 )
{
	if(pow(c2._imag,2) + pow(c2._real,2)==0){ //纠错
		double r,i;
		cpxNum  result2;
		printf("第二个复数的实部与虚部平方和不能为0 \n");
		printf("请重新输入 \n");
		printf("请输入第二个复数的实部\n");
		scanf("%lf", &r );
		printf("请输入第二个复数的虚部\n");
		scanf("%lf", &i );
		c2 = cpnInit(c2 , r , i );
		cpnDisp(c2);
	}

	cpxNum result;

	double r, i, d;
	d = pow( c2._real, 2.0 ) + pow( c2._imag, 2.0 );
	r = ( c1._real * c2._real + c1._imag * c2._imag ) / d;
	i = ( c1._imag * c2._real - c1._real * c2._imag ) / d;

	result._real = r;
	result._imag = i;
	return result;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值