【C语言练习】——找出单身狗、详解atoi函数

news/2024/11/16 9:16:54/

目录

    • 一.找出单身狗
      • 版本1
      • 版本2
    • 二.atoi函数
      • 介绍atoi函数
      • atoi函数的模拟实现

一.找出单身狗

版本1

题目:
一个数组中只有一个数字是出现一次,其他所有数字都出现了两次
找出这一个只出现一次的数字

一个数组比如是1、2、3、4、5、1、2、3、4
只有5出现一次,其他数字都是成对出现的,所以5就是单身狗。

思路:异或法
这里给大家回顾下异或:相同为0,相异为1

比如:
a ^ a = 0
a ^ 0 = a

异或是支持交换律的,用具体数字举例:3 ^ 5 ^ 3

3的二进制是011
5的二进制是101
异或的结果是110
再和3异或
得到的是101——数字5

3 ^ 3 ^ 5

3和3异或是0
0和5异或是5

所以回到前面举例的数组

1、2、3、4、5、1、2、3、4

也等价于:

1、1、2、2、3、3、4、4、5

前面成对出现的数字都异或为0(0异或0还是0),0与唯一出现的数字异或就是这个数字,也就是单身狗

代码:

int F_S_dog1(int arr[], int sz)
{int ret = 0;int i = 0;for (i = 0; i < sz; i++){ret ^= arr[i];}return ret;
}
int main()
{int arr[] = { 1,2,3,4,5,1,2,3,4 };int sz = sizeof(arr) / sizeof(arr[0]);int dog = F_S_dog1(arr, sz);printf("%d\n", dog);return 0;
}

版本2

题目:
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次
找出这两个只出现一次的数字

一个数组比如是1、2、3、4、5、6、1、2、3、4
只有5和6出现一次,其他数字都是成对出现的,所以5和6就是单身狗。

思路:

  1. 将数组进行分组处理,每组有一个单身狗,其他数字成对出现
  2. 成对的数字在同一组里,然后采用异或法找出单身狗

比如分组后为:

1、1、3、3、5
2、2、4、4、6

那么任何进行分组呢?
首先,用版本1的思路我们可以先对原数据进行异或处理,就可以找到那两个是单身狗的数字

1 ^ 1 ^ 2 ^ 2 ^ 3 ^ 3 ^ 4 ^ 4 ^ 5 ^ 6 = 5 ^ 6

5和6异或的结果一定不为0

5的二进制是101
6的二进制是110
异或为011

也就是说5和6异或的结果的二进制后面两位是不同的

以最低位为例,5的最低位是1,6的最低位是0,那么分组就可以根据最低位来判断

1的最低位是1,2的最低位是0,
3的最低位是1,4的最低位是0,
分组后:
1、1、3、3、5
2、2、4、4、6

假如不是5和6,是6和8,最低位相同,那么可以用前面一位比较,方法同上

但不管怎么分,都可以把两个单身狗数字分到不同的组

第二步,找出两个数异或的结果第几位不同
还是前面的两个数字5和6,异或的结果为011,后面两位不同。为了方便起见,使用一个变量(pos)记录最低位不同是移动了几位,移动pos位按位与得到是1就说明两个数字二进制的这一位不同(也就是1,因为1按位与1得到的是1),然后跳出循环。

最后一步,正式开始分组,然后还是异或法找到单身狗
数组的每个元素移动pos位,把移动pos按位与相同的数字放在同一组,然后异或法找到单身狗

当然,只是找到其中一个单身狗,另一个单身狗就是两个单身狗异或的结果再异或前面已经找到的单身狗

代码:

void F_S_dog2(int arr[], int sz, int* pd1, int* pd2)
{int ret = 0;int i = 0;//找到两个唯一的数for (i = 0; i < sz; i++){ret ^= arr[i];}int pos = 0;//找到第几位不同for (i = 0; i < 32; i++){if ((ret >> i & 1) == 1){pos = i;break;}}//分组for (i = 0; i < sz; i++){if ((arr[i] >> pos & 1) == 1){*pd1 ^= arr[i];}}*pd2 = ret ^ *pd1;
}
int main()
{int arr[] = { 1,2,3,4,5,6,1,2,3,4 };int sz = sizeof(arr) / sizeof(arr[0]);int dog1 = 0;int dog2 = 0;F_S_dog2(arr, sz, &dog1, &dog2);printf("%d %d", dog1, dog2);return 0;
}

二.atoi函数

介绍atoi函数

atoi函数的作用是将字符串转换成整数

int atoi (const char * str);

该函数有以下几点要注意
在这里插入图片描述

1.返回值为int 类型的整数,不能超出int 表示的范围
2.该函数首先根据需要丢弃尽可能多的空格字符(如 isspace) ,直到找到第一个非空格字符。然后,从这个字符开始,取一个可选的初始正负号,后跟尽可能多的十进制数字,并返回一个数值
3.字符串可以在构成整数的字符之后包含其他字符,这些字符将被忽略
4.如果 str 中的第一个非空格字符序列不是一个有效的整数,或者由于 str 为空或者它只包含空格字符而不存在这样的序列,则不执行转换并返回零

代码:

#include <stdio.h>
#include <stdlib.h>
int main()
{int ret = atoi("-456");printf("%d\n", ret);return 0;
}

在这里插入图片描述

atoi函数的模拟实现

首先要考虑几个问题:

1.传过来的字符串是否为空指针
2.是否为空字符串
3.有空格字符怎么办
4.遇到正负号
5.是否为数字字符
6.数值太大

接下来一个一个解决问题:

1.传过来的字符串是否为空指针
可以用assert进行断言,防止为空

assert(str);

2.是否为空字符串
加个判断条件,如果为’ \0 ',就返回0

    if (*str == '\0'){return 0;}

3.有空格字符怎么办
使用isspace函数判断是否有空格字符,如果有,向后走一步

    while (isspace(*str)){str++;}

4.遇到正负号
在此之前定义一个变量flag为1,如果遇到 ’ - ',flag=-1,向后走一步;遇到 ’ + ’ ,向后走一步。

    if (*str == '-'){flag = -1;str++;}else if (*str == '+'){str++;}

5.是否为数字字符 && 6.数值太大
使用isdigit函数判断是否为数字字符,如果不是,也就是说刚开始就遇到其他字符或者在中途遇到其他字符,就直接返回前面的数字字符;如果是数字字符,每次循环的值等于上次的值乘以10再加上数字字符减去字符0,得到整数。
还要加上一个判断,如果要返回的值超过int 类型的范围,说明返回值为异常,直接返回0。

    long long ret = 0;while (*str){if (isdigit(*str)){ret = ret * 10 + flag * (*str - '0');if (ret<INT_MIN || ret>INT_MAX){return 0;}}else{return (int)ret;}str++;}

最后的返回值处理
定义一个枚举,如果是VALID,标记为是正常的返回值,是INVALID,标记为异常的返回值。同时给个全局变量State,只有最后让State等于VALID,就说明返回的是正常的值,其他的则为异常。

enum State
{VALID,INVALID
}State = INVALID;//全局变量判断是否为异常的返回值
	State = VALID;return (int)ret;

代码:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
enum State
{VALID,INVALID
}State = INVALID;//全局变量判断是否为异常的返回值
int my_atoi(const char* str)
{int flag = 1;//判断空指针assert(str);//判断空字符串if (*str == '\0'){return 0;}//判断空格字符while (isspace(*str)){str++;}//遇到正负号if (*str == '-'){flag = -1;str++;}else if (*str == '+'){str++;}//返回整数值,遇到其他字符直接返回long long ret = 0;while (*str){if (isdigit(*str)){ret = ret * 10 + flag * (*str - '0');if (ret<INT_MIN || ret>INT_MAX){return 0;}}else{return (int)ret;}str++;}//正常返回State = VALID;return (int)ret;
}
int main()
{int ret = my_atoi("   -456ab21");if (State == VALID){printf("%d\n", ret);}else{printf("异常返回:%d\n", ret);}return 0;
}

在这里插入图片描述

感谢观看~
在这里插入图片描述


http://www.ppmy.cn/news/1028027.html

相关文章

Python-OpenCV中的图像处理-霍夫变换

Python-OpenCV中的图像处理-霍夫变换 霍夫变换霍夫直线变换霍夫圆环变换 霍夫变换 霍夫(Hough)变换在检测各种形状的技术中非常流行&#xff0c;如果要检测的形状可以用数学表达式描述&#xff0c;就可以是使用霍夫变换检测它。即使要检测的形状存在一点破坏或者扭曲也是可以使…

阿里云账号注册入口_账户注册详细流程(图文)

阿里云账号怎么注册&#xff1f;阿里云账号支持手机号注册、阿里云APP注册、支付宝和钉钉多种注册方式&#xff0c;账号注册后需要通过实名认证才可以购买或使用云产品&#xff0c;阿里云百科来详细说下不同途径注册阿里云账号图文流程&#xff1a; 目录 阿里云账号注册流程 …

MySql012——检索数据:创建计算字段(拼接字段、使用别名、执行算术计算)

准备工作1&#xff1a;在study库中创建表vendors&#xff0c;并插入数据 说明&#xff1a;vendors表包含供应商名和位置信息。 use study;CREATE TABLE vendors (vend_id int NOT NULL AUTO_INCREMENT,vend_name char(50) NOT NULL ,vend_address char(50) NULL ,…

vue报错‘vue-cli-service‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

运行我的后台管理项目的时候报错&#xff1a;‘vue-cli-service’ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 查看自己package.json中是否有vue 或者vue-cli-service 查看自己项目目录下有没有node_module文件夹&#xff0c;如果有删除&#xff0c;然后…

vue中有趣的几个功能

vue中有趣的几个功能 老实说&#xff0c;我们大多数人都不太喜欢阅读文档&#xff0c;但是当使用像 Vue 这样不断发展的现代前端框架时&#xff0c;每个新版本都会发生很多变化&#xff0c;我们可能会错过一些后来推出的新的、闪亮的功能。让我们来看看那些有趣但不那么受欢迎…

删除块参照 删除块定义

删除块参照 void CDwgDatabaseUtil::DeleteBlockReference(CString strBlockName) {// 锁定文档acDocManager->lockDocument(acDocManager->curDocument());AcDbObjectId objRecId;if (

学习内容散记

git下载网址 &#xff1a;https://registry.npmmirror.com/binary.html?pathgit-for-windows/ error: remote origin already exists 如果你clone下来一个别人的仓库&#xff0c;在此基础上完成你的代码&#xff0c;推送到自己的仓库可能遇到如下问题&#xff1a; error: r…

Spring-Cloud-Loadblancer详细分析_2

LoadBalancerClients 终于分析到了此注解的作用&#xff0c;它是实现不同服务之间的配置隔离的关键 Configuration(proxyBeanMethods false) Retention(RetentionPolicy.RUNTIME) Target({ ElementType.TYPE }) Documented Import(LoadBalancerClientConfigurationRegistrar…