在JavaScript中创建忽略索引的数组结构
数组中的索引(维护索引)使在JavaScript中创建忽略索引的数组结构,javascript,arrays,node.js,time-complexity,constant-time,Javascript,Arrays,Node.js,Time Complexity,Constant Time,数组中的索引(维护索引)使array.prototype.shift和array.prototype.unshiftO(N)而不是O(1) 但是,如果我们只想使用pop()/push()/shift()和unshift(),而从不使用索引进行查找,有没有办法实现一个忽略索引的JavaScript数组 我想不出一个办法。 我能想到的唯一方法是使用数组,并且只使用pop()/push()(因为它们是O(1))。。。但即使使用多个阵列,也不确定这是否可行 如果可能的话,希望在没有链接列表的情况下完成此
array.prototype.shift
和array.prototype.unshift
O(N)而不是O(1)
但是,如果我们只想使用pop()/push()/shift()和unshift(),而从不使用索引进行查找,有没有办法实现一个忽略索引的JavaScript数组
我想不出一个办法。
我能想到的唯一方法是使用数组,并且只使用pop()/push()(因为它们是O(1))。。。但即使使用多个阵列,也不确定这是否可行
如果可能的话,希望在没有链接列表的情况下完成此操作。我用一个双链表实现了一个解决方案,但不知道是否有可能不用链表来实现
最终目标:尝试创建一个FIFO队列,其中所有操作都在固定时间内进行,而不使用链表。如果存储的数据是基本数据(字符串、整数、浮点或基本数据的组合),则可以使用JavaScript,将其转换为适当的类型化数组视图,加载数据,然后自己跟踪偏移量 在您的示例中,
pop
、shift
和unshift
都可以通过递增/递减整数索引来实现<代码>推送更难,因为TypedArray的大小是固定的:如果ArrayBuffer已满,则只有两个选项是截断数据或分配新的类型数组,因为JS无法存储指针
如果要存储同质对象(它们具有相同的属性),可以使用不同的视图和偏移量将每个值保存到TypedArray中,以模拟C结构(参见MDN示例),然后使用JS函数从TypedArray序列化/取消序列化,基本上是从二进制表示转换数据,变成一个成熟的JS对象。用整数索引的ES2015怎么样
让我们调用mapmyFIFOMap
在FIFO类中保留一个第一个
和最后一个
整数成员。从零开始
每次您想push()
进入FIFO队列时,都要调用myFIFOMap.set(++last,item)
。而pop()
看起来像:
const item = myFIFOMap.get(first);
myFIFOMap.delete(first++);
return item;
应该是O(1)
来推动或弹出
不要忘记检查边界条件(例如,当first==last
时,不要让它们pop()
)
鉴于JavaScript实际上使用双精度浮点,您应该能够在整数精度出现问题之前运行FIFO。因此,如果您每秒通过FIFO运行10000个项目,这对于大约28000年的运行时间应该是有益的 根据@SomeCallMeTim的答案,我认为这是正确的,我有以下几点:
export class Queue {
lookup = new Map<number, any>();
first = 0;
last = 0;
length = 0;
elementExists = false; // when first === last, and item exists there
peek() {
return this.lookup.get(this.first);
}
getByIndex(v: number) {
return this.lookup.get(v);
}
getLength() {
return this.length;
}
pop() {
const last = this.last;
if (this.elementExists && this.first === this.last) {
this.length--;
this.elementExists = false;
}
else if (this.last > this.first) {
this.length--;
this.last--;
}
const v = this.lookup.get(last);
this.lookup.delete(last);
return v;
}
shift() {
const first = this.first;
if (this.elementExists && this.first === this.last) {
this.length--;
this.elementExists = false;
}
else if (this.first < this.last) {
this.length--;
this.first++;
}
const v = this.lookup.get(first);
this.lookup.delete(first);
return v;
}
push(v: any) {
this.length++;
if (this.elementExists && this.first === this.last) {
this.last++;
}
else if (this.first === this.last) {
this.elementExists = true;
}
else {
this.last++;
}
return this.lookup.set(this.last, v);
}
enq(v: any) {
return this.push.apply(this, arguments);
}
enqueue(v: any) {
return this.push.apply(this, arguments);
}
deq() {
return this.shift.apply(this, arguments);
}
dequeue() {
return this.shift.apply(this, arguments);
}
unshift(v: any) {
this.length++;
if (this.elementExists && this.first === this.last) {
this.first--;
}
else if (this.first === this.last) {
this.elementExists = true;
}
else {
this.first--;
}
return this.lookup.set(this.first, v);
}
addToFront(v: any){
return this.unshift.apply(this,arguments);
}
removeAll() {
return this.clear.apply(this, arguments);
}
clear(): void {
this.length = 0;
this.elementExists = false;
this.first = 0;
this.last = 0;
this.lookup.clear();
}
}
要获得队列中的第五个元素,我们需要做的就是:
getByIndex(4);
只需使用对象或映射并围绕它们构建那些方法?您可以构建一个链表,它将支持您在O(1)中提到的所有操作,仅使用对象/映射-不可能检索O(1)中的第一个/最后一个插入项。为了检索O(1)中的第一个/最后一个项目,您必须使用带有对象/映射的链表。@FelixKling但如果删除最后插入的项目会怎么样?您必须找到最后一项才能将其保存为最后一个键?听起来您需要构建另一个数据结构来支持这一点,但还不清楚您试图解决的是什么更高级别的问题。这是行不通的,因为(a)需要通用性,而不仅仅是存储原语,(b)不能固定大小,因为最有可能的用例是FIFO队列。是的,但如何取消移位/移位?我想你可以通过增加/减少两个字段来跟踪第一个和最后一个字段。我想知道负数/整数是否和keys@AlexanderMills:当然可以。键可以是任意值。@AlexanderMills是的,数字在地图中可以变成负数。因此,分别使用适当的减量/增量
first
,shift()/unshift()是有效的出于好奇,你为什么认为这比链表好?我不认为在Map
中访问元素比从链表尾部获取元素快。根据Map
访问时间平均小于O(n)而不是链接数据的O(1)List@FelixKling是的,我没有想过使用递增/递减整数,但这使我们有可能参考以前的研究成果items@Minderov在这种情况下,唯一能确定的方法是尝试两种不同的解决方案,然后看看哪一种更快。@AlexanderMills我同意。如果您要测试它,请在测试后返回结果。非常好奇!
getByIndex(4);