- 写一个函数返回参数二进制中 1 的个数
- 比如: 15 0000 1111 4 个 1 比如: 15 0000 1111 4 个 1
程序原型:
int count_one_bits(unsigned int value)
{
// 返回 1的位数
}
第一种方法,模2除2
这个题目是算出一个十进制数的二进制序列里有多少个1,自然数中任意一个数除以二的余数不是1就是0,我们将要计算的数除以2,这个操作就会把这个数的二进制序列的最后一位右移得到一个新的数字,每除一次,如果余数是1,我们定义一个count作为计数器记录一次,余数若是0,则继续除以2,直到得到的新的数字为0为止,由此可知,这是一个循环。
举个栗子,假设a=13,那么它的二进制序列为1101,
13/2=6-----1 13(二进制)=1101 6(二进制)=0110
6/2=3------0 6(二进制)=0110 3(二进制)=0011
3/2=1------1 3(二进制)=0011 1(二进制)=0001
1/2=0------1 1(二进制)=0001 0(二进制)=0000
具体代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int count_one_bits(unsigned int n)
{
int count = 0;
//1101-13
//0110-13/2=6
//0011-3/2=3
//0001-3/2=1
while (n)
{
if (n % 2 == 1)
{
count++;
}
n = n / 2;
}
return count;
}
int main()
{
int a = 13;
int ret = count_one_bits(a);
printf("%d\n", ret);
return 0;
}
第二种方法,按位与
这种方法采用了按位与的方式,比如,a=13,a(二进制)=1101,a-1(二进制)=1100,将这两个数按位与,也就是a&(a-1)=1100,此时,这个数的二进制中只剩下两个1
同样方法,a=1100,a-1=1011,a&(a-1)=1000,此时二进制序列中只剩下一个1
令a=1000,a-1=0111,a&(a-1)=0000,此时a的二进制序列中已经没有1,这个方法就是将二进制序列中的1从右到左依次取掉,仍然可以用一个循环来完成,同时设置一个计数器count,每按位与依次,count便记录一次,最终得到的count就是二进制序列中1的个数。
具体代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int count_one_bits(unsigned int n)
{
int count = 0;
while (n)
{
n = n&(n - 1);
count++;
}
return count;
}
int main()
{
int a = 13;
int ret = count_one_bits(a);
printf("%d\n", ret);
return 0;
}
- .获取一个数二进制序列中所有的偶数位和奇数位,
分别输出二进制序列。
这个题目其实不难,想要得到一个数二进制的奇数位和偶数位,只要将从该奇数位以后的数字右移,再将右移后的二进制按位与1,就可得到这个数二进制的奇数位与偶数位。
按位与1的作用是,得到右移后的二进制序列的最后一位,如果是1,就得出1,如果是0则为0,。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void printf_num(unsigned n)
{
int i = 32;
//输出奇数
for (i = 31; i >= 0; i -= 2)
{
printf("%d", (n >> i)&1);
}
printf("\n");
//输出偶数
for (i = 30; i >= 0; i -= 2)
{
printf("%d", (n >> i)&1);
}
return NULL;
}
int main()
{
int a =11;
printf_num(a);
return 0;
}
3.输出一个整数的每一位
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int n = 235;
int tmp = 0;
while (n)
{
tmp = n % 10;
printf("%d", tmp);
n = n / 10;
}
return 0;
}
- 5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果
A选手说:B第二,我第三;
B选手说:我第二,E第四;
C选手说:我第一,D第二;
D选手说:C最后,我第三;
E选手说:我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int a = 0, b = 0, c = 0, d = 0, e = 0;
for (a = 1; a <= 5; a++)
{
for (b = 1; b <= 5; b++)
{
for (c = 1; c <= 5; c++)
{
for (d = 1; d <= 5; d++)
{
for (e = 1; e <= 5; e++)
{
if ((2 == b && 3 != a) || (2 != b && 3 == a) == 1)
{
if ((2 == b && 4 != e) || (2 != b && 4 == e) == 1)
{
if ((1 == c && 2 != d) || (1 != c && 2 == d) == 1)
{
if ((5 == c && 3 != d) || (5 != c && 3 == d) == 1)
{
if ((4 == e && 1 != a) || (4 != e && 1 == a) == 1)
{
if (((a != b) && (a != c) && (a != d) && (a != e))
&& (b != c) && (b != d) && (b != e)
&& (c != d) && (c != d)
&& (d != e))
printf("a=%d b=%d c=%d d=%d ", a, b, c, d);
}
}
}
}
}
}
}
}
}
}
return 0;
}
- 日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个
嫌疑犯的一个。以下为4个嫌疑犯的供词。
A说:不是我。
B说:是C。
C说:是D。
D说:C在胡说
已知3个人说了真话,1个人说的是假话。
现在请根据这些信息,写一个程序来确定到底谁是凶手。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
char k = 0;
for (k = 'a'; k <= 'd'; k++)
{
if (3 == ((k != 'a') + (k == 'c') + (k == 'd') + (k != 'd')))
printf("凶手是:%c\n", k);
}
return 0;
}
- 在屏幕上打印杨辉三角。
1
1 1
1 2 1
1 3 3 1
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int i = 0;
int j = 0;
int arr[10][10] = { 0 };
for (i = 0; i < 10; i++)
{
for (j = 0; j < 10; j++)
{
if (j == 0)
arr[i][j] = 1;
if (i == j)
arr[i][j] = 1;
if (i >= 2 && j >= 1)
arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
}
}
for (i = 0; i < 10; i++)
{
for (j = 0; j < i; j++)
{
printf("%d", arr[i][j]);
}
printf("\n");
}
return 0;
}
- unsigned int reverse_bit(unsigned int value);
这个函数的返回值value的二进制位模式从左到右翻转后的值。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
unsigned int reverse_bit(unsigned int value)
{
int i = 0;
unsigned int sum = 0;
for(i=0; i<32; i++)
{
sum <<= 1;
sum |= ((value>>i)&1);
}
return sum;
}
int main()
{
int num = 25;
unsigned int ret = reverse_bit(num);
printf("%u\n", ret);
return 0;
}
- 不使用(a+b)/2这种方式,求两个数的平均值。
由于使用(a+b)/2的方式会导致溢出的情况,首先来看溢出的定义:
对一个N位二进制补码,其可以表达的范围是 - 2N-1+1 ~ 2N+1 - 1之间。如果超出这个范围就称为溢出了。
前面的例子是很简单的例子,请看下面这个例子:
-2 - 6
-2 --> 1110
-6 --> 1010
相加 --------
结果 11000 ,原序列为4为,相加之后为5位,这就是溢出的情况。
第一种方法(a+(a-b)/2)
如图所示,
具体代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int a = 13;
int b = 3;
int ret = (b + (a - b) / 2);
printf("%d\n", ret);
return 0;
}
第二种方法使用了按位与的方法
用a和b相同的部分加上a和b不同的地方,a和b相同的部分为(a&b),a和b不同的部分为(a ^ b),不同的部分除以二就是(a^b>>1)
具体代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int a = 13;
int b = 3;
//int ret = (b + (a - b) / 2);
int ret = ((a&b) + (a^b) >> 1);
printf("%d\n", ret);
return 0;
}
- 编程实现:
一组数据中只有一个数字出现了一次。其他所有数字都是成对出现的。
请找出这个数字。(使用位运算)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4 };
int num = 0;
int i = 0;
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
num ^= arr[i];
}
printf("%d\n", num);
return 0;
}
- 有一个字符数组的内容为:“student a am i”,
请你将数组的内容改为"i am a student".
要求:
不能使用库函数。
只能开辟有限个空间(空间个数和字符串的长度无关)。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int Strlen(const char* str)
{
int count = 0;
assert(str);
while (*str)
{
count++;
str++;
}
return count;
}
void reverse_str(char *left, char *left)
{
assert(left);
assert(right);
while (left < right)
{
char *tmp = left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void reverse(const char *str, int len)
{
assert(str);
//逆序整个字符串
reverse_str(str, str + len - 1);
//逆序单词
while (*str)
{
char *start = str;
while ((*str == ' ') && (*str != '0'))
{
str++;
}
reverse_str(start, str - 1);
if (*str != '\0')
str++;
}
}
int main()
{
char arr[] = "student a am i";
int len = Strlen(arr);
reverse(arr, len);
printf("%s\n", arr);
return 0;
}
- .编程实现: 一组数据中只有一个数字出现了一次。其他所有数字都是成对出现的,请找出这个数字。(使用位运算)
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4 };
int num = 0;
int i = 0;
for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
num ^= arr[i];
}
printf("%d\n", num);
return 0;
}