不幸的是,JavaScript 的内置数据类型 - 尤其是 Map - 对完成这项任务没有太大帮助,因为它们缺乏相关的方法。
在大多数情况下,大多数条目将分为几个连续的
具有相同值的范围。
然而,我们可以利用这一点并在排序数组上使用二进制搜索策略,假设转换表不会经常修改。
通过将每个输入范围的最小值存储在排序数组中,对导致相同状态的连续输入范围进行编码。将相应索引处的状态保存在单独的数组中:
let inputs = [0, 5, 10]; // Input ranges [0,4], [5,9], [10,∞)
let states = [0, 1, 0 ]; // Inputs [0,4] lead to state 0, [5,9] to 1, [10,∞) to 0
现在,给定一个输入,您需要对输入数组执行二进制搜索,类似于Java's floorEntry(k):
// Returns the index of the greatest element less than or equal to
// the given element, or undefined if there is no such element:
function floorIndex(sorted, element) {
let low = 0;
let high = sorted.length - 1;
while (low <= high) {
let mid = low + high >> 1;
if (sorted[mid] > element) {
high = mid - 1;
} else if (sorted[mid] < element) {
low = mid + 1;
} else {
return mid
}
}
return low - 1;
}
// Example: Transition to 1 for emoticons in range 1F600 - 1F64F:
let transitions = {
inputs: [0x00000, 0x1F600, 0x1F650],
states: [0, 1, 0 ]
};
let input = 0x1F60B; // ?
let next = transitions.states[floorIndex(transitions.inputs, input)];
console.log(`transition to ${next}`);
此搜索以 O(log n) 步完成,其中 n 是连续输入范围的数量。单个状态的转换表则需要 O(n) 的空间。只要我们最初的假设(导致相同状态的连续输入范围的数量很小)成立,这种方法同样适用于稀疏和密集转换表。