求一组数据中仅出现了一次的元素(其余元素都是成对出现的)

题目:一组数据中有部分数字仅出现了一次,其他所有数字都是成对出现的, 请找出这些数字。

例如,1,3,2,5,5,3,2,7,1,9。

要求:

1.使用位运算。

2.不能创建除存储数据以外的新的数组   。  

3.使用函数,并且函数中不能出现打印语句  。

题目分析: 首先,我们需要创建一个数组来存储,在函数参数传递的过程中数组的长度是必须要传的,因为在数组传递过程中传递的数组首元素的地址,所以我们需要在main函数中计算数组的长度并且创建一个变量来存放这个长度以便传参。接下来就是封装功能函数了,因为我们要得到仅出现一次的元素,所以我们需要完成将数组整体异或,因为异或运算后会将成对出现的元素异或为0,0与任何元素异或得到的结果都是那个“任何元素”,;然后运用位运算找到整体异或后得到的数的二进制序列中从右往左数的第pos位为1的位;最终分割数组运用位运算将数组中的每个元素右移pos位再与1按位与,将结果为1的元素与结果不为1元素分别放到两个变量x、y中,再与x,y进行异或得到最终结果。(在这里我们不用担心仅出现过一次的元素的pos位会相同,然后会被分割到一个数组中,因为我们使用的是仅出现1次的元素异或后二进制序列中从右往左的第pos位为1的数,异或的特点是相异为1,所以仅出现过一次的元素的第pos位肯定是不一样的)。

解题要点:运用位运算将数组中的每个元素右移pos位再与1按位与,将结果为1的元素与结果不为1元素分别放到两个变量x、y中,再去与x,y进行异或得到最终结果。

在此我们使用题目中的例子具体分析:

整体异或:

	//将数组整体异或
	int i = 0;
	int sum = 0;
	for (i = 0; i < len; i++)
	{
		sum = sum^arr[i];
	}
	//最终sum=7^9=14==>1110;

找到sum的二进制序列中从右往左数的第pos位为1的位:

	int i = 0;
	for (i = 0; i < 32; i++)   //整形为4个字节,32个比特位
	{
		if (((sum >> i) & 1) == 1)//将sum右移i位,然后与1相与,结果如果等于1,将i赋值给pos
		{
			pos = i;//将该位赋给pos
			break;
		}
	}

分割数组:

	//分割数组,因为我们使用的是7和9异或后从右往左的第pos位为1的数,异或的特点是相异为1,所以7和9的第pos位肯定是不一样的,进而将数组分割成两部分
	int i = 0;
	for (i = 0; i < len; i++)
	{
		if (((arr[i] >> pos) & 1) == 1)
		{
			*px = *px^arr[i];//得到数组中每一个元素的第pos位与1按位与后结果为1的元素,用这些元素与*px按位异或得到数组中仅出现过一次的元素

		}
		else
		{
			*py =*px^arr[i];//得到数组中每一个元素的第pos位与1按位与后结果不为1的元素,用这些元素与*p按位异或得到数组中仅出现过一次的元素
		}
	}

整代码:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
void Function(int *arr,int len,int *px,int *py) //功能函数,创建指针int *px,int *py接收参数x,y的地址
{
	int i = 0;
	int sum = 0;
	int pos = 0;
	//将数组整体异或
	for (i = 0; i < len; i++)
	{
		sum = sum^arr[i];
	}
	//最终sum=7^9=14==>1110;
	//找到sum的二进制序列中从右往左数的第pos位为1的位
	for (i = 0; i < 32; i++)   //整形为4个字节,32个比特位
	{
		if (((sum >> i) & 1) == 1)//将sum右移i位,然后与1相与,结果如果等于1,将i赋值给pos
		{
			pos = i;//将该位赋给pos
			break;
		}
	}
	//分割数组,因为我们使用的是7和9异或后从右往左的第pos位为1的数,异或的特点是相异为1,所以7和9的第pos位肯定是不一样的,进而将数组分割成两部分
	for (i = 0; i < len; i++)
	{
		if (((arr[i] >> pos) & 1) == 1)
		{
			*px = *px^arr[i];//得到数组中每一个元素的第pos位与1按位与后结果为1的元素,用这些元素与*px按位异或得到数组中仅出现过一次的元素

		}
		else
		{
			*py =*px^arr[i];//得到数组中每一个元素的第pos位与1按位与后结果不为1的元素,用这些元素与*p按位异或得到数组中仅出现过一次的元素
		}
	}
	
}

int main()
{
	int x = 0;
	int y = 0;
	int arr[] = { 1, 3, 2, 5, 5, 3, 2, 7, 1, 9 };//创建数组arr并初始化数组
	int len = sizeof(arr) / sizeof(arr[0]);//计算数组的长度
	Function(arr, len, &x, &y);//调用功能函数,将x,y以地址的形式传参
	printf("%d %d\n", x, y);
	system("pause");
	return 0;

}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值