Làm thế nào để bạn triển khai một Stack và Queue trong JavaScript?


741

Cách tốt nhất để triển khai Stack và Queue trong JavaScript là gì?

Tôi đang tìm cách thực hiện thuật toán shunting-yard và tôi sẽ cần các cấu trúc dữ liệu này.

Câu trả lời:


1347
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

lấy từ " 9 mẹo javascript bạn có thể không biết "


218
Tôi sẽ khuyên bạn nên thận trọng trong việc sử dụng queue.shift. IIRC nó không phải là O (1), mà là O (n) và có thể quá chậm nếu hàng đợi trở nên lớn.
MAK

20
Tôi muốn nói điều này phụ thuộc vào việc triển khai javascript. Tôi không nghĩ nó được định nghĩa trong thông số javascript.
Georg Schölly

9
Xem code.stephenmorley.org/javascript/queues để biết cách triển khai đơn giản giúp cải thiện hiệu suất hàng đợi.
Gili

15
Đối với các vấn đề về hiệu suất Hàng đợi, hãy xem một so sánh đẹp về ba loại hành vi ngăn xếp khác nhau trên jsperf.com/queue-push-unshift-vs-shift-pop - Bây giờ nếu chỉ có ai đó đủ tốt để bao gồm một bản sửa đổi của jsperf đó sẽ chứa tập lệnh JS mà @Gili đã đề cập ...
Nenotlep

3
Tôi đã phục hồi bài viết trên blog được liên kết trong câu trả lời này vì archive.org không phải lúc nào cũng hiệu quả nhất. Tôi đã cập nhật các liên kết và hình ảnh để chúng hoạt động nhưng tôi không thay đổi gì khác.
Chev

87

Javascript có các phương thức đẩy và pop, hoạt động trên các đối tượng mảng Javascript thông thường.

Đối với hàng đợi, xem tại đây:

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

Hàng đợi có thể được triển khai trong JavaScript bằng cách sử dụng các phương thức đẩy và dịch chuyển hoặc các phương thức bật và tắt của đối tượng mảng. Mặc dù đây là một cách đơn giản để thực hiện hàng đợi, nhưng nó rất không hiệu quả đối với hàng đợi lớn - vì các phương thức hoạt động trên mảng, các phương thức shift và unshift di chuyển mọi phần tử trong mảng mỗi khi chúng được gọi.

Queue.js là một triển khai hàng đợi đơn giản và hiệu quả cho JavaScript có hàm dequeue chạy trong thời gian không đổi được khấu hao. Kết quả là, đối với hàng đợi lớn hơn, nó có thể nhanh hơn đáng kể so với sử dụng mảng.


2
Với liên kết mà bạn đã chia sẻ có chức năng kiểm tra kết quả điểm chuẩn & tôi không thấy hiệu suất tăng khi được thử nghiệm với Google Chrome phiên bản 59. Queue.js không phù hợp với tốc độ của nó nhưng Chrome hoàn toàn phù hợp với tốc độ của nó.
Shiljo Paulson

Ngoài ra, tôi đã tạo một bản demo với queue.js, rằng hàm dequeue không thực sự loại bỏ mục khỏi hàng đợi, vì vậy tôi tự hỏi liệu nó có giả sử nó hoạt động như thế nào không? Nếu vậy, làm thế nào bạn có thể lấy lại hàng đợi mới sau khi loại bỏ mục trước đó? codepen.io/adamchenwei/pen/VxgNrX?editors=0001
Ezeewei

có vẻ như dequeue trong queue.js cũng yêu cầu bộ nhớ bổ sung vì nó đang nhân bản mảng với lát cắt.
JaTo

Hơn nữa, mảng cơ bản ngày càng lớn hơn với mọi phần tử được thêm vào. Mặc dù việc triển khai giảm kích thước mảng theo thời gian, kích thước tổng thể vẫn tăng.
Philipp Mitterer

73

Mảng.

Cây rơm:

var stack = [];

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

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

Xếp hàng:

var queue = [];

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

//Take first value from queue
var value = queue.shift();

1
Array.prototype.pop không xóa giá trị khỏi đỉnh (phần tử đầu tiên) của Mảng. Nó loại bỏ giá trị từ dưới cùng (phần tử cuối cùng) của Mảng.
Michael Geller

21
@MichaelGeller Phần trên cùng của ngăn xếp là phần tử cuối cùng của Mảng. Các phương thức đẩy và pop hoạt động giống như một ngăn xếp.
mrd Momg

@mrdommyg Array.prototype.pop xóa phần tử cuối cùng của mảng (xem developer.mozilla.org/en/docs/Web/JavaScript/Reference/ .) Cuối cùng trong bối cảnh này có nghĩa là các yếu tố có chỉ số cao nhất. Một mảng trong JS không có gì để làm với một ngăn xếp. Nó không phải là một ngăn xếp chỉ vì nó có một phương thức pop. Pop chỉ có nghĩa là "loại bỏ yếu tố cuối cùng và trả lại". Tất nhiên bạn có thể bắt chước chức năng của ngăn xếp với một mảng, nhưng một mảng vẫn không phải là một ngăn xếp theo định nghĩa. Nó vẫn là một danh sách (một đối tượng "liệt kê như" theo MDN).
Michael Geller

5
@MichaelGeller Hành vi của ngăn xếp là "vào trước, ra sau". Nếu bạn triển khai nó bằng cách sử dụng một mảng trong JavaScript với các phương thức pushpopphương thức thì vấn đề đã được giải quyết. Tôi không thực sự thấy quan điểm của bạn ở đây.
Rax Weber

2
@MichaelGeller Một ngăn xếp là khái niệm. Một mảng JS là (trong số những thứ khác) theo định nghĩa một ngăn xếp nhờ vào việc thực hiện ngữ nghĩa của ngăn xếp. Chỉ vì nó cũng thực hiện ngữ nghĩa mảng không thay đổi điều đó. Bạn có thể sử dụng một mảng JS như một ngăn xếp ra khỏi hộp và trong bối cảnh đó, thứ bạn đẩy và bật là phần tử "trên cùng".
Hans

32

Nếu bạn muốn tạo cấu trúc dữ liệu của riêng mình, bạn có thể tự xây dựng:

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;
};

Và để xếp hàng:

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;
};

13
Để tránh phải lặp đi lặp lại toàn bộ để nối vào cuối, hãy lưu trữ một tham chiếu đến cái cuối cùng thông qua this.last = node;
Perkins

9
Không bao giờ thực hiện bất kỳ Hàng đợi nào như thế này trừ khi bạn có lý do thực sự tốt cho nó ... trong khi nó có vẻ đúng về mặt logic, CPU không hoạt động theo sự trừu tượng của con người. Lặp đi lặp lại một cơ sở hạ tầng có con trỏ ở khắp mọi nơi sẽ dẫn đến lỗi bộ nhớ cache trong CPU, không giống như một mảng tuần tự có hiệu quả cao. blog.davidecoppola.com/2014/05/ CPU CPU HATE con trỏ với niềm đam mê cháy bỏng - chúng có lẽ là nguyên nhân số 1 của việc bỏ lỡ bộ nhớ cache và phải truy cập bộ nhớ từ RAM.
Centril

1
Đây là một giải pháp hấp dẫn, nhưng tôi không thấy đã tạo ra Nodebị xóa khi bật / tắt ... họ sẽ không ngồi quanh bộ nhớ cho đến khi trình duyệt gặp sự cố?
cneuro

5
@cneuro Không giống như C ++, JavaScript là ngôn ngữ được thu thập rác. Nó có một deletetừ khóa, nhưng nó chỉ hữu ích khi đánh dấu một thuộc tính của một đối tượng là không hiện diện, điều này khác với việc chỉ gán undefinedcho thuộc tính . JavaScript cũng có một newtoán tử, nhưng nó chỉ được sử dụng để đặt thisthành một đối tượng trống mới khi gọi một hàm. Trong C ++, bạn cần ghép mọi thứ newvới a delete, nhưng không phải bằng JavaScript vì GC. Để ngừng sử dụng bộ nhớ trong JavaScript, chỉ cần dừng tham chiếu đối tượng và cuối cùng nó sẽ được lấy lại.
b Liệu

Có phải cũng cần kiểm tra ngăn xếp để tràn không bằng cách đặt kích thước ngăn xếp tối đa?
con ong

16

Tôi thực hiện StackQueuesử dụngLinked List

// 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();


10

Dịch chuyển mảng Javascript () chậm đặc biệt là khi giữ nhiều phần tử. Tôi biết hai cách để thực hiện hàng đợi với độ phức tạp O (1) được khấu hao.

Đầu tiên là bằng cách sử dụng bộ đệm tròn và nhân đôi bảng. Tôi đã thực hiện điều này trước đây. Bạn có thể xem mã nguồn của tôi ở đây https://github.com/kevyuu/rapid-queue

Cách thứ hai là sử dụng hai ngăn xếp. Đây là mã cho hàng đợi với hai ngăn xếp

function createDoubleStackQueue() {
var that = {};
var pushContainer = [];
var popContainer = [];

function moveElementToPopContainer() {
    while (pushContainer.length !==0 ) {
        var element = pushContainer.pop();
        popContainer.push(element);
    }
}

that.push = function(element) {
    pushContainer.push(element);
};

that.shift = function() {
    if (popContainer.length === 0) {
        moveElementToPopContainer();
    }
    if (popContainer.length === 0) {
        return null;
    } else {
        return popContainer.pop();
    }
};

that.front = function() {
    if (popContainer.length === 0) {
        moveElementToPopContainer();
    }
    if (popContainer.length === 0) {
        return null;
    }
    return popContainer[popContainer.length - 1];
};

that.length = function() {
    return pushContainer.length + popContainer.length;
};

that.isEmpty = function() {
    return (pushContainer.length + popContainer.length) === 0;
};

return that;}

Đây là so sánh hiệu suất bằng cách sử dụng jsPerf

Thông tưQueue.shift () so với Array.shift ()

http://jsperf.com/rapidqueue-shift-vs-array-shift

Như bạn có thể thấy nó nhanh hơn đáng kể với tập dữ liệu lớn


8

Có khá nhiều cách để bạn có thể triển khai Ngăn xếp và Hàng đợi trong Javascript. Hầu hết các câu trả lời ở trên là các triển khai khá nông và tôi sẽ cố gắng thực hiện một cái gì đó dễ đọc hơn (sử dụng các tính năng cú pháp mới của es6) và mạnh mẽ.

Đây là cách thực hiện ngăn xếp:

class Stack {
  constructor(...items){
    this._items = []

    if(items.length>0)
      items.forEach(item => this._items.push(item) )

  }

  push(...items){
    //push item to the stack
     items.forEach(item => this._items.push(item) )
     return this._items;

  }

  pop(count=0){
    //pull out the topmost item (last item) from stack
    if(count===0)
      return this._items.pop()
     else
       return this._items.splice( -count, count )
  }

  peek(){
    // see what's the last item in stack
    return this._items[this._items.length-1]
  }

  size(){
    //no. of items in stack
    return this._items.length
  }

  isEmpty(){
    // return whether the stack is empty or not
    return this._items.length==0
  }

  toArray(){
    return this._items;
  }
}

Và đây là cách bạn có thể sử dụng ngăn xếp:

let my_stack = new Stack(1,24,4);
// [1, 24, 4]
my_stack.push(23)
//[1, 24, 4, 23]
my_stack.push(1,2,342);
//[1, 24, 4, 23, 1, 2, 342]
my_stack.pop();
//[1, 24, 4, 23, 1, 2]
my_stack.pop(3)
//[1, 24, 4]
my_stack.isEmpty()
// false
my_stack.size();
//3

Nếu bạn muốn xem mô tả chi tiết về việc triển khai này và làm thế nào để cải thiện nó hơn nữa, bạn có thể đọc tại đây: http://jschap.com/data-strucenses-in-javascript-stack/

Đây là mã để thực hiện hàng đợi trong es6:

class Queue{
 constructor(...items){
   //initialize the items in queue
   this._items = []
   // enqueuing the items passed to the constructor
   this.enqueue(...items)
 }

  enqueue(...items){
    //push items into the queue
    items.forEach( item => this._items.push(item) )
    return this._items;
  }

  dequeue(count=1){
    //pull out the first item from the queue
    this._items.splice(0,count);
    return this._items;
  }

  peek(){
    //peek at the first item from the queue
    return this._items[0]
  }

  size(){
    //get the length of queue
    return this._items.length
  }

  isEmpty(){
    //find whether the queue is empty or no
    return this._items.length===0
  }
}

Đây là cách bạn có thể sử dụng triển khai này:

let my_queue = new Queue(1,24,4);
// [1, 24, 4]
my_queue.enqueue(23)
//[1, 24, 4, 23]
my_queue.enqueue(1,2,342);
//[1, 24, 4, 23, 1, 2, 342]
my_queue.dequeue();
//[24, 4, 23, 1, 2, 342]
my_queue.dequeue(3)
//[1, 2, 342]
my_queue.isEmpty()
// false
my_queue.size();
//3

Để xem hướng dẫn đầy đủ về cách các cấu trúc dữ liệu này đã được triển khai và làm thế nào để cải thiện chúng hơn nữa, bạn có thể muốn xem qua phần 'Chơi với cấu trúc dữ liệu trong chuỗi javascript' tại jsch.com. Đây là các liên kết cho hàng đợi - http://jschap.com/playing-data-strucenses-javascript-queues/


7

Bạn có thể sử dụng lớp tùy chỉnh của riêng bạn dựa trên khái niệm, ở đây đoạn mã mà bạn có thể sử dụng để thực hiện công cụ

/*
*   Stack implementation in JavaScript
*/



function Stack() {
  this.top = null;
  this.count = 0;

  this.getCount = function() {
    return this.count;
  }

  this.getTop = function() {
    return this.top;
  }

  this.push = function(data) {
    var node = {
      data: data,
      next: null
    }

    node.next = this.top;
    this.top = node;

    this.count++;
  }

  this.peek = function() {
    if (this.top === null) {
      return null;
    } else {
      return this.top.data;
    }
  }

  this.pop = function() {
    if (this.top === null) {
      return null;
    } else {
      var out = this.top;
      this.top = this.top.next;
      if (this.count > 0) {
        this.count--;
      }

      return out.data;
    }
  }

  this.displayAll = function() {
    if (this.top === null) {
      return null;
    } else {
      var arr = new Array();

      var current = this.top;
      //console.log(current);
      for (var i = 0; i < this.count; i++) {
        arr[i] = current.data;
        current = current.next;
      }

      return arr;
    }
  }
}

và để kiểm tra điều này, hãy sử dụng bảng điều khiển của bạn và thử từng dòng một.

>> var st = new Stack();

>> st.push("BP");

>> st.push("NK");

>> st.getTop();

>> st.getCount();

>> st.displayAll();

>> st.pop();

>> st.displayAll();

>> st.getTop();

>> st.peek();

2
Downvote cho một quy ước đặt tên: phương thức bắt đầu bằng một vốn được coi là một nhà xây dựng.
Pavlo

6
/*------------------------------------------------------------------ 
 Defining Stack Operations using Closures in Javascript, privacy and
 state of stack operations are maintained

 @author:Arijt Basu
 Log: Sun Dec 27, 2015, 3:25PM
 ------------------------------------------------------------------- 
 */
var stackControl = true;
var stack = (function(array) {
        array = [];
        //--Define the max size of the stack
        var MAX_SIZE = 5;

        function isEmpty() {
            if (array.length < 1) console.log("Stack is empty");
        };
        isEmpty();

        return {

            push: function(ele) {
                if (array.length < MAX_SIZE) {
                    array.push(ele)
                    return array;
                } else {
                    console.log("Stack Overflow")
                }
            },
            pop: function() {
                if (array.length > 1) {
                    array.pop();
                    return array;
                } else {
                    console.log("Stack Underflow");
                }
            }

        }
    })()
    // var list = 5;
    // console.log(stack(list))
if (stackControl) {
    console.log(stack.pop());
    console.log(stack.push(3));
    console.log(stack.push(2));
    console.log(stack.pop());
    console.log(stack.push(1));
    console.log(stack.pop());
    console.log(stack.push(38));
    console.log(stack.push(22));
    console.log(stack.pop());
    console.log(stack.pop());
    console.log(stack.push(6));
    console.log(stack.pop());
}
//End of STACK Logic

/* Defining Queue operations*/

var queue = (function(array) {
    array = [];
    var reversearray;
    //--Define the max size of the stack
    var MAX_SIZE = 5;

    function isEmpty() {
        if (array.length < 1) console.log("Queue is empty");
    };
    isEmpty();

    return {
        insert: function(ele) {
            if (array.length < MAX_SIZE) {
                array.push(ele)
                reversearray = array.reverse();
                return reversearray;
            } else {
                console.log("Queue Overflow")
            }
        },
        delete: function() {
            if (array.length > 1) {
                //reversearray = array.reverse();
                array.pop();
                return array;
            } else {
                console.log("Queue Underflow");
            }
        }
    }



})()

console.log(queue.insert(5))
console.log(queue.insert(3))
console.log(queue.delete(3))

5

Hoặc nếu không, bạn có thể sử dụng hai mảng để thực hiện cấu trúc dữ liệu hàng đợi.

var temp_stack = new Array();
var stack = new Array();

temp_stack.push(1);
temp_stack.push(2);
temp_stack.push(3);

Nếu tôi bật các phần tử bây giờ thì đầu ra sẽ là 3,2,1. Nhưng chúng tôi muốn cấu trúc FIFO để bạn có thể làm như sau.

stack.push(temp_stack.pop());
stack.push(temp_stack.pop());
stack.push(temp_stack.pop());

stack.pop(); //Pop out 1
stack.pop(); //Pop out 2
stack.pop(); //Pop out 3

1
Điều này chỉ hoạt động nếu bạn không bao giờ pushsau lần đầu tiênpop
jnnnnn

5

Đây là một cách thực hiện hàng đợi khá đơn giản với hai mục đích:

  • Không giống như mảng.shift (), bạn biết phương thức dequeue này mất thời gian không đổi (O (1)).
  • Để cải thiện tốc độ, cách tiếp cận này sử dụng phân bổ ít hơn nhiều so với cách tiếp cận danh sách liên kết.

Việc thực hiện ngăn xếp chỉ chia sẻ mục đích thứ hai.

// Queue
function Queue() {
        this.q = new Array(5);
        this.first = 0;
        this.size = 0;
}
Queue.prototype.enqueue = function(a) {
        var other;
        if (this.size == this.q.length) {
                other = new Array(this.size*2);
                for (var i = 0; i < this.size; i++) {
                        other[i] = this.q[(this.first+i)%this.size];
                }
                this.first = 0;
                this.q = other;
        }
        this.q[(this.first+this.size)%this.q.length] = a;
        this.size++;
};
Queue.prototype.dequeue = function() {
        if (this.size == 0) return undefined;
        this.size--;
        var ret = this.q[this.first];
        this.first = (this.first+1)%this.q.length;
        return ret;
};
Queue.prototype.peek = function() { return this.size > 0 ? this.q[this.first] : undefined; };
Queue.prototype.isEmpty = function() { return this.size == 0; };

// Stack
function Stack() {
        this.s = new Array(5);
        this.size = 0;
}
Stack.prototype.push = function(a) {
        var other;
    if (this.size == this.s.length) {
            other = new Array(this.s.length*2);
            for (var i = 0; i < this.s.length; i++) other[i] = this.s[i];
            this.s = other;
    }
    this.s[this.size++] = a;
};
Stack.prototype.pop = function() {
        if (this.size == 0) return undefined;
        return this.s[--this.size];
};
Stack.prototype.peek = function() { return this.size > 0 ? this.s[this.size-1] : undefined; };

5

Việc thực hiện ngăn xếp là tầm thường như được giải thích trong các câu trả lời khác.

Tuy nhiên, tôi không tìm thấy bất kỳ câu trả lời thỏa đáng nào trong chuỗi này để thực hiện một hàng đợi trong javascript, vì vậy tôi đã tự tạo ra.

Có ba loại giải pháp trong chủ đề này:

  • Mảng - Giải pháp tồi tệ nhất, sử dụng array.shift() trên một mảng lớn là rất không hiệu quả.
  • Danh sách được liên kết - Đó là O (1) nhưng sử dụng một đối tượng cho mỗi thành phần là hơi quá, đặc biệt là nếu có rất nhiều trong số chúng và chúng nhỏ, như lưu trữ số.
  • Mảng dịch chuyển bị trì hoãn - Nó bao gồm việc liên kết một chỉ mục với mảng. Khi một yếu tố bị mất hiệu lực, chỉ số sẽ di chuyển về phía trước. Khi chỉ số đến giữa của mảng, mảng được cắt thành hai để loại bỏ nửa đầu.

Mảng dịch chuyển bị trì hoãn là giải pháp thỏa đáng nhất trong tâm trí tôi, nhưng chúng vẫn lưu trữ mọi thứ trong một mảng lớn liền kề có thể gây ra vấn đề và ứng dụng sẽ loạng choạng khi mảng bị cắt.

Tôi đã thực hiện bằng cách sử dụng danh sách các mảng nhỏ được liên kết (tối đa 1000 phần tử mỗi mảng). Các mảng hoạt động giống như các mảng dịch chuyển bị trì hoãn, ngoại trừ chúng không bao giờ bị cắt: khi mọi phần tử trong mảng bị loại bỏ, mảng sẽ bị loại bỏ.

Gói hàng vào npm với chức năng FIFO cơ bản, tôi mới đẩy nó gần đây. Mã được chia thành hai phần.

Đây là phần đầu tiên

/** Queue contains a linked list of Subqueue */
class Subqueue <T> {
  public full() {
    return this.array.length >= 1000;
  }

  public get size() {
    return this.array.length - this.index;
  }

  public peek(): T {
    return this.array[this.index];
  }

  public last(): T {
    return this.array[this.array.length-1];
  }

  public dequeue(): T {
    return this.array[this.index++];
  }

  public enqueue(elem: T) {
    this.array.push(elem);
  }

  private index: number = 0;
  private array: T [] = [];

  public next: Subqueue<T> = null;
}

Và đây là Queuelớp chính :

class Queue<T> {
  get length() {
    return this._size;
  }

  public push(...elems: T[]) {
    for (let elem of elems) {
      if (this.bottom.full()) {
        this.bottom = this.bottom.next = new Subqueue<T>();
      }
      this.bottom.enqueue(elem);
    }

    this._size += elems.length;
  }

  public shift(): T {
    if (this._size === 0) {
      return undefined;
    }

    const val = this.top.dequeue();
    this._size--;
    if (this._size > 0 && this.top.size === 0 && this.top.full()) {
      // Discard current subqueue and point top to the one after
      this.top = this.top.next;
    }
    return val;
  }

  public peek(): T {
    return this.top.peek();
  }

  public last(): T {
    return this.bottom.last();
  }

  public clear() {
    this.bottom = this.top = new Subqueue();
    this._size = 0;
  }

  private top: Subqueue<T> = new Subqueue();
  private bottom: Subqueue<T> = this.top;
  private _size: number = 0;
}

: XCó thể dễ dàng xóa các chú thích ( ) để lấy mã javascript ES6.


4

Nếu bạn hiểu các ngăn xếp với các hàm push () và pop (), thì hàng đợi chỉ là để thực hiện một trong các thao tác này theo nghĩa đối diện. Đối diện của đẩy () là unshift () và đối diện với pop () es shift (). Sau đó:

//classic stack
var stack = [];
stack.push("first"); // push inserts at the end
stack.push("second");
stack.push("last");
stack.pop(); //pop takes the "last" element

//One way to implement queue is to insert elements in the oposite sense than a stack
var queue = [];
queue.unshift("first"); //unshift inserts at the beginning
queue.unshift("second");
queue.unshift("last");
queue.pop(); //"first"

//other way to do queues is to take the elements in the oposite sense than stack
var queue = [];
queue.push("first"); //push, as in the stack inserts at the end
queue.push("second");
queue.push("last");
queue.shift(); //but shift takes the "first" element

Một lời cảnh báo cho những người viết phần mềm hiệu suất quan trọng. Các .shift()phương pháp không phải là một việc thực hiện hàng đợi thích hợp. Đó là O (n) chứ không phải O (1) và sẽ chậm đối với các hàng đợi lớn.
Rudi Kershaw

3

Đây là phiên bản danh sách được liên kết của hàng đợi cũng bao gồm nút cuối cùng, như được đề xuất bởi @perkins và khi thích hợp nhất.

// QUEUE Object Definition

var Queue = function() {
  this.first = null;
  this.last = 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){ // for empty list first and last are the same
    this.first = node;
    this.last = node;
  } else { // otherwise we stick it on the end
    this.last.next=node;
    this.last=node;
  }

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

Queue.prototype.dequeue = function() {
  if (!this.first) //check for empty list
    return null;

  temp = this.first; // grab top of list
  if (this.first==this.last) {
    this.last=null;  // when we need to pop the last one
  }
  this.first = this.first.next; // move top of list down
  this.size -= 1;
  return temp;
};

Trong dequeue, bạn nên trả lại temp.data. Bởi vì đó là những gì đã được xếp hàng.
không phải là robot

3

Nếu bạn đang tìm kiếm ES6 OOP triển khai cấu trúc dữ liệu Stack và Queue với một số thao tác cơ bản (dựa trên danh sách được liên kết) thì có thể như sau:

Queue.js

import LinkedList from '../linked-list/LinkedList';

export default class Queue {
  constructor() {
    this.linkedList = new LinkedList();
  }

  isEmpty() {
    return !this.linkedList.tail;
  }

  peek() {
    if (!this.linkedList.head) {
      return null;
    }

    return this.linkedList.head.value;
  }

  enqueue(value) {
    this.linkedList.append(value);
  }

  dequeue() {
    const removedHead = this.linkedList.deleteHead();
    return removedHead ? removedHead.value : null;
  }

  toString(callback) {
    return this.linkedList.toString(callback);
  }
}

Stack.js

import LinkedList from '../linked-list/LinkedList';

export default class Stack {
  constructor() {
    this.linkedList = new LinkedList();
  }

  /**
   * @return {boolean}
   */
  isEmpty() {
    return !this.linkedList.tail;
  }

  /**
   * @return {*}
   */
  peek() {
    if (!this.linkedList.tail) {
      return null;
    }

    return this.linkedList.tail.value;
  }

  /**
   * @param {*} value
   */
  push(value) {
    this.linkedList.append(value);
  }

  /**
   * @return {*}
   */
  pop() {
    const removedTail = this.linkedList.deleteTail();
    return removedTail ? removedTail.value : null;
  }

  /**
   * @return {*[]}
   */
  toArray() {
    return this.linkedList
      .toArray()
      .map(linkedListNode => linkedListNode.value)
      .reverse();
  }

  /**
   * @param {function} [callback]
   * @return {string}
   */
  toString(callback) {
    return this.linkedList.toString(callback);
  }
}

Và triển khai LinkedList được sử dụng cho Stack và Queue trong các ví dụ ở trên có thể được tìm thấy trên GitHub tại đây .


2

Không có mảng

//Javascript stack linked list data structure (no array)

function node(value, noderef) {
    this.value = value;
    this.next = noderef;
}
function stack() {
    this.push = function (value) {
        this.next = this.first;
        this.first = new node(value, this.next);
    }
    this.pop = function () {
        var popvalue = this.first.value;
        this.first = this.first.next;
        return popvalue;
    }
    this.hasnext = function () {
        return this.next != undefined;
    }
    this.isempty = function () {
        return this.first == undefined;
    }

}

//Javascript stack linked list data structure (no array)
function node(value, noderef) {
    this.value = value;
    this.next = undefined;
}
function queue() {
    this.enqueue = function (value) {
        this.oldlast = this.last;
        this.last = new node(value);
        if (this.isempty())
            this.first = this.last;
        else 
           this.oldlast.next = this.last;
    }
    this.dequeue = function () {
        var queuvalue = this.first.value;
        this.first = this.first.next;
        return queuvalue;
    }
    this.hasnext = function () {
        return this.first.next != undefined;
    }
    this.isempty = function () {
        return this.first == undefined;
    }

}

Làm thế nào tôi có thể chạy chức năng nội bộ như đẩy pop?
Chandan Kumar

2

Cấu trúc mảng thông thường trong Javascript là một Stack (đầu tiên vào trước, cuối cùng) và cũng có thể được sử dụng như một hàng đợi (đầu tiên vào, ra trước) tùy thuộc vào các cuộc gọi bạn thực hiện.

Kiểm tra liên kết này để xem cách làm cho một mảng hoạt động như một hàng đợi:

Hàng đợi


2

Trân trọng,

Trong Javascript, việc thực hiện các ngăn xếp và hàng đợi như sau:

Ngăn xếp: Ngăn xếp là một thùng chứa các đối tượng được chèn và loại bỏ theo nguyên tắc nhập trước xuất trước (LIFO).

  • Đẩy: Phương thức thêm một hoặc nhiều phần tử vào cuối một mảng và trả về độ dài mới của mảng.
  • Pop: Phương thức loại bỏ phần tử cuối cùng khỏi một mảng và trả về phần tử đó.

Hàng đợi: Hàng đợi là một thùng chứa các đối tượng (một bộ sưu tập tuyến tính) được chèn và loại bỏ theo nguyên tắc nhập trước xuất trước (FIFO).

  • Unshift: Phương thức thêm một hoặc nhiều phần tử vào đầu một mảng.

  • Shift: Phương thức loại bỏ phần tử đầu tiên khỏi một mảng.

let stack = [];
 stack.push(1);//[1]
 stack.push(2);//[1,2]
 stack.push(3);//[1,2,3]
 
console.log('It was inserted 1,2,3 in stack:', ...stack);

stack.pop(); //[1,2]
console.log('Item 3 was removed:', ...stack);

stack.pop(); //[1]
console.log('Item 2 was removed:', ...stack);


let queue = [];
queue.push(1);//[1]
queue.push(2);//[1,2]
queue.push(3);//[1,2,3]

console.log('It was inserted 1,2,3 in queue:', ...queue);

queue.shift();// [2,3]
console.log('Item 1 was removed:', ...queue);

queue.shift();// [3]
console.log('Item 2 was removed:', ...queue);


1
  var x = 10; 
  var y = 11; 
  var Queue = new Array();
  Queue.unshift(x);
  Queue.unshift(y);

  console.log(Queue)
  // Output [11, 10]

  Queue.pop()
  console.log(Queue)
  // Output [11]

1

Dường như với tôi rằng mảng dựng sẵn là tốt cho một ngăn xếp. Nếu bạn muốn một hàng đợi trong TypeScript thì đây là một triển khai

/**
 * A Typescript implementation of a queue.
 */
export default class Queue {

  private queue = [];
  private offset = 0;

  constructor(array = []) {
    // Init the queue using the contents of the array
    for (const item of array) {
      this.enqueue(item);
    }
  }

  /**
   * @returns {number} the length of the queue.
   */
  public getLength(): number {
    return (this.queue.length - this.offset);
  }

  /**
   * @returns {boolean} true if the queue is empty, and false otherwise.
   */
  public isEmpty(): boolean {
    return (this.queue.length === 0);
  }

  /**
   * Enqueues the specified item.
   *
   * @param item - the item to enqueue
   */
  public enqueue(item) {
    this.queue.push(item);
  }

  /**
   *  Dequeues an item and returns it. If the queue is empty, the value
   * {@code null} is returned.
   *
   * @returns {any}
   */
  public dequeue(): any {
    // if the queue is empty, return immediately
    if (this.queue.length === 0) {
      return null;
    }

    // store the item at the front of the queue
    const item = this.queue[this.offset];

    // increment the offset and remove the free space if necessary
    if (++this.offset * 2 >= this.queue.length) {
      this.queue = this.queue.slice(this.offset);
      this.offset = 0;
    }

    // return the dequeued item
    return item;
  };

  /**
   * Returns the item at the front of the queue (without dequeuing it).
   * If the queue is empty then {@code null} is returned.
   *
   * @returns {any}
   */
  public peek(): any {
    return (this.queue.length > 0 ? this.queue[this.offset] : null);
  }

}

Và đây là một Jestthử nghiệm cho nó

it('Queue', () => {
  const queue = new Queue();
  expect(queue.getLength()).toBe(0);
  expect(queue.peek()).toBeNull();
  expect(queue.dequeue()).toBeNull();

  queue.enqueue(1);
  expect(queue.getLength()).toBe(1);
  queue.enqueue(2);
  expect(queue.getLength()).toBe(2);
  queue.enqueue(3);
  expect(queue.getLength()).toBe(3);

  expect(queue.peek()).toBe(1);
  expect(queue.getLength()).toBe(3);
  expect(queue.dequeue()).toBe(1);
  expect(queue.getLength()).toBe(2);

  expect(queue.peek()).toBe(2);
  expect(queue.getLength()).toBe(2);
  expect(queue.dequeue()).toBe(2);
  expect(queue.getLength()).toBe(1);

  expect(queue.peek()).toBe(3);
  expect(queue.getLength()).toBe(1);
  expect(queue.dequeue()).toBe(3);
  expect(queue.getLength()).toBe(0);

  expect(queue.peek()).toBeNull();
  expect(queue.dequeue()).toBeNull();
});

Hy vọng ai đó thấy điều này hữu ích,

Chúc mừng

Stu


0

Tạo một cặp lớp cung cấp các phương thức khác nhau mà mỗi cấu trúc dữ liệu này có (đẩy, bật, nhìn trộm, v.v.). Bây giờ thực hiện các phương pháp. Nếu bạn quen thuộc với các khái niệm đằng sau ngăn xếp / hàng đợi, điều này sẽ khá đơn giản. Bạn có thể triển khai ngăn xếp với một mảng và một hàng đợi với một danh sách được liên kết, mặc dù chắc chắn có nhiều cách khác để thực hiện. Javascript sẽ làm cho việc này trở nên dễ dàng, vì nó được gõ yếu, do đó bạn thậm chí không phải lo lắng về các loại chung chung, điều mà bạn phải làm nếu bạn triển khai nó trong Java hoặc C #.


0

Đây là triển khai ngăn xếp của tôi.

function Stack() {
this.dataStore = [];
this.top = 0;
this.push = push;
this.pop = pop;
this.peek = peek;
this.clear = clear;
this.length = length;
}
function push(element) {
this.dataStore[this.top++] = element;
}
function peek() {
return this.dataStore[this.top-1];
}
function pop() {
return this.dataStore[--this.top];
}
function clear() {
this.top = 0;
}
function length() {
return this.top;
}

var s = new Stack();
s.push("David");
s.push("Raymond");
s.push("Bryan");
console.log("length: " + s.length());
console.log(s.peek());

0

bạn có thể sử dụng WeakMaps để triển khai thuộc tính riêng tư trong lớp ES6 và lợi ích của các phương thức và phương thức chuỗi trong ngôn ngữ JavaScript như dưới đây:

const _items = new WeakMap();

class Stack {
  constructor() {
    _items.set(this, []);
  }

push(obj) {
  _items.get(this).push(obj);
}

pop() {
  const L = _items.get(this).length;
  if(L===0)
    throw new Error('Stack is empty');
  return _items.get(this).pop();
}

peek() {
  const items = _items.get(this);
  if(items.length === 0)
    throw new Error ('Stack is empty');
  return items[items.length-1];
}

get count() {
  return _items.get(this).length;
}
}

const stack = new Stack();

//now in console:
//stack.push('a')
//stack.push(1)
//stack.count   => 2
//stack.peek()  => 1
//stack.pop()   => 1
//stack.pop()   => "a"
//stack.count   => 0
//stack.pop()   => Error Stack is empty

0

Xây dựng một hàng đợi bằng cách sử dụng hai ngăn xếp.

O (1) cho cả hoạt động enqueue và dequeue.

class Queue {
  constructor() {
    this.s1 = []; // in
    this.s2 = []; // out
  }

  enqueue(val) {
    this.s1.push(val);
  }

  dequeue() {
    if (this.s2.length === 0) {
      this._move();
    }

    return this.s2.pop(); // return undefined if empty
  }

  _move() {
    while (this.s1.length) {
      this.s2.push(this.s1.pop());
    }
  }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.