คุณจะใช้งาน Stack และ Queue ใน JavaScript ได้อย่างไร


740

วิธีที่ดีที่สุดในการนำ Stack และ Queue ไปใช้ใน JavaScript คืออะไร?

ฉันกำลังมองหาอัลกอริธึมการหลบหลีกและฉันต้องการโครงสร้างข้อมูลเหล่านี้

คำตอบ:


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

นำมาจาก " 9 javascript tips ที่คุณอาจไม่รู้ "


217
ฉันจะแนะนำอย่างระมัดระวังในการใช้ queue.shift IIRC ไม่ใช่ O (1) แต่ O (n) และอาจช้าเกินไปหากคิวมีขนาดใหญ่
MAK

20
ฉันจะบอกว่าสิ่งนี้ขึ้นอยู่กับการใช้งานจาวาสคริปต์ ฉันไม่คิดว่ามันถูกกำหนดไว้ในข้อกำหนดของจาวาสคริปต์
Georg Schölly

9
ดูcode.stephenmorley.org/javascript/queuesสำหรับการนำไปใช้งานแบบง่ายที่ช่วยเพิ่มประสิทธิภาพของคิว
Gili

15
สำหรับปัญหาด้านประสิทธิภาพของคิวให้ดูการเปรียบเทียบพฤติกรรมสแต็กสามประเภทที่แตกต่างกันในjsperf.com/queue-push-unshift-vs-shift-pop - ตอนนี้ถ้ามีเพียงคนที่ดีพอที่จะรวม rev ของ jsperf ที่จะ มีสคริปต์ JS ที่ @Gili พูดถึง ...
Nenotlep

3
ฉันรื้อฟื้นการโพสต์บล็อกที่เชื่อมโยงในคำตอบนี้อีกครั้งเนื่องจาก archive.org ไม่ได้มีประสิทธิภาพมากที่สุดเสมอไป ฉันอัปเดตลิงก์และรูปภาพเพื่อให้ทำงานได้ แต่ฉันไม่ได้เปลี่ยนแปลงอะไรเลย
Chev

87

Javascript มีวิธีการพุชและป๊อปซึ่งทำงานกับออบเจ็กต์อาร์เรย์ของ Javascript ทั่วไป

สำหรับคิวดูที่นี่:

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

คิวสามารถนำมาใช้ใน JavaScript โดยใช้วิธีการผลักและเปลี่ยนหรือวิธีการ unshift และป๊อปอัพของวัตถุอาร์เรย์ แม้ว่านี่จะเป็นวิธีที่ง่ายในการใช้คิว แต่ก็ไม่มีประสิทธิภาพมากสำหรับคิวขนาดใหญ่ - เนื่องจากวิธีการทำงานในอาร์เรย์วิธีการ shift และ unshift จะย้ายองค์ประกอบทุกอย่างในอาร์เรย์ทุกครั้งที่มีการเรียกใช้

Queue.js เป็นการใช้งานคิวที่ง่ายและมีประสิทธิภาพสำหรับ JavaScript ซึ่งฟังก์ชัน dequeue ทำงานในเวลาคงที่ที่ถูกตัดจำหน่าย เป็นผลให้สำหรับคิวที่มีขนาดใหญ่กว่ามันสามารถเร็วกว่าการใช้อาร์เรย์อย่างมีนัยสำคัญ


2
ด้วยลิงก์ที่คุณแชร์มีฟังก์ชั่นการตรวจสอบผลการเปรียบเทียบและฉันไม่เห็นประสิทธิภาพที่เพิ่มขึ้นเมื่อทดสอบกับ Google Chrome รุ่น 59 Queue.js ไม่สอดคล้องกับความเร็ว แต่ Chrome มีความสอดคล้องกับความเร็ว
Shiljo Paulson

นอกจากนี้ฉันได้สาธิตด้วย Que.js ว่าฟังก์ชั่นการถอนออกจากตำแหน่งไม่ได้ลบรายการออกจากคิวจริง ๆ หรือไม่ดังนั้นฉันจึงสงสัยว่ามันน่าจะใช้งานได้จริงหรือ ถ้าเป็นเช่นนั้นคุณจะเรียกคิวใหม่ได้อย่างไรหลังจากถอนรายการก่อนหน้าออก codepen.io/adamchenwei/pen/VxgNrX?editors=0001
Ezeewei

ดูเหมือนว่า dequeue ใน queue.js ยังต้องการหน่วยความจำเพิ่มเติมเนื่องจากมันทำการโคลนอาร์เรย์ด้วย slice
JaTo

ยิ่งกว่านั้นอาร์เรย์ที่ซ่อนอยู่นั้นใหญ่ขึ้นเรื่อย ๆ ทุกองค์ประกอบที่เพิ่มเข้ามา แม้ว่าการนำไปใช้จะลดขนาดอาเรย์เป็นครั้งคราวขนาดโดยรวมจะเพิ่มขึ้น
Philipp Mitterer

73

อาร์เรย์

ซ้อนกัน:

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

1
Array.prototype.pop ไม่ลบค่าออกจากด้านบน (องค์ประกอบแรก) ของ Array มันลบค่าจากด้านล่าง (องค์ประกอบสุดท้าย) ของอาร์เรย์
Michael Geller

21
@MichaelGeller ส่วนบนสุดของสแต็กเป็นองค์ประกอบสุดท้ายของ Array วิธีการพุชและป๊อปอาเรย์จะทำงานเหมือนกองซ้อน
mrdommyg

@mrdommyg Array.prototype.pop ลบองค์ประกอบสุดท้ายของอาร์เรย์ (ดูdeveloper.mozilla.org/en/docs/Web/JavaScript/Reference/ ...... ) สุดท้ายในบริบทนี้หมายถึงองค์ประกอบที่มีดัชนีสูงสุด อาร์เรย์ใน JS ไม่มีส่วนเกี่ยวข้องกับสแต็ก มันไม่ได้เป็นเพียงสแต็กเพราะมันมีวิธีการป๊อป ป๊อปหมายถึง "ลบองค์ประกอบสุดท้ายแล้วส่งคืน" แน่นอนคุณสามารถเลียนแบบการทำงานของสแต็กที่มีอาร์เรย์ แต่อาร์เรย์ยังไม่ได้เป็นสแต็ก มันยังคงเป็นรายการ (วัตถุ "รายการเช่น" ตาม MDN)
Michael Geller

5
@MichaelGeller พฤติกรรมของสแต็กคือ "เข้าก่อนออกก่อน" หากคุณใช้มันโดยใช้อาร์เรย์ใน JavaScript ด้วยpushและpopวิธีการแก้ไขปัญหาที่เกิดขึ้นแล้ว ฉันไม่เห็นจุดของคุณที่นี่
Rax Weber

2
@MichaelGeller สแต็คเป็นแนวคิด อาร์เรย์ JS คือ (เหนือสิ่งอื่นใด) โดยการกำหนดสแต็กโดยอาศัยการใช้ความหมายสแต็ก เพียงเพราะมันยังใช้ซีแมนทิกส์ของอาเรย์ไม่เปลี่ยนสิ่งนั้น คุณสามารถใช้อาร์เรย์ JS เหมือนสแต็กนอกกรอบและในบริบทนั้นสิ่งที่คุณกดและป๊อปคือองค์ประกอบ "ด้านบน"
Hans

32

หากคุณต้องการสร้างโครงสร้างข้อมูลของคุณเองคุณสามารถสร้างของคุณเอง:

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

13
เพื่อหลีกเลี่ยงการต้องวนซ้ำสิ่งทั้งหมดเพื่อผนวกเข้ากับท้ายสุดให้เก็บการอ้างอิงถึงสิ่งสุดท้ายผ่านทาง this.last = node;
Perkins

9
อย่าใช้คิวใด ๆ เช่นนี้จนกว่าคุณจะมีเหตุผลที่ดีสำหรับมัน ... ในขณะที่มันอาจดูเหมือนถูกต้องตามหลักเหตุผลซีพียูไม่ทำงานตามนามธรรมของมนุษย์ การวนซ้ำโครงสร้างข้อมูลที่มีพอยน์เตอร์อยู่ทั่วสถานที่จะทำให้แคชหายไปใน CPU ซึ่งแตกต่างจากอาร์เรย์ลำดับซึ่งมีประสิทธิภาพสูง blog.davidecoppola.com/2014/05/… ซีพียู HATE พอยน์เตอร์ที่มีความหลงใหลในการเผาไหม้ - พวกเขาน่าจะเป็นสาเหตุอันดับที่ 1 ของการพลาดแคช
Centril

1
นี่เป็นวิธีแก้ปัญหาที่ดึงดูด แต่ฉันไม่เห็นว่ามีการสร้างNodeลบเมื่อ popping / dequeuing ... พวกเขาจะไม่นั่งรอบหน่วยความจำ hogging จนกว่าเบราว์เซอร์ล่มหรือไม่
cneuro

5
@cneuro แตกต่างจาก C ++, JavaScript เป็นภาษาที่รวบรวมขยะ มีdeleteคำหลัก แต่มีประโยชน์เฉพาะในการทำเครื่องหมายคุณสมบัติของวัตถุว่าไม่เป็นปัจจุบันซึ่งแตกต่างจากการกำหนดundefinedให้กับคุณสมบัติเท่านั้น จาวาสคริปต์ยังมีnewโอเปอเรเตอร์ แต่มันถูกใช้เพื่อตั้งค่าthisเป็นวัตถุว่างเปล่าใหม่เมื่อเรียกใช้ฟังก์ชัน ใน C ++ คุณต้องจับคู่ทุกตัวnewด้วย a deleteแต่ไม่ได้อยู่ใน JavaScript เพราะ GC หากต้องการหยุดใช้หน่วยความจำใน JavaScript เพียงหยุดการอ้างอิงวัตถุและในที่สุดก็จะถูกเรียกคืน
binki

ไม่จำเป็นหรือไม่ในการตรวจสอบสแต็กสำหรับโอเวอร์โฟลว์ด้วยการตั้งค่าขนาดสแต็กสูงสุด?
bee

16

การใช้StackและการQueueใช้งานของฉันLinked 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

Javascript array shift () ช้าโดยเฉพาะเมื่อถือองค์ประกอบหลายอย่าง ฉันรู้วิธีนำคิวมาใช้สองวิธีด้วยความซับซ้อนของ O (1) ที่ถูกตัดจำหน่าย

อย่างแรกคือการใช้บัฟเฟอร์วงกลมและตารางเพิ่มเป็นสองเท่า ฉันได้ดำเนินการนี้มาก่อน คุณสามารถดูซอร์สโค้ดของฉันได้ที่นี่ https://github.com/kevyuu/rapid-queue

วิธีที่สองคือโดยใช้สองกอง นี่คือรหัสสำหรับคิวที่มีสองสแต็ก

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

นี่เป็นการเปรียบเทียบประสิทธิภาพโดยใช้ jsPerf

CircularQueue.shift () vs Array.shift ()

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

อย่างที่คุณเห็นมันเป็นชุดข้อมูลขนาดใหญ่ที่เร็วกว่ามาก


8

มีหลายวิธีที่คุณสามารถใช้สแต็กและคิวใน Javascript ได้ คำตอบข้างต้นส่วนใหญ่เป็นการใช้งานที่ค่อนข้างตื้นและฉันจะลองใช้สิ่งที่อ่านได้ง่ายขึ้น (โดยใช้คุณสมบัติไวยากรณ์ใหม่ของ es6) และมีประสิทธิภาพ

นี่คือการใช้สแต็ก:

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

และนี่คือวิธีที่คุณสามารถใช้สแต็ก:

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

หากคุณต้องการดูคำอธิบายโดยละเอียดเกี่ยวกับการใช้งานนี้และวิธีการปรับปรุงเพิ่มเติมคุณสามารถอ่านได้ที่นี่: http://jschap.com/data-structures-in-javascript-stack/

นี่คือรหัสสำหรับการใช้คิวใน 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
  }
}

นี่คือวิธีที่คุณสามารถใช้การใช้งานนี้:

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

หากต้องการดูบทแนะนำที่สมบูรณ์เกี่ยวกับวิธีการใช้โครงสร้างข้อมูลเหล่านี้และวิธีการปรับปรุงเหล่านี้เพิ่มเติมคุณอาจต้องการดูชุดข้อมูล 'การเล่นกับโครงสร้างข้อมูลใน javascript' ที่ jschap.com นี่คือลิงค์สำหรับคิว - http://jschap.com/playing-data-structures-javascript-queues/


7

คุณสามารถใช้คลาสการปรับแต่งของคุณเองตามแนวคิดนี่คือข้อมูลโค้ดที่คุณสามารถใช้ในการทำสิ่งต่างๆ

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

และเพื่อตรวจสอบนี้ใช้คอนโซลของคุณและลองบรรทัดเหล่านี้หนึ่งโดยหนึ่ง

>> 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 สำหรับแบบแผนการตั้งชื่อ: เมธอดที่ขึ้นต้นด้วยตัวสันนิษฐานว่าเป็นตัวสร้าง
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

หรือมิฉะนั้นคุณสามารถใช้สองอาร์เรย์เพื่อใช้โครงสร้างข้อมูลคิว

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

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

ถ้าฉันเปิดองค์ประกอบตอนนี้ผลลัพธ์จะเป็น 3,2,1 แต่เราต้องการโครงสร้าง FIFO เพื่อให้คุณสามารถทำสิ่งต่อไปนี้

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
วิธีนี้จะใช้งานได้เฉพาะเมื่อคุณไม่เคยpushเป็นครั้งแรกหลังจากคุณpop
jnnnnn

5

นี่คือการใช้คิวที่ค่อนข้างง่ายโดยมีเป้าหมายสองประการ:

  • ซึ่งแตกต่างจาก array.shift () คุณรู้ว่าวิธีการถอนพิษนี้ต้องใช้เวลาคงที่ (O (1))
  • เพื่อปรับปรุงความเร็ววิธีนี้ใช้การจัดสรรน้อยกว่าวิธีการแบบรายการเชื่อมโยง

การใช้งานสแต็กแบ่งปันเป้าหมายที่สองเท่านั้น

// 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

การใช้สแต็กนั้นเป็นเรื่องเล็กน้อยตามที่อธิบายไว้ในคำตอบอื่น ๆ

อย่างไรก็ตามฉันไม่พบคำตอบที่น่าพอใจในกระทู้นี้เพื่อใช้คิวในจาวาสคริปต์ดังนั้นฉันจึงสร้างของตัวเอง

มีวิธีแก้ปัญหาสามประเภทในชุดข้อความนี้:

  • อาร์เรย์ - ทางออกที่แย่ที่สุดที่ใช้array.shift()กับอาร์เรย์ขนาดใหญ่นั้นไม่มีประสิทธิภาพมาก
  • รายการที่เชื่อมโยง - มันเป็น O (1) แต่การใช้วัตถุสำหรับแต่ละองค์ประกอบนั้นมากเกินไปโดยเฉพาะอย่างยิ่งหากมีจำนวนมากและมีขนาดเล็กเช่นจัดเก็บตัวเลข
  • อาร์เรย์เลื่อนกะ - ประกอบด้วยการเชื่อมโยงดัชนีกับอาร์เรย์ เมื่อองค์ประกอบถูกเลื่อนออกไปดัชนีจะเลื่อนไปข้างหน้า เมื่อดัชนีถึงกึ่งกลางของอาร์เรย์อาร์เรย์จะถูกแบ่งเป็นสองส่วนเพื่อลบครึ่งแรก

อาร์เรย์เลื่อนที่ล่าช้าเป็นวิธีแก้ปัญหาที่น่าพอใจที่สุดในใจ แต่ก็ยังเก็บทุกอย่างไว้ในอาร์เรย์ขนาดใหญ่ที่ต่อเนื่องกันซึ่งอาจเป็นปัญหาได้และแอปพลิเคชั่นจะซวนเซ

ฉันใช้งานโดยใช้รายการที่เชื่อมโยงของอาร์เรย์ขนาดเล็ก (แต่ละอิลิเมนต์สูงสุดไม่เกิน 1,000 องค์ประกอบ) อาร์เรย์ทำหน้าที่เหมือนอาร์เรย์เลื่อนการทำงานล่าช้ายกเว้นจะไม่มีการแบ่งเป็นส่วน ๆ : เมื่อทุกองค์ประกอบในอาเรย์ถูกลบอาเรย์จะถูกยกเลิก

แพคเกจอยู่ในเวลา 17.00 น.พร้อมฟังก์ชั่นพื้นฐานของ FIFO ฉันเพิ่งผลักมันไปไม่นาน รหัสจะแบ่งออกเป็นสองส่วน

นี่คือส่วนแรก

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

และนี่คือQueueคลาสหลัก:

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

ประเภทคำอธิบายประกอบ ( : X) สามารถลบออกได้อย่างง่ายดายเพื่อรับรหัสจาวาสคริปต์ ES6


4

หากคุณเข้าใจสแต็คที่มีฟังก์ชัน push () และ pop () แสดงว่าคิวนั้นเป็นเพียงการทำให้หนึ่งในการดำเนินการเหล่านี้มีความหมายในทิศทางตรงกันข้าม Oposite of push () คือ unshift () และ oposite ของ pop () es shift () แล้ว:

//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

คำเตือนสำหรับซอฟต์แวร์ที่สำคัญเกี่ยวกับการเขียน .shift()วิธีการไม่ได้เป็นการดำเนินการที่เหมาะสมคิว มันคือ O (n) มากกว่า O (1) และจะช้าสำหรับคิวขนาดใหญ่
ฤดี Kershaw

3

นี่คือเวอร์ชันรายการที่เชื่อมโยงของคิวซึ่งรวมถึงโหนดสุดท้ายตามที่ @perkins แนะนำและเหมาะสมที่สุด

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

ใน dequeue คุณควรคืนค่า temp.data แทน เพราะนั่นคือสิ่งที่ถูกจัดคิว
ไม่ใช่หุ่นยนต์

3

หากคุณกำลังมองหาการนำ ES6 OOP ไปใช้กับโครงสร้างข้อมูล Stack และ Queue ด้วยการดำเนินการพื้นฐานบางอย่าง (ตามรายการที่ลิงก์) มันอาจมีลักษณะเช่นนี้:

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

และ LinkedList การดำเนินงานที่ใช้สำหรับการกองและคิวในตัวอย่างข้างต้นอาจจะพบได้บน GitHub ที่นี่


2

ไม่มีอาเรย์

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

}

ฉันจะเรียกใช้ฟังก์ชั่นภายในเช่น push pop ได้อย่างไร
Chandan Kumar

2

โครงสร้างอาเรย์ปกติใน Javascript คือสแต็ก (เข้าก่อน, ออกก่อน) และยังสามารถใช้เป็นคิว (เข้าก่อนเข้าก่อน) ขึ้นอยู่กับการโทรของคุณ

ตรวจสอบลิงค์นี้เพื่อดูวิธีการทำ Array ให้เหมือนกับ Queue:

คิว


2

ความนับถือ,

ใน Javascript การใช้สแต็กและคิวมีดังนี้:

สแต็ค:สแต็กเป็นคอนเทนเนอร์ของวัตถุที่ถูกแทรกและลบออกตามหลักการ last-in-first-out (LIFO)

  • Push: Method เพิ่มองค์ประกอบหนึ่งรายการขึ้นไปที่ส่วนท้ายของอาร์เรย์และส่งคืนความยาวใหม่ของอาร์เรย์
  • ป๊อป: วิธีการลบองค์ประกอบสุดท้ายจากอาร์เรย์และส่งกลับองค์ประกอบนั้น

คิว:คิวเป็นคอนเทนเนอร์ของวัตถุ (คอลเลกชันเชิงเส้น) ที่ถูกแทรกและลบออกตามหลักการ first-in-first-out (FIFO)

  • Unshift: วิธีการเพิ่มองค์ประกอบอย่างน้อยหนึ่งองค์ประกอบไปยังจุดเริ่มต้นของอาร์เรย์

  • Shift: เมธอดจะลบองค์ประกอบแรกออกจากอาร์เรย์

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

ดูเหมือนว่าฉันจะสร้างอาร์เรย์ในตัวสำหรับสแต็ก หากคุณต้องการคิวใน TypeScript นี่คือการใช้งาน

/**
 * 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);
  }

}

และนี่คือบทJestทดสอบสำหรับมัน

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

หวังว่าบางคนพบว่ามีประโยชน์นี้

ไชโย

Stu


0

สร้างคลาสที่ให้วิธีการต่าง ๆ ที่แต่ละโครงสร้างข้อมูลเหล่านี้มี (push, pop, peek, ฯลฯ ) ตอนนี้ใช้วิธีการ หากคุณคุ้นเคยกับแนวคิดที่อยู่เบื้องหลังสแต็ก / คิวสิ่งนี้ควรตรงไปตรงมา คุณสามารถใช้กองซ้อนกับอาร์เรย์และคิวที่มีรายการที่เชื่อมโยงแม้ว่าจะมีวิธีอื่น ๆ Javascript จะทำให้ง่ายขึ้นเพราะพิมพ์ได้อย่างอ่อนดังนั้นคุณไม่ต้องกังวลเกี่ยวกับประเภททั่วไปซึ่งคุณต้องทำหากคุณนำไปใช้ใน Java หรือ C #


0

นี่คือการใช้งานกองของฉัน

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

คุณสามารถใช้ WeakMaps เพื่อนำทรัพย์สินส่วนตัวไปใช้ในคลาส ES6 และประโยชน์ของการใช้สตริงและวิธีการในภาษาจาวาสคริปต์ดังต่อไปนี้:

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

สร้างคิวโดยใช้สองกอง

O (1) สำหรับการดำเนินงานทั้งคิวและคิว

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());
    }
  }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.