var ShortURL = new function() {
var _alphabet = '23456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ-_',
_base = _alphabet.length;
this.encode = function(num) {
var str = '';
while (num > 0) {
str = _alphabet.charAt(num % _base) + str;
num = Math.floor(num / _base);
}
return str;
};
this.decode = function(str) {
var num = 0;
for (var i = 0; i < str.length; i++) {
num = num * _base + _alphabet.indexOf(str.charAt(i));
}
return num;
};
};
我理解编码通过从十进制转换为自定义基础(在这种情况下为自定义字母/数字)
我不太确定解码是如何工作的。 为什么我们将base乘以当前数字然后添加字母表的位置编号?我知道要将010 base 2转换为十进制,我们会做
(2 * 0 ^ 2)+(2 * 1 ^ 1)+(2 * 0 ^ 0)= 2
不确定它在解码算法中的表示方式
编辑: 我自己的解码版
this.decode2 = function (str) {
var result = 0;
var position = str.length - 1;
var value;
for (var i = 0; i < str.length; i++) {
value = _alphabet.indexOf(str[i]);
result += value * Math.pow(_base, position--);
}
return result;
}
这就是我编写自己的解码版本的方式(就像我想在纸上转换它一样。我希望有人详细解释第一个版本的解码是如何工作的。还是不知道为什么我们将数字乘以num * base并以0开始num。
答案 0 :(得分:3)
好的,那么376
对encode()
函数的基数为10的输出意味着什么?这意味着:
1 * 100
+ 5 * 10
+ 4 * 1
为什么呢?因为在encode()
中,您在每次迭代时按划分。这意味着,隐含地,在早期迭代中推送到字符串上的字符每次通过循环时都会通过基数因子获得显着性。
decode()
函数因此每次看到新字符时乘以。这样,对于每个数字位置超过它所代表的第一个数字,第一个数字乘以基数一次,依此类推其余数字。
请注意,在上面的说明中,1
,5
和4
来自字符3
的位置,{ {1}}和7
在&#34;字母表中&#34;名单。这就是您的编码/解码机制的工作原理。如果你为6
函数提供一个数字字符串,该数字字符串由试图产生正常的10号数字的东西编码,那么你当然会得到一个奇怪的结果;这可能是显而易见的。
编辑进一步详细说明decode()
函数:忘记(现在)关于特殊基数和编码字母表。无论涉及的基础如何,该过程基本相同。所以,让我们看一个函数,它将一个基数为10的数字字符串解释为数字:
decode()
累加器变量function decode10(str) {
var num = 0, zero = '0'.charCodeAt(0);
for (var i = 0; i < str.length; ++i) {
num = (num * 10) + (str[i] - zero);
}
return num;
}
首先被初始化为0,因为在检查输入数字字符串的任何字符之前,唯一有意义的值是0。
然后,该函数从左到右迭代输入字符串的每个字符。在每次迭代中,累加器乘以基数,并添加当前字符串位置的数字值。
如果输入字符串是&#34; 214&#34;,则迭代将按如下方式进行:
num
设置为0 num
为str[i]
,因此2
为(num * 10) + 2
2
为str[i]
,因此1
为(num * 10) + 1
21
为str[i]
,因此4
为(num * 10) + 4
连续乘以10可以实现对214
的调用在代码中的作用。请注意,Math.pow()
乘以10 两次,实际上将其乘以100。
原始代码中的2
例程执行相同的操作,而不是通过简单的字符代码计算来获取数字的数值,它在字母表字符串中执行查找。
答案 1 :(得分:1)
decode
函数的原始版本和您自己的版本都实现了相同的功能,但原始版本的效率更高。
在以下作业中:
num = num * _base + _alphabet.indexOf(str.charAt(i));
......有两个部分:
_alphabet.indexOf(str.charAt(i))
indexOf
返回基础_base
中数字的值。你在自己的算法中有这个部分,所以应该清楚。
num * _base
这使得迄今为止累积的结果倍增。我的其余部分是关于那部分的:
在第一次迭代中,这没有任何效果,因为此时num
仍为0。但是在第一次迭代结束时,num
包含的值就像str
只有最左边的字符一样。它是最左边数字的基数为51的数字。
从下一次迭代开始,结果乘以基数,这为下一个值添加空间。它的功能就像一个数字移位。
将此示例输入设为decode
:
bd35
单个字符代表值8,10,1和3.由于字母表中有51个字符,我们位于基数51.所以bd35
代表值:
8*51³ + 10*51² + 1*51 + 3
以下是每次迭代后值为num
的表格:
8
8*51 + 10
8*51² + 10*51 + 1
8*51³ + 10*51² + 1*51 + 3
为了使可视化更清晰,让我们将51的强大功能放在列标题中,然后从行中删除它:
3 2 1 0
----------------------------
8
8 10
8 10 1
8 10 1 3
注意8在每次迭代时8向左移动并与基数相乘(51)。同样的情况发生在10,一旦从向右移动,与1和3相同,尽管这是最后一个并且不再移动。
乘法num * _base
因此表示基数向左移位,为新数字腾出空间(通过简单加法)。
在最后一次迭代中,所有数字都在正确的位置移动,即它们已经被基数乘以足够的次数。
将您自己的算法放在同一个方案中,您将拥有此表:
3 2 1 0
----------------------------
8
8 10
8 10 1
8 10 1 3
这里没有移位:数字立即放在正确的位置,即它们立即乘以51的正确功率。
答案 2 :(得分:1)
你问
我想了解解码功能如何从逻辑角度运作。为什么我们使用num * base并以num = 0开头。
并写下
我不太确定解码是如何工作的。为什么我们将基数乘以a 当前的数字,然后添加字母的位置号?一世 知道要将010 base 2转换为十进制,我们会做
(2 * 0 ^ 2)+(2 * 1 ^ 1)+(2 * 0 ^ 0)= 2
解码函数使用一种称为Horner规则的基本转换方法,因为它具有计算效率:
num = 0
num
乘以基数num
,num
现在包含转换后的值(在基数10中)使用十六进制数A5D
的示例:
num = 0
num
现在仍为0 A
的数字值为10
)并将其添加到num
,num
现在为10 num
乘以基数(16),num
现在为160 5
添加到num
,num
现在为165 num
乘以基数(16),num
现在为2640 D
添加到num
(添加13)num
现在包含转换后的值(在基数10中),即2653 比较标准方法的表达方式:
(10×16 2 )+(5×16 1 )+(13×16 0 )= 2653
使用霍纳的规则:
<(>((10×16)+ 5)×16)+ 13 = 2653
这是完全相同的计算,但重新排列为一种形式,使其更容易计算。这就是decode
函数的工作原理。
为什么我们使用num * base并以num = 0开头。
转换算法需要一个起始值,因此num
设置为0.对于每次重复(每次循环迭代),num
乘以base
。这只对第二次迭代产生任何影响,但是这样写的是为了更容易将转换编写为for
循环。