你如何在 JavaScript 中实现堆栈和队列?

IT技术 javascript data-structures stack queue
2021-01-26 00:22:52

在 JavaScript 中实现堆栈和队列的最佳方法是什么?

我正在寻找调车场算法,我将需要这些数据结构。

6个回答
var stack = [];
stack.push(2);       // stack is now [2]
stack.push(5);       // stack is now [2, 5]
var i = stack.pop(); // stack is now [2]
alert(i);            // displays 5

var queue = [];
queue.push(2);         // queue is now [2]
queue.push(5);         // queue is now [2, 5]
var i = queue.shift(); // queue is now [5]
alert(i);              // displays 2

摘自“你可能不知道的 9 个 JavaScript 技巧

我复活了博文此答案中链接,因为 archive.org 并不总是性能最高的。我更新了链接和图像,以便它们工作,但我没有更改任何其他内容。
2021-03-26 00:22:52
我会说这取决于 javascript 实现。我不认为它是在 javascript 规范中定义的。
2021-03-27 00:22:52
我建议谨慎使用 queue.shift。IIRC 它不是 O(1),而是 O(n),如果队列变大可能会太慢。
2021-03-28 00:22:52
有关提高队列性能的简单实现,请参阅code.stephenmorley.org/javascript/queues
2021-03-28 00:22:52
对于队列性能问题,请参阅对三种不同类型的堆栈行为的很好的比较 jsperf.com/queue-push-unshift-vs-shift-pop——现在,如果有人足够好,包含该 jsperf 的 rev包含@Gili 提到的 JS 脚本...
2021-04-12 00:22:52

Javascript 有 push 和 pop 方法,它们对普通的 Javascript 数组对象进行操作。

对于队列,请看这里:

http://safalra.com/web-design/javascript/queues/

队列可以在 JavaScript 中使用数组对象的 push 和 shift 方法或 unshift 和 pop 方法实现。虽然这是实现队列的简单方法,但对于大队列来说效率非常低——因为这些方法对数组进行操作,每次调用时,shift 和 unshift 方法都会移动数组中的每个元素。

Queue.js 是一个简单而高效的 JavaScript 队列实现,它的出队函数在分摊常数时间内运行。因此,对于较大的队列,它可以比使用数组快得多。

看起来 queue.js 中的出队也需要额外的内存,因为它正在使用切片克隆数组。
2021-03-22 00:22:52
您分享的链接具有检查基准测试结果的功能,在使用 Google Chrome 59 版测试时,我没有看到性能提升。Queue.js 与它的速度不一致,但 Chrome 与它的速度非常一致。
2021-03-23 00:22:52
另外我用 queue.js 做了一个演示,dequeue 函数并没有真正从队列中删除项目,所以我想知道它是如何工作的?如果是这样,您如何在前一项出列后检索新队列?codepen.io/adamchenwei/pen/VxgNrX?editors=0001
2021-04-05 00:22:52
此外,随着每个添加的元素,底层数组变得越来越大。尽管实现会不时减小数组大小,但总体大小会增加。
2021-04-11 00:22:52

数组。

堆:

var stack = [];

//put value on top of stack
stack.push(1);

//remove value from top of stack
var value = stack.pop();

队列:

var queue = [];

//put value on end of queue
queue.push(1);

//Take first value from queue
var value = queue.shift();
@MichaelGeller 堆栈的行为是“先进后出”。如果您使用JavaScript中的数组,其实现它pushpop方法,那么问题就迎刃而解了。我真的不明白你的意思。
2021-03-15 00:22:52
@MichaelGeller 栈顶是数组最后一个元素。数组 push 和 pop 方法的行为就像一个堆栈。
2021-03-16 00:22:52
Array.prototype.pop 不会从数组的顶部(第一个元素)中删除值。它从数组的底部(最后一个元素)中删除值。
2021-03-24 00:22:52
@MichaelGeller 堆栈是概念性的。JS 数组是(除其他外)通过实现堆栈语义定义的堆栈。仅仅因为它也实现了数组语义并不会改变这一点。您可以像开箱即用的堆栈一样使用 JS 数组,在这种情况下,您推送和弹出的是“顶部”元素。
2021-03-26 00:22:52
@mrdommyg Array.prototype.pop 删除数组最后一个元素(参见developer.mozilla.org/en/docs/Web/JavaScript/Reference/...)。最后在此上下文中表示具有最高索引的元素。JS 中的数组与堆栈无关。它不是一个栈,因为它有一个 pop 方法。Pop 只是意味着“删除最后一个元素并返回它”。当然,您可以使用数组来模拟堆栈的功能,但根据定义,数组仍然不是堆栈。它仍然是一个列表(根据 MDN 是一个“类似列表”的对象)。
2021-04-03 00:22:52

如果您想制作自己的数据结构,可以构建自己的:

var Stack = function(){
  this.top = null;
  this.size = 0;
};

var Node = function(data){
  this.data = data;
  this.previous = null;
};

Stack.prototype.push = function(data) {
  var node = new Node(data);

  node.previous = this.top;
  this.top = node;
  this.size += 1;
  return this.top;
};

Stack.prototype.pop = function() {
  temp = this.top;
  this.top = this.top.previous;
  this.size -= 1;
  return temp;
};

对于队列:

var Queue = function() {
  this.first = null;
  this.size = 0;
};

var Node = function(data) {
  this.data = data;
  this.next = null;
};

Queue.prototype.enqueue = function(data) {
  var node = new Node(data);

  if (!this.first){
    this.first = node;
  } else {
    n = this.first;
    while (n.next) {
      n = n.next;
    }
    n.next = node;
  }

  this.size += 1;
  return node;
};

Queue.prototype.dequeue = function() {
  temp = this.first;
  this.first = this.first.next;
  this.size -= 1;
  return temp;
};
@cneuro 与 C++ 不同,JavaScript 是一种垃圾收集语言。它有一个delete关键字,但这仅用于将对象的属性标记为不存在——这与仅分配undefined给属性不同JavaScript 也有一个new运算符,但它只是用来this在调用函数时设置一个新的空对象。在 C++ 中,您需要将 eachnew与 a配对delete,但在 JavaScript 中不需要,因为 GC。要停止在 JavaScript 中使用内存,只需停止引用该对象,它最终将被回收。
2021-03-17 00:22:52
是否还需要通过设置最大堆栈大小来检查堆栈是否溢出?
2021-03-26 00:22:52
永远不要实现任何像这样的队列,除非你有一个很好的理由......虽然它在逻辑上看起来是正确的,但 CPU 并不根据人类的抽象运行。遍历一个到处都有指针的数据结构将导致 CPU 中的缓存未命中,这与高效的顺序数组不同。blog.davidecoppola.com/2014/05/... CPU非常讨厌指针 - 它们可能是缓存未命中和不得不从 RAM 访问内存的第一大原因。
2021-03-31 00:22:52
为了避免需要遍历整个事物以追加到末尾,请通过 this.last=node 存储对最后一个的引用;
2021-04-02 00:22:52
这是一个诱人的解决方案,但我没有看到 created Nodes 在弹出/出队时被删除......他们不会只是坐在那里占用内存直到浏览器崩溃吗?
2021-04-04 00:22:52

这是我使用链表实现的堆栈和队列:

// Linked List
function Node(data) {
  this.data = data;
  this.next = null;
}

// Stack implemented using LinkedList
function Stack() {
  this.top = null;
}

Stack.prototype.push = function(data) {
  var newNode = new Node(data);

  newNode.next = this.top; //Special attention
  this.top = newNode;
}

Stack.prototype.pop = function() {
  if (this.top !== null) {
    var topItem = this.top.data;
    this.top = this.top.next;
    return topItem;
  }
  return null;
}

Stack.prototype.print = function() {
  var curr = this.top;
  while (curr) {
    console.log(curr.data);
    curr = curr.next;
  }
}

// var stack = new Stack();
// stack.push(3);
// stack.push(5);
// stack.push(7);
// stack.print();

// Queue implemented using LinkedList
function Queue() {
  this.head = null;
  this.tail = null;
}

Queue.prototype.enqueue = function(data) {
  var newNode = new Node(data);

  if (this.head === null) {
    this.head = newNode;
    this.tail = newNode;
  } else {
    this.tail.next = newNode;
    this.tail = newNode;
  }
}

Queue.prototype.dequeue = function() {
  var newNode;
  if (this.head !== null) {
    newNode = this.head.data;
    this.head = this.head.next;
  }
  return newNode;
}

Queue.prototype.print = function() {
  var curr = this.head;
  while (curr) {
    console.log(curr.data);
    curr = curr.next;
  }
}

var queue = new Queue();
queue.enqueue(3);
queue.enqueue(5);
queue.enqueue(7);
queue.print();
queue.dequeue();
queue.dequeue();
queue.print();