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 。
作者:文琼
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 。
作者:文琼
相关文章推荐
- Java Spring RPC Hessian 学习笔记
- dojo事件驱动编程之事件绑定
- python list to string
- js中cookie的使用详细分析
- 安装centos后无法引导启动windows7的解决方法
- iOS&&Swift入门(二)App图标
- HDU 5322 Hope (CDQ分治+NTT)
- 求多边形的质心hdu1115
- 关于哪些标签的默认宽度的总结
- 读书笔记MoreEffectiveC++(29)
- 黑马程序员——集合框架collection集合接口及List子类
- 合并两个排序的链表
- 浏览器中展示地图
- disabled属性的启用和禁止
- MAC显示与隐藏文件夹
- Win10更新 800240020 错误代码解决办法
- 数据库服务器mysql性能调优
- Java 学习笔记
- VFS
- 封装 字符串