您的位置:首页 > 其它

atoi的一个实现

2015-07-30 01:09 197 查看
leetcode 上有一道实现 atoi 题目。两年前我参加百度校招面试就被问到过这个题目。解决一个问题的方法很多,最简单的方法自然是用一个现成的方法解决之。譬如:

c++ 简单版本:
#include <sstream>

class Solution {
public:
int myAtoi(string s) {
int v {0};
std::istringstream stream {s};
stream >> v;
return v;
}
};
[/code]

c 简单版本:
#include <stdlib.h>
#include <limits.h>

int myAtoi(char* s) {
long long v = atoll(s);
return v > INT_MAX ? INT_MAX : v < INT_MIN ? INT_MIN : v;
}
[/code]

c++ 版本对应的 c 版本: sscanf(str, "%d", &v) 是无效的,因为 c 没有规定溢出下的情况,而 c++ 有。恰好, c++ 溢出时的处理和本道题目一致,故方法真的很简单。

如果要重新发明 atoi 的轮子(面试的时候就是酱紫!),而不是用轮子替代轮子,下面是一个参考实现:
#include <limits.h>

#define is_digit(a) ((a) >= '0' && (a) <= '9')
#define is_space(a) ((a) == ' ' || (a) == '\t')

int myAtoi(char* s) {
if(!s || !*s) return 0;
while(is_space(*s)) ++s;

int sign = *s != '-';
if(*s == '+' || *s == '-') ++s;
if(!is_digit(*s)) return 0;

unsigned v = *s - '0', upper = sign > 0 ? INT_MAX : INT_MIN;;
while(*++s && is_digit(*s)){
if(v > upper/10 || (v = v * 10 + (*s-'0')) > upper){
return sign ? INT_MAX : INT_MIN;
}
}
return sign ? v : -v;
}
[/code]

最核心部分不是计算,而是溢出的判断。溢出的判断有多种方法:

使用 long long 判断是否溢出:一般来说 sizeof(int) < sizeof(long long),这样的话,试用 long long 直接保存 int * 10 + int 的结果没有问题,然后和 INT_MAX、INT_MIN 对比;
将 *10 操作转化为加法操作,然后使用符号改变来判断溢出;
比较 v 和 MAX/10、-INT/10 的大小,判断溢出(这里采用的方法)。

不采用第一种方法不是因为其不好,而是某些地方不够通用,譬如我们求 atoll,这样哪来的更长的 int 呢?第二种方法比较通用,就是需要多次计算加法。 第三种简单些,也通用些,但有些基本假定,譬如 sizeof(int) 长度不能太短,需要保证 UINT_MAX - INT_MAX > 9 !那么 int 至少得 5 位,几乎所有系统都满足的吧!

注:补充几句。补码表示的整数在正负取值上并不对称,譬如 32 位整数的 INT_MAX = 2147483647,INT_MIN = -2147483648,UINT_MAX = 4294967295 。

作者:文琼
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: