复数乘法器的功能实现(C语言)
题目介绍:
图片来源:LeetCode
这道题思路并不是很复杂,就是在对字符串处理上,步骤相对多一些。
人尽皆知,两个复数乘法的结果是:
二者实部之积与虚部之积的差 + 二者实部虚部之积的和*i。
所以现在我们的思路就清晰了:
- 求得以字符串形式给定的复数的实部虚部对应的整数,atoi函数完成这一步。(ASCII to integer,顾名思义,itoa同理)
(字符串不能加减乘除,这时最终结果的实部虚部只能用整数乘法和加法运算出来) - 将两部分——复数乘法最终结果的虚部和实部,再分别转换为两部分字符串
- 将两部分运算结果与’+'和’i’连接,成为最终结果。
最开始我提交的代码版本并没有itoa1函数模块,直接调用了头文件stdlib.h下的itoa函数(实现整数转字符串的功能),这一点在codeblocks的环境下是可以运行的,但是在力扣的编译环境下是不允许的,仅仅允许atoi,所以我就索性自己写了一个简陋版本的itoa函数.
char * itoa1(int n,char * d)
{
char * zero=(char *)malloc(sizeof(char)*10);
* zero = '0';
*(zero+1)='\0';
char * nega=(char *)malloc(sizeof(char)*100);
* nega = '-';
*(nega+1)='\0';
int i,j;
int k=1;
int tem;
if(n<0) tem=-n;
else tem=n;
int temtem=tem;
while(tem)//求数字对应的最大位数,比如7888对应千分位
{
tem=tem/10;
k*=10;
}//这一步改变了tem的值,遂再用temtem保存tem的值
for(i=k/10,j=0;i>0;i=i/10)//求abs(n)对应的字符串,使用强转并在ASCII码上位移以转到整数字符
{
* (d+j) = (char)(temtem/i %10) + 48;
j++;
}
if(n<0) return strcat(nega,d);
else if(n==0) return zero;
else return d;
}
char * complexNumberMultiply(char * a, char * b){
int i,j,Re_a,Re_b,Im_a,Im_b;
char *c,*d;
c = (char*)malloc(sizeof(char)*15);
memset(c,'\0',sizeof(char)*15);
d = (char*)malloc(sizeof(char)*15);
memset(d,'\0',sizeof(char)*15);
char * t1;//四个字符串存两个实部两个虚部为atoi做准备
char * t2;
char * t3;
char * t4;
t1 = (char*)malloc(sizeof(char)*10);
t2 = (char*)malloc(sizeof(char)*10);
t3 = (char*)malloc(sizeof(char)*10);
t4 = (char*)malloc(sizeof(char)*10);
memset(t1,'\0',sizeof(char)*10);
memset(t2,'\0',sizeof(char)*10);
memset(t3,'\0',sizeof(char)*10);
memset(t4,'\0',sizeof(char)*10);
for(i=0,j=0;*(a+i)!='+';i++,j++)//在取到'+'之前终止对t(i)的读取,下一步关于'i'同理
{
*(t1+j)=*(a+i);
}
int tem1=i;//要跳过字符位,i的值需要加1,下面一步取另一个复数的实部改变了i的值,先存起来。下面的tem2同理。
for(i=0,j=0;*(b+i)!='+';i++,j++)
{
*(t2+i)=*(b+i);
}//完成对实部的读取
int tem2=i;
Re_a=atoi(t1);
Re_b=atoi(t2);
for(i=tem1+1,j=0;*(a+i)!='i';i++,j++)//跳过字符位,读取虚部
{
t3[j]=*(a+i);
}
for(i=tem2+1,j=0;*(b+i)!='i';i++,j++)
{
t4[j]=*(b+i);
}
Im_a=atoi(t3);
Im_b=atoi(t4);
char * Add = (char*)malloc(sizeof(char)*2);
* Add = '+';
* (Add+1) = '\0';
char * I = (char*)malloc(sizeof(char)*2);
* I = 'i';
* (I+1) = '\0';
d = strcat(itoa1(Re_a*Re_b-Im_a*Im_b,d),Add);
d = strcat(d,itoa1(Re_a*Im_b+Im_a*Re_b,c));
d = strcat(d,I);
free(t1);
free(t2);
free(t3);
free(t4);
free(c);
return d;
}
结果:
It sucks,innit?繁琐和低下的代码效率,占空间和运行时间都很大。
从未用过sprintf函数的我,因为strcat函数不能一数组和一指针同时处理,就重新定义了指针、初始化、连接。导致程序执行时间过长内存消耗大。这时候引入sprintf就好些了。
sprintf的功能极其强大,比如可以将整数打印在字符串上,大多数场合可以代替itoa函数。
优化后代码如下:
char * complexNumberMultiply(char * a, char * b){
int i,j,Re_a,Re_b,Im_a,Im_b;
char * c = (char*)malloc(sizeof(char)*15);
memset(c,'\0',sizeof(char)*15);
char * t1;
char * t2;
char * t3;
char * t4;
t1 = (char*)malloc(sizeof(char)*10);
t2 = (char*)malloc(sizeof(char)*10);
t3 = (char*)malloc(sizeof(char)*10);
t4 = (char*)malloc(sizeof(char)*10);
memset(t1,'\0',sizeof(char)*10);
memset(t2,'\0',sizeof(char)*10);
memset(t3,'\0',sizeof(char)*10);
memset(t4,'\0',sizeof(char)*10);
for(i=0,j=0;*(a+i)!='+';i++,j++)
{
*(t1+j)=*(a+i);
}
int tem1=i;
for(i=0,j=0;*(b+i)!='+';i++,j++)
{
*(t2+i)=*(b+i);
}
int tem2=i;
Re_a=atoi(t1);
Re_b=atoi(t2);
for(i=tem1+1,j=0;*(a+i)!='i';i++,j++)
{
t3[j]=*(a+i);
}
for(i=tem2+1,j=0;*(b+i)!='i';i++,j++)
{
t4[j]=*(b+i);
}
Im_a=atoi(t3);
Im_b=atoi(t4);
sprintf(c,"%d%s%d%s",Re_a*Re_b-Im_a*Im_b,"+",Re_a*Im_b+Im_a*Re_b,"i");
free(t1);
free(t2);
free(t3);
free(t4);
return c;
}
效果还不错~就是太费内存。
唉,当我在解决一个问题时,顺着自己的思路,不断花费时间试错,最后只得到一个勉强的结果,殊不知早有极其简洁优美屡试不爽的解决办法早已被别人设计,在等着我了。
这就是没好好学习的结果吧…>_<
无知的代价是可怕的,虽然探索的过程是愉悦的。
这件事,好坏参半吧…
继续前进哦,You gotta move and move on.
2020.12.28