July大神交大读书会子atoi

来源:互联网 发布:北理工 大数据联盟 编辑:程序博客网 时间:2024/05/17 02:53

犹记得July大大在今年交大一次读书会上让大家10min写这个算法,然后讲解这个算法,我是通过百度网盘的视频看的,我10min没写出来,而且还是在输出exception case的几次提示下才AC掉的,而且关于需求分析还差了cplusplus的说明= =


今天写了这个函数,一开始想估计有千万种情况考虑,但是细细一想,其实也是可以枚举出来的,关键就是逻辑要能处理所有的case,

我已开始居然连需求都没弄清楚,他是允许非法字符的,只要前面有一些可以产生数值的,例如-9a.986返回-9,-9.a8a77a 返回-9,这感觉有点奇怪,我觉得出现非 + - . 0-9的就都是非法了,不知道系统设计出于什么目的。


设计逻辑了,前缀我主要分为4种:

1) [+|-]   [(0-9)上加号] [非法或.]

2) [(0-9)上加号] [非法或.]      

3) [+ | -] .

4) .

主要分为这些,然后先看第一个是否符号位,是的话i++, 然后这时判断i是否越界(每次i++ i--都要判断是否可能越了上下界,有的话就特殊处理,我又一次就这么错了),如果是的话,说明只有符号位,返回非法字符。否则从后面找连续的数字,然后同时loop 要判断是否越界,发现越界可以统一处理~ 然后后面算值,这部分比较简单,我又一次居然直接用ASCII码算= = 然后最后如果负数的话,根据之前的 符号判断,sum-=2*sum, 我出现正负数一起处理都是这样把两者统一成正数处理,这样逻辑比较清晰。


还有最最难想到的就是溢出了,从给的case来看如果上溢返回上届,下溢返回下届,所以需要再加完之后就判断,我之前还在最后判断发现已经没用了,sum已经因为溢出错了= = 然后如果上溢了,就返回上届,因为int是补码范围,负变正后负数最大会多一个,也即-2^31,但是发现这个case可以统一到里面,因为2^31溢出恰好变为-2^31,于是直接返回下届是对的。


我还有一次直接写2^31-1结果就不知道C++认为是什么了= =(后来发现了,是异或操作,2^31得到29然后-1得28,发现2^31=29=31-2,好像还有点规律可以挖掘)我有时候还会犯从数学到代码转换的一个缺口,甚至左右赋值都写错过一次,感觉程序设计和数学思维会有些不同


最后的最后,附上修改几次后的代码:

int myatoi(const char* str){string cppstr=str, intstr;istringstream istr(cppstr);int isnegative=false,i=0;while(istr>>intstr){if(intstr.at(0)=='-'){isnegative=true;i++;}if(intstr.at(0)=='+'){i++;}if(i==intstr.size())//whether only  + -   return 0;if(intstr.at(i)=='.')return 0;int starti=i;while(i<intstr.size()&&intstr.at(i)<='9'&&intstr.at(i)>='0')i++;int endi=i-1;int sum=0,weighti=0;for(int k=endi;k>=starti;k--,weighti++)sum+=(intstr.at(k)-'0')*pow(10.0, weighti);if(sum<0) //overflow{if(isnegative==false)return pow(2.0,31)-1;elsereturn -pow(2.0,31);}if(isnegative==true)sum-=2*sum;return sum;}if(intstr.size()==0)return 0;}

代码质量太差了,这个是经典面试题,考察程序员的鲁棒性能力。


一下是代码,需要注意

1.正负号

2.上下溢出

3高位到低位逐个移动,计算sum和从低位的区别

4.用isdigit里面是字符,不是数值,例如'0' '9'

5. 判溢出要注意 >214748364 或者= 214748364 && *str>='8' 要这样,之前犯了一次错误

下面的是代码


int atoi(const char* str){bool flag=1;while((*str)==' ') str++;if((*str)=='+') str++,flag=1;else if((*str)=='-') str++,flag=0;int sum=0;while(isdigit(*str)){if(flag){if(sum >214748364 || sum==214748364 && (*str)>='8' ) {return (int)((1<<31)-(unsigned int)1);}}else{if(sum>214748364 || sum==214748364 && (*str)>='9') {return (int)(1<<31);}}sum*=10;sum+=((*str)-'0');str++;}return flag? sum : -sum;}

这个代码应该是比较简洁版的。实现较为方便。


 

0 0
原创粉丝点击