库函数atoi的实现和单身狗思路

😏库函数atoi的实现和单身狗思路

<作者:丘比特,大梦想 日期:2023.2.9>

不管怎样,生活还是要继续向前走去。有的时候伤害和失败不见得是一件坏事,它会让你变得更好,孤单和失败亦是如此。每件事到最后一定会变成一件好事。只要你走到最后。

在这里插入图片描述

找两个单身狗思路

在作这道题之前我们先来看这样一道题,假设只有一个单身狗,这样该怎么找呢?

一般人最开始想到的可能是暴力解法

第一种解法:

两层for循环对每个元素进行细数记录每个元素出现的次数,如果只出现一次的话,则加以记录。

但是这样的话时间复杂度却是O(n^2)效率有点低

第二种解法:

开辟临时数组来记录每个数的出现情况,但是这个数组要足够大,能供容纳,出现的数据的次数
在这里插入图片描述

这个解法也有它的弊处,就是当数据达到一个量级的时候就无法达到记录 的目的了

第三种解法

在了解这个解法之前我们要对按位异或操作符有足够的理解,相同为0,相异为1。了解到这一点,我们观察数列可得到,除了单身狗没有重复的数,其他都有。所以如果数列中只有一个单身狗的时候就可以利用到按位异或的性质。,将其他重复的数字消除,留下单身狗。

int find_dog1(int * p,int sz)
{
    int x = p[0];
    int i = 0;
    for(i = 1;i < sz;i++)//将数组中的第一个数放到x中然后依依按位异或
    {
        x ^= p[i];
	}
    return x;
}//这就是找一个单身狗的思路。

那么,将这个方法映射到寻找两个单身狗,那么我们就要应该将总问题细化为一个单身狗的情况。那就要进行分组即可,那么分组的依据是啥呢?两个不同的单身狗,一定有不同的那一二进制位。那么该如何找到这两个单身狗二进制不同的位呢??我们可以将单身狗的二进制位的区别映射到异或的结果中。只要判断异或的结果哪一位是1即可,并且加以记录。然后,动态开辟两个元素数组,来记录根据二进制位分成的两组分别异或的结果,即可得到两个单身狗。

int * find_dog2(int * p,int sz)
{
    int x = p[0];
    for(i = 0;i < sz;i++)
    {
        x ^= p[i];
	}
    for(i = 0;i < 32;++i)
    {
        if( (x >> i) & 1)
        {
            int tem = i;//记录相异的那一位
        }
    }
    //进行分组,然后分别异或
    //进行遍历
    int * p1 = (int*)malloc(sizeof(int) * 2);//开辟记录单身狗数组
    //对动态数组进行初始化
    memset(p1,0,8);
    for(i = 0;i < sz;i++)
    {
        if((p[i] >> tem)&1)
        {
            p1[0] ^= p[i];
		}
        if(!(p[i] >> tem) & 1)
        {
            p1[1] ^= p[i];
		}
	}
    return p1;
    
}

atoi函数实现

库函数参数以及作用详解:

我们先来看看库中的参数和作用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-osV1G76y-1675926036994)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230209123146919.png)]

参数分析:

传入一个字符串或者是字符数组

返回值

返回整型数值

作用:

将字符中的数值类字符串提取出来,返回。

具体实现

在实现这个函数之前我们来测试一下这个函数的一些特性:

#include<stdlib.h>
#include<stdio.h>
int main()
{
    printf("%d\n",atoi("*22223"));
    printf("%d\n",atoi("22*3"));
    printf("%d\n",atoi("-1234"));
    printf("%d\n",atoi("     -1234"));
    printf("%d\n",atoi("22222222222222222222222222222222222222"));
    return 0;
}

测试结果:

![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VxdcsHMR-1675926036994)(C:\Users\Lenovo\AppData\Roaming\Typora\typora-user-images\image-20230209125715043.png)](https://img-blog.csdnimg.cn/8a59ecfd95174ae2be4af084a7aeef3a.png)

看到上边的结果,可以略微窥见atoi函数的一点真容。

  • 当读取到非法字符即不读了返回之前读取的数
  • 对于负号也是可以进行读取的,正号也可以
  • 当正常数值字符串前有空格字符的时候

所以,我们要对这些特点一一还原,而且还要对一些极端情况进行反应

  1. 如果传入空字符串
  2. 如果传入空指针
//字符串是否为合法;
enum global
{
    error,
    right,
}judge;//在主函数判断是否合法
int my_atoi(const char * p)
{
    //传进来的有可能是空指针
    assert(p);
    //还有可能是空字符串
    judge = right;
    if(!*p)
    {
        judge = error;
        return EOF;
    }
    //刨除空格
    int flag = 1;
    //int ret = 0;不能用整形来存储数据因为如果用整型存储的话,一旦溢出就会截断没法正确判断
    long long ret = 0;
    while (isspace(*p))
    {
        p++;
        /* code */
    }
    if(*p == '-')
    {
        flag = -flag;
        p++;
    }
    else if(*p == '+')
    {
        p++;
    }
    
    //判断是不是正经符号符号
    while(*p)
    {
        //ret *= 10;放在这里乘的话会导致中间停止的时候多一位
         if(isdigit(*p))
        {
            ret = ret*10 + (*p - '0')*flag;
            if(ret > INT_MAX)
            {
                return INT_MAX;
            }
            if(ret < INT_MIN)
            {
                return INT_MIN;
            }
        }
        else
        {
            return ret;
        }
        p++;
    }
    return ret;
}

结语

Linus Torvalds Quote: “Talk is cheap. Show me the code.”

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

难扰浮生梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值