求一个二进制数中有多少个1
思路是对这个数进行对2取余操作,每次如果对2取余的结果是1,那么这个二进制的数中的1的个数就加一
然后进行这个操作后,对数进行除2操作
知道循环结束我们就可以得到这个二进制数中含有多少个1
int CountNum1(unsigned int n)
{
int count = 0;//计数变量
while (n)
{
if (n % 2 == 1)//对2取余判断结果
{
count++;
}
n /= 2;//对原数据除2
}
return count;
}
其实这个操作是针对十进制数进行操作
其实还可以对位运算进行操作
把除2操作变成位运算中的右移
int CountNum2(unsigned int n)
{
int count = 0;
while (n)
{
count += n & 0x1;
n >>= 1;
}
return count;
}
n>>=1,这个位运算操作就是除2动作
反之n<<=1,左移一个单位就是给n乘以2的一次方
还有一种位运算格式是每次丢掉二进制数右边的一个一,然后就对计算变量加一
int CountNum3(unsigned int n)
{
int count = 0;
while (n)
{
n &= n - 1;//每次都丢弃最右边的1
count++;
}
return count;
}
然后还有个更加简便的操作——查表法
顾名思义就是当我们要找某个二进制数中的一时,我们有提前记录的数据,然后直接在表里查询即可
这种方法在数据体量不大的前提下是一种很好的方法
int counttable[256] = { 0,1,1,2,1,2,2,3,1 };
int CountNum(int n)
{
return counttable[n];
}
int main()
{
printf("1的二进制中有%d个1\n", CountNum(1));//1
printf("2的二进制中有%d个1\n", CountNum(2));//1
printf("3的二进制中有%d个1\n", CountNum(3));//2
printf("4的二进制中有%d个1\n", CountNum(4));//1
printf("5的二进制中有%d个1\n", CountNum(5));//2
printf("6的二进制中有%d个1\n", CountNum(6));//2
printf("7的二进制中有%d个1\n", CountNum(7));//3
printf("8的二进制中有%d个1\n", CountNum(8));//1
printf("-1的二进制中有%d个1\n", CountNum(-1));//32
return 0;
}
但是这个需要提前计算各个二进制的数字中有多少个一,这个需要的前期准备就要多很多
求数组中唯一不成对的一个数字
比如数组:1 4 7 0 2 7 4 1 0,返回2;
方法1:排序
方法2:从头到尾把所有数字异或(因为相同数字按位异或结果为0)
第一种方式就是通过一个排序函数对整个数组进行排序,然后可以使用两个指针,一个从尾部遍历,一个从头部遍历如果有相同的就继续,如果有不同我们就可以将这个数输出
这个方法比较基础,我们可以使用位运算——"^",我们知道相同的数进行”^“操作后会变成0,那我们可以将所以的数据全部^在一起,相同的^操作之后变成0,然后剩下那个唯一不成对的数
int GetUnpaired(int* arr, int len)
{
int tmp = 0;
for (int i = 0; i < len; i++)
{
tmp ^= arr[i];
}
return tmp;
}
int main()
{
int arr[] = { 1,4,7,0,2,7,4,1,0 };
int number = GetUnpaired(arr, sizeof(arr) / sizeof(arr[0]));
printf("%d\n", number);
return 0;
}
求数组中两个不成对的一个数字
例如数组: 1,2,4,5,4,5,1,2,6,7
要返回其中两个不成对的数字
我们可以将这个数据分成两组,然后采用上一题同样的方法,那么我们分组的依据是什么
我们分组的依据是这两个不同的数的^结果中第几个是1
struct Pairs
{
int a;
int b;
};
Pairs GetUnpaireTwo(int* arr, int len)
{
Pairs pair = { 0,0 };
int tmp = 0;
for (int i = 0; i < len; i++)
{
tmp ^= arr[i];
}
if (tmp == 0)
{
printf("所有的数字都成对\n");
return pair;
}
//求tmp右数的第一个1即a;
int a = 0x1;
while ((tmp & a) != 1)
{
a <<=1;
}
//以a作为分组依据
for (int i = 0; i < len; i++)
{
if ((arr[i] & a) == 1)
{
pair.a ^= arr[i];
}
else
{
pair.b ^= arr[i];
}
}
return pair;
}
需要注意的是我们要返回一个数对,就是有两个数的数对
我们还可以用返回参数的方式进行操作,其实就是在传入形式参数时传入指针
bool GetSubscript(int* arr, int len, int* sub1, int* sub2, int sum)
{
assert(arr != NULL && sub1 != NULL && sub2 != NULL && len > 0);
int i = 0;
int j = len - 1;
while (i < j)
{
if (arr[i] + arr[j] == sum)
{
*sub1 = i;
*sub2 = j;
return true;
}
else if (arr[i] + arr[j] > sum)
{
j--;
}
else
{
i++;
}
}
return false;
}
int main()
{
int sub1, sub2;
int arr[] = { 1,2,5,9,10,15 };
int len = sizeof(arr) / sizeof(arr[0]);
if (GetSubscript(arr, len, &sub1, &sub2, 9))
{
printf("和为7的下标为%d %d\n", sub1, sub2);
}
else
{
printf("没有和为9的两个数字!");
}
return 0;
}