首先,一个数组里面的元素可能是奇数个也可能是偶数个。同时,判断数组里的数是否成对出现有三种情况:可能有一个单数、也可能没有、还有可能有两个单数。
当数组个数奇数时:
- 例如{1,3,5,7,1,3,5};
数组不全成对出现,且只可能有一个单数,全部异或的结果为那个单数。
当数组个数偶数时:
例如{1,3,5,1,3,5};
数组成对出现,全部异或的结果为0。例如{3,5,7,3, 5, 11};
数组不全成对出现,有2个单数。
此时,每个数依次异或的结果为:0011^0101^0111^0011^0101^1011=1100。
因为后边两位是0,则说明两个单数是从倒数三位不同的。然后让每个数右移两位 则数据会变为
3: 0000
5: 0001
7: 0001
3: 0000
5: 0001
11:0010
然后把末尾为零的依次异或 在这组数据里是3 3 11; 结果得到单数11。
把末尾为1的依次异或 在这组数据里是5 7 5;结果得到单数7。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void find_num(int *p, int sz)
{
int num = 0;
int num1 = 0;
int num2 = 0;
int i = 0;
int count = 0;
int n = 0;
if ((sz % 2) == 1) //数组个数为奇数
{
for (i = 0; i < sz; i++)
{
num = num ^ *(p + i); //所有数异或结果为单数
}
printf("单数:%d\n", num);
}
else //数组个数为偶数:一种是没有单数 还有是两个单数
{
for (i = 0; i < sz; i++)
num = num^ *(p + i);
if (num == 0) //所有数异或结果为零说明没有单数
{
printf("没有单数\n");
}
else //有两个单数
{
while (!(num & 1))
{
count++;
num = num >> 1;
}
for (i = 0; i < sz; i++)
{
n = p[i] >> count; //所有数异或结果后面有几个0,
//每个数依次往右移动几位
if (n & 1) //把末位为1的数依次异或
{
num1 = num1 ^ *(p + i);
}
else //把末位为0的数依次异或
{
num2 = num2 ^ *(p + i);
}
}
printf("两个单数 :\n%d\n%d\n ", num1, num2);
}
}
}
void display(int *p, int sz)
{
int i = 0;
printf("数组为:\n");
for (i = 0; i < sz; i++)
printf("%d ", p[i]);
printf("\n");
}
int main()
{
int arr[] = { 1, 3, 5, 7, 1, 8, 3, 5 };
int sz = sizeof(arr) / sizeof(arr[0]);
display(arr, sz)
find_num(arr, sz);
system("pause");
return 0;
}