【C语言】操作符相关编程题

本文介绍了C语言中不创建临时变量交换两个数的两种方法,以及如何通过位操作统计二进制中1的个数、修改特定位和判断三角形类型。还涉及到了变种水仙花数的查找和整数二进制奇偶位打印。
摘要由CSDN通过智能技术生成

目录

题目一:

题目二:

题目三:

题目三:

题目四:

题目五:

题目六:

题目七:

题目八:


题目一:

题目:不创建临时变量,交换两个数。

思路:(方法一:交换律思想)

  • 先将两个数相加赋值给num1,此时num1为两数之和
  • 接着对赋值后的num1 - num2,即6-2,此时的结果就是一开始num1的值,赋值给num2此时num2存储了一开始num1的值
  • 最后两数之和 - num2,可以得出一开始num2的值,赋值给num1,就完成交换
  • 缺陷:可能溢出,当两个数太大时,相加可能超出整形大小
#include<stdio.h>

//不创建临时变了,交换两个数
int main()
{
	int num1 = 4;
	int num2 = 2;
	printf("交换前:%d %d\n", num1, num2);
	num1 = num1 + num2;
	num2 = num1 - num2;
	num1 = num1 - num2;
	printf("交换后:%d %d\n", num1, num2);
	return 0;
}

思路:(方法二:异或操作符法)

  • 异或的特殊性:
  1. 两个相同的数进行异或 == 0,因为异或是相同为0,相异为1.
  2. n^0 == n,为什么?因为0的二进制为32个0,则任何数的二进制要么为0要么1,当对应二进制位为0时,则为0,为1时,则为1,本质上没有改变。
  3. 异或支持交换律,如:3^5^3 == 5 等价于 3^3^5 == 5
#include<stdio.h>

//不创建临时变了,交换两个数
int main()
{
	int num1 = 4;
	int num2 = 2;
	printf("交换前:%d %d\n", num1, num2);
	num1 = num1 ^ num2;
	num2 = num1 ^ num2; //拆分成:num2 = num1^num2^num2 异或支持交换律,因此值为变化前的num1
	num1 = num1 ^ num2; //拆分成:num1 = num1^num2^num2(num1),num2的值其实就是变化前的num1,
	//因此值为变化前的num2
	printf("交换后:%d %d\n", num1, num2);
	return 0;
}


题目二:

题目:编写代码实现:求一个整数存储在内存中的二进制中1的个数。

思路1:

  • 题目要求统计一个整数的二进制中有多少个1.
  • 对该整数按位与上一个1即可。
  • 按位与:对二进制进行操作,一个为0,结果为0,两个为1才为1.
  • 因此对一个数按位与1,可以判断该数的最低位是否为1.
  • 判断完之后对该数进行右移操作,移动1位,持续对最低位进行判断。
#include<stdio.h>
int main()
{
	int n = 0;
	scanf("%d", &n);
	int count = 0;

	//循环32次是因为一个整数4字节,32比特,由32个二进制组成
	for (int i = 0; i < 32; i++)
	{
		//n&1,判断最低位是否为1
		if (n & 1)
		{
			count++;
		}
		//无论最低位是1还是0,均更新最低位,即右移
		n = n >> 1;
	}
	printf("%d的二进制中有:%d个1\n", n, count);
	
	return 0;
}

思路2:采用相邻的两个数进行按位与操作(非常高效)

  • &:1个0都为0,两个1才为1
  • res和res-1的二进制有什么区别?假设res==3
  • res:....011;res-1:....010
  • res&res-1结果:010,因此可以得出,一个res-1后,得到的二进制位将是res二进制最右侧的1变为0的二进制
  • 再进行&操作后,就能得到res二进制位中将1个1变为0的二进制数
  • 因此,只要不断的重复,当最后res变为0了,也就说明res中的1被全部去除
  • 因此循环多少次,就代表res中1的个数
#include<stdio.h>
int main()
{
	int n = 0;
	scanf("%d", &n);
	int count = 0;
	while(n)
    {
        n = n & (n-1);
        count++;
    }    
	printf("%d的二进制中有:%d个1\n", n, count);
	return 0;
}

题目三:

题目:假设把一个数的二进制中某一位改为1,其它位不变

思路:

  • 利用位操作符的特性,对该数的二进制中第n位进行按位或1操作,其它位均或0,则只会改变第n位上的二进制为1.
  • 按位或:一个为1则为1,两个为0才为0.
  • 对第n位按位或1,当第n位时1时,则为1,是0时,也为1.
  • 如何得到这个二进制序列呢?通过对1左移n-1位。
#include <stdio.h>
int main()
{
	int num = 0;
    int n = 0;
    scanf("%d %d", &num, &n);
	//对num二进制中第n修改为1
	num = num | (1 << n-1);
	printf("%d\n", num);
	return 0;
}

如果现在又想将该位改为0该怎么做?也就是对一个数的某个二进制为改为0

思路:

  • 同样的,针对于二进制中的某一位,那对该位按位与0。
  • 按位与:一个为0则为0,两个为1才为1。
  • 如果该位是1,那按位与0则为0,如果该位是0,那按位与0也为0.
  • 如何得到这个二进制序列呢?分为两步:
  • 首先得到刚刚对某一位二进制改为1的二进制序列,对它进行取反操作。说简单点就是对1左移n-1位。
  • 对该二进制序列按位取反操作。
#include <stdio.h>
int main()
{
	int num = 0;
    int n = 0;
    scanf("%d %d", &num, &n);
	//对num二进制中第n修改为1
	num = num | (1 << n-1);
	printf("将该位改为1:%d\n", num);
    num = num & (~(1<<n-1));
    printf("将该位改为0:%d\n", num);
	return 0;
}


题目三:

题目:打印整数二进制的奇数位和偶数位

描述:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列

思路:

  • 获取一个数二进制位中的最低位:n & 1,能得出n的最低位是0还是1.
  • 因此计算一个数二进制的偶数位和奇数位,只需要控制好每次按位与第几个二进制位就可以了。
  • 奇数位:写得出高位中最后一个奇数位,即第31位,打印后,不断-2得到下一个奇数位,这就需要通过>>操作符了。
  • 偶数位:同样的,写对第32位进行打印,再不断-2得到下一个偶数位。通过>>操作符。
#include <stdio.h>
int main()
{
	int a = 2; //010
	//获取二进制的偶数位
	for (int i = 31; i >= 1; i-=2)
	{
		printf("%d ", (a >> i) & 1);
	}
	printf("\n");
	//获取二进制的奇数位
	for (int i = 30; i >= 0; i-=2)
	{
		printf("%d ", (a >> i) & 1);
	}
	return 0;
}

题目四:

题目两个整数二进制位不同个数_牛客题霸_牛客网 (nowcoder.com)

描述:

输入两个整数,求两个整数二进制格式有多少个位不同

输入描述:

两个整数

输出描述:

二进制不同位的个数

示例:

输入:22 33

输出:5

思路:

分为两部分:

  • 对两个整数进行异或操作,因为异或的特点为:相同为0,相异为1。因此结果中二进制位1的个数就是不同的个数。
  • 统计res中有几个1。
#include <stdio.h>
int Comp_func(int res)
{
	//方法一:>>和&操作
	//检查res中的二进制位有几个1,就是不同的个数
	//res&1能得到最低位是0还是1,int32个二进制位,那就不断更新最低位进行&
	//如何不断得到最低位呢?res>>i
	int count = 0;
	// for (int i=0; i<32; i++) {
	//     if ((res>>i)&1) {
	//         count++;
	//     }
	// }
	//方法二:利用&的特性,对两个相邻的数进行&操作(非常高效)
	//&:1个0都为0,两个1才为1
	//res和res-1的二进制有什么区别?假设res==3
	//res:....011;res-1:....010
	//res&res-1结果:010,因此可以得出,一个res-1后,得到的二进制位将是res二进制最右侧的1变为0的二进制
	//再进行&操作后,就能得到res二进制位中将1个1变为0的二进制数
	//因此,只要不断的重复,当最后res变为0了,也就说明res中的1被全部去除
	//因此循环多少次,就代表res中1的个数
	while (res) {
		res = res & (res - 1);
		count++;
	}
	return count;
}
int main() {
	int a, b;
	scanf("%d %d", &a, &b);
	//a^b, 异或的特点:相同为0,相异为1
	//a^b 后,相同的二进制位变为0,不同的变为1
	int count = Comp_func(a ^ b);
	printf("%d\n", count);
	return 0;
}

题目五:

题目:有序序列合并_牛客题霸_牛客网 (nowcoder.com)

描述:

输入两个升序排列的序列,将两个序列合并为一个有序序列并输出。
输入描述:输入包含三行
第一行包含两个正整数n, m,用空格分隔。n表示第二行第一个升序序列中数字的个数,m表示第三行第二个升序序列中数字的个数。
第二行包含n个整数,用空格分隔。
第三行包含m个整数,用空格分隔。
输出描述:输出为一行,输出长度为n+m的升序序列,即长度为n的升序序列和长度为m的升序序列中的元素重新进行升序序列排列合并。

示例:
输入:
5 6
1 3 7 9 22
2 8 10 17 33 44
输出:
1 2 3 7 8 9 10 17 22 33 44

思路:

  1. 定义一个n+m大小的数组res
  2. 依次将n和m个整数输入到res中
  3. 对res进行冒泡排序
#include <stdio.h>
int main() {
    int n = 0;
    int m = 0;
    scanf("%d %d", &n, &m);
    int res[n+m];
    for (int i = 0; i < n; i++) {
        scanf("%d", &res[i]);
    }
    for (int i = n; i < n + m; i++) {
        scanf("%d", &res[i]);
    }
    //排序,冒泡排序(升序)
    //外层循环控制趟数,内存循环控制一趟的比较次数
    for (int i = 0; i < n + m - 1; i++) {
        for (int j = 0; j < n + m - 1 - i; j++) {
            //升序
            if (res[j] > res[j + 1]) {
                int tmp = res[j];
                res[j] = res[j + 1];
                res[j + 1] = tmp;
            }
        }
    }
    for (int i = 0; i < n + m; i++) {
        printf("%d ", res[i]);
    }
}

题目六:

题目:小乐乐走台阶_牛客题霸_牛客网 (nowcoder.com)

描述:

小乐乐上课需要走n阶台阶,因为他腿比较长,所以每次可以选择走一阶或者走两阶,那么他一共有多少种走法?
输入描述:输入包含一个整数n (1 ≤ n ≤ 30)
输出描述:输出一个整数,即小乐乐可以走的方法数。

示例1:

输入:2
输出:2

示例2:

输入:10
输出:89

思路:参考【C语言】青蛙跳台阶问题-CSDN博客

  • n==1,只有1种跳法
  • n==2,只有两种跳法
  • n>2时,统计只走一阶台阶的方法 + 只走两阶的方法 == 总走法
  • 递归
#include <stdio.h>
int function(int n)
{
	//n为1时,只有1种走法
	if (n == 1) {
		return 1;
	}
	//n为2时,只有2种走法
	if(n == 2) {
		return 2;
	}
	//n>2时,统计只走一阶台阶的方法 + 只走两阶的方法 == 总走法
	//需要用到递归
	return function(n-1) + function(n-2);
}
int main()
{
	//青蛙跳台阶问题
	int n = 0;
	scanf("%d", &n);
	int count = function(n);
	printf("%d\n", count);
	return 0;
}

题目七:

题目:变种水仙花_牛客题霸_牛客网 (nowcoder.com)

描述:

变种水仙花数 - Lily Number:把任意的数字,从中间拆分成两个数字,比如1461 可以拆分成(1和461),(14和61),(146和1),如果所有拆分后的乘积之和等于自身,则是一个Lily Number。

例如:

655 = 6 * 55 + 65 * 5

1461 = 1*461 + 14*61 + 146*1

求出 5位数中的所有 Lily Number。

输入描述:

输出描述:

一行,5位数中的所有 Lily Number,每两个数之间间隔一个空格。

思路:

运用%和/操作符,不断得到每个位数,如:n=12345,n%10==5,n/10=1234,进行相乘n%100=45,n/100=123,进行相乘.....依此类推

#include <stdio.h>
int main()
{
	for (int i=10000; i<=99999; i++) {
		
		//统计每个数拆分相乘后相加的值
		int sum = 0;
		for (int j=10; j<=10000; j*=10) {
			sum += (i/j) * (i%j); 
		}
		//判断sum是否等于i,如果是,则符合
		if (sum == i) {
			printf("%d ", i);
		}
	}

	return 0;
}

题目八:

题目:三角形判断_牛客题霸_牛客网 (nowcoder.com)

描述:

KiKi想知道已经给出的三条边a,b,c能否构成三角形,如果能构成三角形,判断三角形的类型(等边三角形、等腰三角形或普通三角形)。

输入描述:

题目有多组输入数据,每一行输入三个a,b,c(0<a,b,c<1000),作为三角形的三个边,用空格分隔。

输出描述:

针对每组输入数据,输出占一行,如果能构成三角形,等边三角形则输出“Equilateral triangle!”,等腰三角形则输出“Isosceles triangle!”,其余的三角形则输出“Ordinary triangle!”,反之输出“Not a triangle!”。

思路:

构成三角形的要求:两边之和大于第三边

三角形的类型:

  • 等腰三角形:两边相等
  • 等边三角形:三边相等
  • 普通三角形:三边均不相等
#include <stdio.h>
int main() {
    //三边
    int a = 0;
    int b = 0;
    int c = 0;
    while (scanf("%d %d %d", &a, &b, &c) == 3) {
        //首先判断是否能构成三角形
        if (a + b > c && a + c > b && b + c > a) {
            //此时至少两条边相等,但也可能三条边相等
            if (a == b || a == c || b == c) {
				//三边相等-->等边三角形
				if (a == b && b == c) {
                	printf("Equilateral triangle!\n");
				}else { //等腰三角形
                	printf("Isosceles triangle!\n");	
				}
            }
			else {
                printf("Ordinary triangle!\n");
            }
        } else {
            printf("Not a triangle!\n");
        }
    }
    return 0;
}

  • 29
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值