进制转换系列

前言

进制转换的问题,在算法与数据结构中是一个比较基础的问题,大多数公司都不会对其进行考察,但是如果考察就是十分致命性的题目,因为大多数人对这块基本的逻辑是不明白的,甚至对于在相应的语言中如何表示不同的进制数都不清楚。
二进制可以使用的数字:0,1
八进制可以使用的数字:0,1,2,3,4,5,6,7
十进制可以使用的数字:0,1,2,3,4,5,6,7,8,9
十六进制可以使用的数字:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
java中能够用的数值数据类型:java为了有效的实现跨平台性,在java中只提供了byte、short、int、long、float、double等数值类型,不同于c、c++中提供了无符号数值类型,unsigned byte,unsigned int,java中没有,所以在一些进制转换中不太好做。
java取模运算中,余数的符号和被除数符号相同(除号前面的数),即与第一个数的符号相同

不同进制数在Java中的表示

不仅仅是Java中,大多数语言中都这样声明不同的进制数
二进制前缀:0b
八进制前缀:0
十六进制前最:0x

//都表示二进制10
int a=0b1010;
int a=012;
int a=0xA;

java中不同进制间的输出

String b=Integer.toBinaryString(a);
String c=Integer.toOctalString(a);
String d=Integer.toHexString(a);

不同进制数间的转换

题目1:负二进制转换

负二进制转换

class Solution {
    public String baseNeg2(int n) {
        //普通的10进制数转其他进制数的做法
        int k=-2;
        StringBuilder sb=new StringBuilder();
        if(n==0)
        {
            return "0";
        }
        while(n!=0)
        {
            int d=n%(k);
            if(d<0)
            {
                d=(d+Math.abs(k))%Math.abs(k);
            }
            sb.append(d);
            n=(n-d)/k;
        }
        return sb.reverse().toString();
    }
}

主要需要解决的问题是余数为负数的情况,当多次迭代做商之后,被除数为负,所以出现余数为负的情况,这时候需要求其正的同余数{d+Math.abs(k))%Math.abs(k)}。
这道题还有一个难点我们一般做正数迭代求余操作的时候,直接n=n/k即可,因为除法是向下保留的{例如,9/2=4,而不是等于5}所以不会出现“缺失”的问题,但是对于负数而言,{9/(-2)=-4,-1/-2=0}是向上取,所以需要我们减去同余数,使其向下取。

这道题可以提炼出任何正数转化为K进制(K可以为任意正数或负数)的代码。

String s="0123456789abcdef"
StringBuilder res=new StringBuilder;
char []alphabet=s.tocharArray();
while(n!=0)
{
	b=n%k;
	if(b<0)
	{
		b=(b+Math.abs(b))%Math.abs(b);
	}
	res.append(alphabet[b]);
	n=(n-b)/k;
}

对于一般的做法讲完之后,对于这道题,由于是-2,所以还可以用另外的情况去做,这直接避免了不必要的麻烦讨论

    public String baseNeg2(int N) {
        StringBuilder res = new StringBuilder();
        while (N != 0) {
            res.append(N & 1);
            N = -(N >> 1);
        }
        return res.length() > 0 ? res.reverse().toString() : "0";
    }

上面这道题目可以变化的更难一点,因为这个题目中,并没有考虑N<0的情况

题目2:数字转换为十六进制数

转16进制

这道题其实是最基本的题目,没有任何复杂度,唯一需要考虑的就是负数时的额外处理。而这个处理会引出很多讨论,纵使其一句代码可以解决。
首先贴上解决代码

public String toHex(int num)
{
	if(num==0)
	{
		return "0";
	}
	long lnum=num;
	if(num<0)
	{
		lnum=Math.pow(2,32)+num;
	}
	while(lnum!=0)
	{
		long b=lnum%16;
		char c=(char)(b+'0');
		if(b>10)
		{
			c=(char)(b-10+'a');
		}
		res.append(c);
		lnum=lnum/16;
	}
	return res.reverse().toString();
}

引出的讨论如下:
计算机在存储负数的时候本身用的就是补码,负数在其内部的存储我们就是我们最终想要的结果,奈何这些语言的发明者替我们考虑了太多。
32位有符号整型的范围的分析,32个bit,第一个bit是用来表示符号位的,那么最大的正数为:0111-1111-1111-1111-1111-1111-1111-11112147483647最小的数是多少呢?如果没有什么补码,原码、反码之说,那么我们可以想到的最小的数1111-1111-1111-1111-1111-1111-1111-1111,-2147483647其实不对!!!
对于+0的原码为0000-0000-0000-0000-0000-0000-0000-0000
-0的原码为1000-0000-0000-0000-0000-0000-0000-0000
因为0只需要一个,所以把-0拿来当做一个最小的数-2147483648
-2147483648的补码表示为1000-0000-0000-0000-0000-0000-0000 -0000,在32位没有原码。
注意,这个补码并不是真正的补码,真正的补码是1 1000 0000 0000 0000 0000 0000 0000 0000,溢出。
先枚举几个负数的补码值: -1对应0xFFFFFFFF,(看作0xFFFFFFFF+1-1);-2对应0xFFFFFFFE,(看作0xFFFFFFFF+1-2)。我们可以发现,对于一个给定的负数,只需要将其加上0xFFFFFFFF+1,再减去该负数的绝对值即可得到该负数对应的补码值。

引出题目1:给定一个整数,求出这个整数的原码表示。

引出题目2:给定一个整数,求出这个整数的反码表示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值