atoi函数模拟实现和解决单身狗问题(C语言实现)

atoi函数模拟实现和解决单身狗问题(C语言实现)_第1张图片

文章目录

  • atoi函数
    • 模拟实现
  • 单身狗问题
    • 方法1:暴力解决
    • 方法2:排序解决
    • 方法3:异或解决

atoi函数

这是个非常有趣的函数,它的功能是把字符串中的数字转化为一个整数。
但是其中的坑是有不少的,我们往下面分析分析。
atoi函数模拟实现和解决单身狗问题(C语言实现)_第2张图片
先来使用体会体会:

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 

int main()
{
     
	char arr[] = " -123 45+  ";
	char arr2[] = "+34896  ";
	char arr3[] = "abc235";
	char arr4[] = "+2335+11";
	char arr5[] = "++567  ";
	printf("%d\n", atoi(arr));
	printf("%d\n", atoi(arr2));
	printf("%d\n", atoi(arr3));
	printf("%d\n", atoi(arr4));
	printf("%d\n", atoi(arr5));
	return 0;
}

atoi函数执行结果:
atoi函数模拟实现和解决单身狗问题(C语言实现)_第3张图片

模拟实现

刚开始的时候觉得模拟实现atoi函数很简单,转化一下数字嘛,但是在上面使用过后就感受到复杂了。它的要求有以下几点要注意:
1、不能传空指针过来
2、转化有范围限制,超出范围就返回0
3、能转化的字符只有:正负号、空格、数字,其它字符都不能转化
4、转化过数字,就不能再转化其它字符
5、转化过正负号,后面就不能再转化正负号

模拟实现如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include 
#include 
#include 

int my_atoi(const char* p)
{
     
	if (p == NULL) //传过来空指针就直接返回
	{
     
		return 0;
	}
	int flag = 1;   //检测+-符号,正号为1,负号就为-1
	int tmp = 1;    //检测转化过数字和正负号没有,转化过就置为0
	int ret = 0;    //接收数字
	while (*p != '\0')
	{
     
		if (*p <= '9' && *p >= '0')
		{
     
		     ret = 10 * ret + flag * (*p - '0');
			 if (ret< INT_MIN || ret> INT_MAX) //验证整数在有效范围
			 {
     
				 return 0;
			 }
			 tmp = 0;  //转化过数字,置为0
			 p++;
		}
		//检测第一次遇到正负号,而已经转化过到这里就不符合条件
		else if (*p == '+' && tmp != 0)
		{
     
			p++;
			flag = 1;
			tmp = 0;
		}
		else if (*p == '-' && tmp != 0)
		{
     
			p++;
			flag = -1;
			tmp = 0;
		}
		//检测没转化过数字和正负号之前遇到空格,而已经转化过到这里就不符合条件
		else if (*p == ' '&& tmp != 0)
		{
     
			p++;
		}
		else
		{
     
			//跳到这里分为以下几种情况:
			//1.不是数字
			//2.已经转化过数字再遇到正负号
			//3.已经转化过数字再遇到空格
			//以上都不符合条件,结束检测字符串
			break;
		}
	}
	return ret;
}

int main()
{
     
	char arr[] = " -123 45+  ";
	char arr2[] = "+34896  ";
	char arr3[] = "abc235";
	char arr4[] = "+2335+11";
	char arr5[] = "++567  ";
	printf("库函数atoi实现结果:\n");
	printf("%d\n", atoi(arr));
	printf("%d\n", atoi(arr2));
	printf("%d\n", atoi(arr3));
	printf("%d\n", atoi(arr4));
	printf("%d\n\n", atoi(arr5));
	printf("模拟atoi实现结果:\n");
	printf("%d\n", my_atoi(arr));
	printf("%d\n", my_atoi(arr2));
	printf("%d\n", my_atoi(arr3));
	printf("%d\n", my_atoi(arr4));
	printf("%d\n", my_atoi(arr5));
	return 0;
}

程序执行结果对比如下:
atoi函数模拟实现和解决单身狗问题(C语言实现)_第4张图片

单身狗问题

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

方法1:暴力解决

最简单粗暴的方法就是每一位数字都与数组中除了自己之外的元素遍历一遍,如果没有找到相同的就说明就是单身狗。
代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include 

void Find(int* p, int sz)
{
     
	int i = 0, j = 0;
	for (i = 0; i < sz; i++)
	{
     
		//每一位数字都与数组中除了自己之外的元素遍历一遍
		for (j = 0; j < sz; j++)
		{
     
			//找到相同的数字就跳出第二层循环
			//j肯定不等于sz
			if (p[i] == p[j] && i != j)
			{
     
				break;
			}
		}
		//如果不是break跳到这里,则没有找到相同数字
		//j肯定等于sz,p[i]就是单身狗
		if (j == sz)
		{
     
			printf("%d ", p[i]);
		}
	}
}
int main()
{
     
	int arr[] = {
      5,5,9,4,6,2,4,6,1,2 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Find(arr, sz);
}


程序执行结果:
atoi函数模拟实现和解决单身狗问题(C语言实现)_第5张图片

方法2:排序解决

一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。这句话给了我们不少信息,说明如果数组从小到大排序好的话,那么两个相邻元素不相等的话,前者肯定是单身狗。
解决思路: 第一步我们先用冒泡排序把数组元素从小到大排序好,然后我们在逐一验证两个相邻元素是否相等,如果相等那就下标就自增2,如果不相等说明前者是单身狗,并且下标自增1,直到找完数组中元素。
代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include 

//冒泡排序把数组排成有序
void BubbleSort(int* p, int sz) 
{
     
	int i = 0, j = 0;
	for (i = 0; i < sz - 1; i++)
	{
     
		int flag = 1;
		for (j = 0; j < sz - 1 - i; j++)
		{
     
			if (p[j] > p[j + 1])
			{
     
				flag = 0;
				int tmp = p[j];
				p[j] = p[j + 1];
				p[j + 1] = tmp;
			}
		}
		if (flag == 1)
		{
     
			return;
		}
	}
}

//在有序数组中找单身狗
void Search(int* p, int sz)
{
     
	int i = 0;
	while (i < sz)
	{
     
		//相邻元素相等下标自增2
		if (p[i] == p[i+1])
		{
     
			i+=2;
		}
		//相邻元素不相等下标自增1
		//并且前者是单身狗
		else
		{
     
			printf("%d ", p[i]);
			i++;
		}
	}
}

int main()
{
     
	int arr[] = {
      5,5,9,4,6,2,4,6,1,2 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	BubbleSort(arr, sz);
	Search(arr, sz);
}

程序执行结果:
在这里插入图片描述

方法3:异或解决

这个方法不易想到,构思非常巧妙,是今天的重点菜。
我们知道两个相同的元素异或是什么结果?不错就是为0。那么根据题目内容:
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。所以定义一个变量tmp,把数组中的元素从第一位异或到最后一位保存到变量tmp中会出现什么结果呢?
结果就是变量tmp是两个单身狗数字异或的内容。

可问题来了,我们求的是两个单身狗,而不是要异或的内容呀!不急不急,接着分析,
当我们知道两个单身狗异或的内容后,结果转化为二进制后,里面肯定至少有一位不同,因为每一位都相同的话就不是两个不同的数字了。

而至少有一位不同,那变量tmp中肯定有一位为1,其中单身狗不同的一位是0,另外一个单身狗不同的一位是1。
所以我们在tmp中从右边往左边找到1的下标num,异或结果中第一个1的下标就找到了。
而在数组中相同的数字二进制位下标num也是0或者1,所以我们把数组中所有元素都与1左移num位 并 过一遍,大于或者等于1的就再异或一遍,最终得到一个单身狗,并的结果为0的也异或一遍,最终也到一个单身狗。相当于把两个单身狗放在不同的数组中进行异或。
代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include 

void Find(int* p, int sz)
{
     
	int i = 0;
	int tmp = 0; //把数组中异或的结果放在tmp中
	for (i = 0; i < sz; i++)
	{
     
		tmp = tmp ^ p[i];
	}
	//在异或结果中找第一个为1的下标是多少
	for (i = 0; i < 32; i++)
	{
     
		if (tmp & (1 << i))
		{
     
			break;
		}
	}
	int num = i; //把下标保存到num中
	int sum1 = 0;
	int sum2 = 0;
	for (i = 0; i < sz; i++)
	{
     
		//数组中元素并上 1左移num位的元素分不同结果 进行异或
		//结果大于或者等于1为一组
		if (p[i] & (1<<num))
		{
     
			sum1 = sum1 ^ p[i]; 
		}
		//结果为0是为一组
		else
		{
     
			sum2 = sum2 ^ p[i];
		}
	}
	//最终得到两个单身狗
	printf("sum1=%d  sum2=%d\n", sum1, sum2);

}

int main()
{
     
	int arr[] = {
      5,5,9,4,6,2,4,6,1,2 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Find(arr, sz);
	return 0;
}

程序执行结果:
atoi函数模拟实现和解决单身狗问题(C语言实现)_第6张图片

atoi函数模拟实现和解决单身狗问题(C语言实现)_第7张图片

你可能感兴趣的