算法很美第一章(位运算的奇技淫巧)例题代码(C++实现)

1.找出唯一成对的数

1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现。

分析:两个相同的数进行异或(^)运算得到0

//找出唯一成对的数
#include
#include
using namespace std;
int main(){
	int N = 11;
	int tmp=0;
	int  arr[N];
	int index = rand()%(N-1);
	for(int i=0;i<N;i++){
		arr[i] = i+1;
	}
	arr[N-1] = index+1;
	cout<<"打印数组:" ;
	for(int i=0;i<N;i++)
		cout<<arr[i]<<" ";
	cout<<endl;
	for(int i=0;i<N;i++){
		tmp=tmp^(i);
	}
	for(int i=0;i<N;i++){
		tmp=tmp^arr[i];
	}
	cout<<"重复的数字是"<<tmp<<endl; 
	return 0;
} 

2.找出落单的数

一个数组里除了某一个数字之外,其他的数字都出现了两次,请写程序找出这个只出现一次的数字
分析:同1

//找出落单的数
#include
using namespace std;
int main(){
	int N = 10;
	int arr[2*N+1];
	cout<<"打印数组:" ;
	for(int i=0;i<2*N+1;i++){
		arr[i] = i/2;
		cout<<arr[i]<<" ";
	}
	cout<<endl;
	int tmp=0;
	for(int i=0;i<2*N+1;i++){
		tmp = tmp^arr[i];
	}
	cout<<"落单的数字是"<<tmp<<endl;
	return 0;
} 

3.二进制中1的个数

请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。
例: 9的二进制表示为1001,有2位是1
分析:与(&)运算,n&(n-1)可以消去一个数最低位上的1

//二进制数中1的个数
#include
using namespace std;
int numberOfOne(int n){
	int number=0;
	while(n){
		n = n&(n-1);
		number++;
	}
	return number;
}
int main(){
	cout<<"9中有"<<numberOfOne(9)<<"个1"<<endl;
	return 0; 
} 

4.判断一个整数是不是2的整数次方

用一条语句判断一个整数是不是2的整数次方
分析:同3

//判断一个整数是不是2的整数次方 
#include
using namespace std;
int main(){
	int n=8;
	if (n>0&&n^(n-1))
		cout<<"是2的整数次方";
	else
		cout<<"不是2的整数次方";
} 

5.将整数的奇偶位互换

将一个数的二进制表示中的奇数位和偶数位互换
分析:使用&运算分别提取出奇数位和偶数位,然后用>>和<<移动一位后用|或^运算相加。

//将整数的奇偶位互换
#include
using namespace std;
int main(){
	int ou = 0xaaaaaaaa;
	int ji = 0x55555555;
	int m =9;
	int n1,n2;
	n1 = m&ou;
	n2 = m&ji;
	n1 = n1>>1;
	n2 = n2<<1;
	cout<<(n1^n2)<<endl;
} 

6.0~1之间浮点实数的二进制表示

给定一个介于0和1之间的实数,(如0.625),类型为double,打印它的二进制表示(0.101,因为小数点后的二进制分别为0.5,0.25,0.125……)。
如果该数字无法精确用32位以内
分析:乘2,挪整

//0~1之间浮点实数的二进制表示
#include
#include 
#include
using namespace std;
int main(){
	double n = 0.3;
	string str="0.";
	bool flag = true;
	while(n>0){
		n*=2;
		if(n>=1){
			str.append("1");
			n = n-1;
		}
		else
			str.append("0");
		if(str.size()>34){
			cout<<"ERROR";
			flag = false;
			break;
		}
	}
	if(flag)
		cout<<str<<endl;
} 

7.出现k次与出现1次

数组中只有一个数字出现了一次,其他的数都出现了k次,请输出只出现了1次的数
分析:先转为k进制,做不进位加法,
K个相同的K进制数进行无进位加法,相加的结果一定是每一位上都为0的K进制数

//出现k次与出现1次 
#include
#include
#include
using namespace std;
string dectok(int n, int k){
	string str = "";
	while(n>0){
		str += n%k+'0';
		n /= k;
	}
	reverse(str.begin(),str.end());
	return str;
}
int ktodec(string n,int k){
	int dec = 0;
	for(int i=0;i<n.size();i++){
		dec += (n[i]-'0')*pow(k,n.size()-i-1); 
	}
	return dec;
}
int main(){
	int k = 3;
	int arr[16]={2,2,2,9,7,7,7,3,3,3,6,6,6,0,0,0};
	string str[sizeof(arr)/sizeof(arr[0])];
	cout<<"打印数组:" ;
	for(int i=0;i<sizeof(arr)/sizeof(arr[0]);i++){
		cout<<arr[i]<<" ";
	}
	cout<<endl;
	int maxlen=0,tmp; 
	//将十进制数转为k进制,并计算k进制字符的最大长度 
	for(int i=0;i<sizeof(arr)/sizeof(arr[0]);i++){
		str[i]=dectok(arr[i],k);
		tmp = str[i].size();
		maxlen=max(tmp,maxlen);
	}
	//将所有字符都补成一样的长度,方便进行不进位加法 
	for(int i=0;i<sizeof(arr)/sizeof(arr[0]);i++){
		while(str[i].size()<maxlen){
			str[i]="0"+str[i];
		}
	}
	string result="";
	while(result.size()<maxlen){
		result+="0";
	}
	for(int i=0;i<sizeof(arr)/sizeof(arr[0]);i++){
		for(int j=0;j<maxlen;j++){
			result[j]=char(((str[i][j]-'0')+(result[j]-'0'))%k+'0');
		}
	} 
	cout<<"出现1次的数为"<<ktodec(result,k)<<endl;
	return 0; 
}

你可能感兴趣的:(算法很美C++实现)