程序员面试金典: 9.5位操作5.1两个整数的位合并

#include <iostream>
#include <stdio.h>
#include <stack>
#include <string>
#include <stdlib.h> //用于atoi函数
using namespace std;

/*
问题:给定两个32位的证书N与M,以及表示比特位置的i与j。编写一个方法,将M插入N,使得M从N的第j位开始,到第i位结束(j>i)。
      嘉定从j位得到i位足以容纳M,也即若M=10011,那么j和i之间至少可以容纳5个位。例如,不可能出现j=3和i=2的情况,因为第
	  3位和第2位之间放不下M。
	  示例输入:N= 100 0000 0000
	           M=      100 11
			   i= 2,j =6
		  输出:N= 100 0100 1100
分析:这个问题实际上就是寻找这样一个整数x,x与y进行位操作后,以y全部出现。
      等同于以下步骤:
	  1:先将N从第j位到第i位之间变成0,设置数M,问题转化为如何使得某一位变成0,从而将从第j位到第i位依次都变成0
	  2:将M整体向左移动i位得到新的M
	  3: 将N和新的M进行或运算

输入:
10000000000 (N) 10011(M) 2(i) 6(j)
输出:
10001001100

关键:
1
书上解法:
对一个数从第j位到第i位进行清零,涉及到两次掩码运算。
首先:将0取反,得到全1的数,将该全1的数向左移动j+`位,因为这里最低位是从0开始计算的,0到第j位全为0,实际上是j+1个位都为0,因此
      向左移动j+1位,记得到P
然后:需要将第i位以下的位全部变成1,可以用1向左移动i位,然后减去1,记得到Q
最后: P|Q 得到最终掩码R,将R和N进行与运算
想不到:将0取反右移j+1位即可使得第j位前面均为1

2 注意输入的N和M都是字符串,需要转化为二进制
*/

/*
对一个数从第j位到第i位进行清零,涉及到两次掩码运算。
首先:将0取反,得到全1的数,将该全1的数向左移动j+`位,因为这里最低位是从0开始计算的,0到第j位全为0,实际上是j+1个位都为0,因此
      向左移动j+1位,记得到P
然后:需要将第i位以下的位全部变成1,可以用1向左移动i位,然后减去1,记得到Q
最后: P|Q 得到最终掩码R,将R和N进行与运算
*/
int clearBit(int N , int i , int j)
{
	if(i > j)
	{
		return -1;
	}
	int allOnes = ~0;
	int P = allOnes << (j+1);
	int Q = (1 << i) - 1;
	int R = P | Q;
	int result = R & N;
	return result;
}

/*
	  1:先将N从第j位到第i位之间变成0
	  2:将M整体向左移动i位得到新的M
	  3: 将N和新的M进行或运算
*/
int replaceBit(int N , int M , int i , int j)
{
	if(i < 0 || j < 0 || i > j)
	{
		return -1;
	}
	int C = clearBit(N , i , j);
	M = M << i;
	int result = C | M;
	return result;
}

stack<int>  tenToTwo(int num)
{
	stack<int> stackResult;
	do{
		int j = num % 2;
		stackResult.push(j);
		num /= 2;
	}while(num);
	return stackResult;
}

void print(stack<int> stackResult)
{
	while(!stackResult.empty())
	{
		int value = stackResult.top();
		stackResult.pop();
		cout << value;
	}
	cout << endl;
}

//将字符串中表示的二进制整数转化为10进制整数,只能每次取一位,并乘以2^i,进行累加
int toInt(string& str)
{
	if(str.empty())
	{
		return -1;
	}

	//字符串应该从后向前获取
	int size =str.size() ;
	int num;
	int count = 0;
	int result = 0;
	for(int i = size -1 ; i >= 0 ; i--)
	{
		num = str[i] - '0';
		int value = (int) pow(2 , count);
		result += num * value;
		count++;
	}
	return result;
	//int value = atoi(str.c_str());//这里输入的是二进制整数需要转换,不能直接用字符串转换
	//return value;
}

void process()
{
	string strN , strM ;
	int N , M;
	int i ,j;
	while(cin >> strN >> strM >> i >> j)
	{
		N = toInt(strN);
		M = toInt(strM);
		int result = replaceBit(N , M , i , j);
		//得到结果后,需要转化成二进制数,十进制转二进制就是除二取余,然后逆序输出即可
		stack<int> stackResult = tenToTwo(result);
		print(stackResult);
	}
}

int main(int argc, char* argv[])
{
	process();
	getchar();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值