左神算法笔记(异或)+C语言实现

1 篇文章 0 订阅

性质

1、相同为0,不同为1
记为不进位相加

运算性质

2、异或运算的性质:A^0=A A^A=0
满足交换律、结合律(多个^顺序不影响答案)

应用举例

1、不用额外变量,交换两个数的值

a=a^b
b=a^b
a=a^b

原理

	int a=甲,int b=乙
    a = 甲^乙
    b = 甲^乙^乙
    a = 甲^乙^乙^甲^乙
 	(前提:a,b地址不同)

代码

#include <stdio.h>

int change(int a,int b) {
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("a=%d\nb=%d",a,b);
	return 0;
}

2、找到数组中唯一一个出现奇数次的数字

全部异或起来即可

3、提取最右侧的1(常用)

A&(~A)+1

应用1:找到数组中唯二出现的两个出现奇数次的数字

先找到数组全部异或起来以后结果最右侧的1出现在哪一位x

根据第x位是1或0将数组分成两组,分别全部异或,即得结果。

代码

#include <stdio.h>
#include <stdlib.h>

int two_oddTimes_numb(int list[], int size) {
	int i, j ,rightone;
	int eor = 0;
	for (i = 0; i < size; i++) {
		eor ^= list[i];
	}
	rightone = eor & (~eor) + 1;
	//用&实现分组^
	int ans = 0;
	for (j = 0; j < size;j++) {
		if ((list[j] & rightone) != 0) {
			ans ^= list[j];
			printf("%d\n",list[j]);
		}
	}
	char string1[33],string2[33],string3[33];
	_itoa_s(eor, string1, 33, 2);
	_itoa_s(ans, string2, 33, 2);
	_itoa_s(ans^eor, string3, 33, 2);
	printf("库函数得到的二进制为:%s\r\n", string1);
	printf("库函数得到的二进制为:%s\r\n", string2);
	printf("库函数得到的二进制为:%s\r\n", string3);
	printf("两个出现奇数次的数为:%d和%d\n",ans,ans^eor);
	return 0;
}

刚学C,一开始没有初始化eor,以为是默认的0,结果编译可以通过,编译器也没给我提示必须必须初始化。就是结果不对,懵了很久。
结果原因就是C没有默认是0的说法,只声明一个变量只会给他一块地址,里面还有之前系统放的垃圾数据(操作系统回收内存空间时,并不清空该内存空间中遗留下来的数据
编译器如果发现一个变量里面存放的是一个垃圾值,就认为没有给它赋初值,那么系统就会自动将一个很小的,如 –858993460 这个填充数字给放进去。所以我们看到的结果都是一个不变的值。
还有就是直接printf未初始化的数据会报错,使用这个未初始化的数进行一番操作以后再printf又不会报错了。
我用的visual studio 2022版的,转二进制的时候报itoa()不能用了,要用_itoa_s(int 要转换的数字,char 存放转换结果的字符串,size_t 存放结果的字符数组长度,int 转化的进制数,2表示2进制,10表示10进制),比原来多了一个字段,size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数。

应用2:找到二进制有多少1

只要还不是1,就一直和自己提取的右边第一个1^,同时计数。

代码

#include <stdio.h>
#include <stdlib.h>

int find_1Times(int a) {
	char str[33];
	_itoa_s(a, str, 33, 2);
	printf("二进制为:%s\n", str);

	int times = 0,tmp =0;
	while (a != 0) {
		//去掉最后一个1
		tmp = a & ((~a) + 1);
		times++;
		a ^= tmp;
	}
	printf("有%d个1\n", times);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值