/*
一个数组中只有两个数字是出现一次,
其他所有数字都出现了两次。
找出这两个数字,编程实现。
*/
//思路:
//一个数与另个数异或两次,结果为原数.
//1.考虑将两个只出现一次的数分别放到两个不同的数组中;
//2.保证1的条件下,不能使出现两次的数分到不同数组中;
//3.两个不同的数异或,总有至少一个二进制位为1;
//4.其中的1就是这两个数的分歧点;
//5.可以任取一个为1的二进制位对数组元素进行分组.
//所以先让数组各元素与0异或,最终得两个只出现一次的数的异或结果
//再找到这个数的最低且为1的二进制位,利用这一点将数组元素分组,
//最后用0分别与两数组中的元素异或,就得到两个只出现一次的数.
#include<stdio.h>
#include<stdlib.h>
//找一个数的最低且为1的二进制位函数
int find_min1_bit(int n){
int count = 0;
int i;
for (i = n; i; i >>= 1){ //遍历n每一位
if (i & 1 == 1){ //若i此时的最低二进制位为1
break; //跳出循环
}
else{
++count; //count加1
}
}
return count;
}
//找一个出现一次的数函数(返回该值)
int first_occur_number(int arr[],int len){
int i;
int num = 0;
for (i = 0; i < len; ++i){ //遍历异或,找只出现一次的数
num ^= arr[i];
}
return num;
}
//利用二进制位分解数组函数
void divide_array_by_bit(int arr[8],int arr1[8],int arr2[8],int position){
int i;
for (i = 0; i < 8; ++i){ //遍历数组将元素按第position位为0和1分为两组
if (arr[i] & (1 << position) == 1){ //若元素第position位为1
arr1[i] = arr[i]; //将元素放入数组arr1
}
else{ //若元素第position位为1
arr2[i] = arr[i]; //将元素放入数组arr2
}
}
}
//主函数
int main(){
int arr[8] = { 1, 2, 3, 5, 3, 2, 1, 6 };
int arr1[8] = { 0 };
int arr2[8] = { 0 };
int len; //用以保存数组arr的长度
int num; //用以保存两个只出现一次的数的异或结果
int position; //用以保存一个数的最低且为1的二进制位的位数
len = sizeof(arr) / sizeof(arr[0]); //计算数组arr的长度
num = first_occur_number(arr,len); //调用找找一个出现一次的数函数
position = find_min1_bit(num); //调用找一个数的最低且为1的二进制位函数
divide_array_by_bit(arr, arr1, arr2, position); //调用利用二进制位分解数组函数
int number1 = first_occur_number(arr1, len); //调用找找一个出现一次的数函数
int number2 = first_occur_number(arr2, len); //调用找找一个出现一次的数函数
printf("%d %d\n", number1, number2); //打印输出结果
system("pause");
return 0;
}