程序员面试金典——解题总结: 9.18高难度题 18.1编写一个函数,将两个数字相加。不得使用+或其他算术运算符。

时间:2021-10-14 17:25:19
#include <iostream>
#include <stdio.h>

using namespace std;
/*
问题:编写一个函数,将两个数字相加。不得使用+或其他算术运算符。
分析:既然不能使用+,应该就是位运算了。
      可以将两个数字每次向右移动,每次将移动后的最低位进行与操作,若与操作结果为1,说明这两个数最后的都为1就进位,直到两个数都变成0
	  假设: 3 + 10
	  3对应:	00011
	  10对应:	01010
	  初始化一个结果result为0:每次将两个数最低位计算后的结果存放在result的第0位,第1位,..,
	  即可。
	  那么问题的关键变成:如何求两个数最低位,求某个数的第i位,可以采用将该数与(1<<i)进行与运算
	  设两个数分别为a,b
	  
	  int pass = 0;
	  while( a && b)
	  {
		int aBit = a & 1;
		int bBit = b & 1;
		//需要进位
		if( ( 1 == aBit && 1 == bBit) || ( 1 == aBit))
		{
			pass = 1;
		}
		resultBit = ;
		result |= resultBit;
	  }

书上解法:比如759 + 674,加法的:相加和进位拆分开:
           1】759和674相加,不进位,得到323
		   2】759和674相加,只进位,得到1110
		   将1110 + 323 = 1433
		   上述只加不进位,就是异或操作
		       只进位不加,只要a和b的i-1位皆为1,总和的第i位为1,就是AND加上位移操作

输入:
3 5
3 -5
-3 -5
0 5
输出:
8
-2
-8
5

关键:
1
书上解法:比如759 + 674,加法的:相加和进位拆分开:
           1】759和674相加,不进位,得到323
		   2】759和674相加,只进位,得到1110
		   将1110 + 323 = 1433
		   上述只加不进位,就是异或操作
		       只进位不加,只要a和b的i-1位皆为1,总和的第i位为1,就是AND加上位移操作
//递归得加法
int addRecursive(int a ,int b)
{
	//注意递归的出口是: b为0,会导致sum为a , pass为0; 如果a为0,那么sum=0,pass为0
	if(0 == a)
	{
		return b;
	}
	if(0 == b)
	{
		return a;
	}
	//累加,但不进位,通过异或实现
	int sum = a ^ b;
	//只进位,通过与操作,然后左移一位实现
	int pass = (a & b) << 1;
	return addRecursive(sum , pass);
}

2 注意,由于负数即使右移,填充的也是1,导致while(num1 && num2)陷入死循环,最好的办法就是采用(1<<i)次方取与 或者 次数超过32次就终止
int add(int num1 , int num2)
{
	int pass = 0;
	int result = 0;
	pair<int, int> resultPair;
	int resultBit;
	int count = 0;
	//注意,由于负数即使右移,填充的也是1,导致while(num1 && num2)陷入死循环,最好的办法就是采用(1<<i)次方取与 或者 次数超过32次就终止
	//while(num1 || num2)
	while(true)
	{
		//说明其中有一个是负数,直接退出循环
		if(count >= 32)
		{
			break;
		}
		int bit1 = num1 & (1 );
		int bit2 = num2 & (1 );
		resultPair = getPassAndBit(bit1 , bit2 , pass );
		resultBit = resultPair.first;
		pass = resultPair.second;
		result |= (resultBit << count);
		num1 >>= 1;//右移一位
		num2 >>= 1;
		count++;
	}
	return result;
}
*/

//计算当前位和进位,pair第一个元素为当前位,第二个元素为进位
pair<int , int> getPassAndBit(int bit1 , int bit2 , int pass )
{
	//如果全为0,进位为0,当前位为0
	if( 0 == bit1 && 0 == bit2 && 0 == pass )
	{
		pair<int, int> result(0, 0);
		return result;
	}
	//如果全为1,进位为1,当前位为1
	else if( 1 == bit1 && 1 == bit2 && 1 == pass)
	{
		pair<int, int> result(1, 1);
		return result;
	}
	//排除全1和全0的情况后:只剩两种可能:三者异或结果为0或1
	else
	{
		//bit1,bit2,pass中有两个1,1个0,三者异或结果为0,此时当前位为0,进位为1
		if( (bit1^bit2^pass) == 0)
		{
			pair<int, int> result(0, 1);
			return result;
		}
		//bit1,bit2,pass中有两个0,1个1,三者异或结果为1,此时当前位为1,进位为0
		else
		{
			pair<int, int> result(1, 0);
			return result;
		}
	}
}

int add(int num1 , int num2)
{
	int pass = 0;
	int result = 0;
	pair<int, int> resultPair;
	int resultBit;
	int count = 0;
	//注意,由于负数即使右移,填充的也是1,导致while(num1 && num2)陷入死循环,最好的办法就是采用(1<<i)次方取与 或者 次数超过32次就终止
	//while(num1 || num2)
	while(true)
	{
		//说明其中有一个是负数,直接退出循环
		if(count >= 32)
		{
			break;
		}
		int bit1 = num1 & (1 );
		int bit2 = num2 & (1 );
		resultPair = getPassAndBit(bit1 , bit2 , pass );
		resultBit = resultPair.first;
		pass = resultPair.second;
		result |= (resultBit << count);
		num1 >>= 1;//右移一位
		num2 >>= 1;
		count++;
	}
	return result;
}

//递归得加法
int addRecursive(int a ,int b)
{
	//注意递归的出口是: b为0,会导致sum为a , pass为0; 如果a为0,那么sum=0,pass为0
	if(0 == a)
	{
		return b;
	}
	if(0 == b)
	{
		return a;
	}
	//累加,但不进位,通过异或实现
	int sum = a ^ b;
	//只进位,通过与操作,然后左移一位实现
	int pass = (a & b) << 1;
	return addRecursive(sum , pass);
}

void process()
{
	int num1;
	int num2;
	while(cin >> num1 >> num2)
	{
		//int result = add(num1 , num2);
		int result = addRecursive(num1 , num2);
		cout << result << endl;
	}
}

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