Як ви реалізуєте стек і чергу в JavaScript?


740

Який найкращий спосіб застосувати стек і чергу в 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, які ви можете не знати "


217
Я б радив обережно використовувати queue.shift. IIRC це не O (1), а O (n) і може бути занадто повільним, якщо черга стає великою.
МАК

20
Я б сказав, що це залежить від реалізації javascript. Я не думаю, що це визначено в специфікації javascript.
Георг Шоллі

9
Див. Code.stephenmorley.org/javascript/queues для простої реалізації, яка покращує продуктивність черги.
Гілі

15
Щодо проблем роботи з чергою , дивіться приємне порівняння трьох різних типів поведінки стека на jsperf.com/queue-push-unshift-vs-shift-pop - Тепер, якщо тільки комусь було досить приємно, щоб включити ревізію jsperf, яка б містять сценарій JS, про який згадував @Gili ...
Ненотлеп

3
Я воскресив допис у блозі, пов’язаний у цій відповіді, оскільки archive.org не завжди є найефективнішим. Я оновив посилання та зображення, щоб вони працювали, але нічого іншого не змінив.
Шев

87

У Javascript є методи push і pop, які працюють на звичайних об'єктах Javascript масиву.

Для черг дивіться тут:

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

Черги можуть бути реалізовані в JavaScript за допомогою методів "push and shift" або методів "без змін" та "pop" об'єкта масиву. Хоча це простий спосіб реалізації черг, він дуже неефективний для великих черг - через те, що методи працюють на масивах, методи shift і невмикання переміщують кожен елемент у масиві щоразу, коли вони викликаються.

Queue.js - це проста та ефективна реалізація черги для JavaScript, функція декерування працює в постійному амортизованому часі. Як результат, для великих черг це може бути значно швидше, ніж використання масивів.


2
З посиланням, яким ви поділилися, функціонувало перевірка результатів порівняльних показників, і я не бачу підвищення продуктивності при тестуванні з Google Chrome версією 59. Queue.js не відповідає своїй швидкості, але Chrome суттєво відповідав швидкості.
Шильйо Полсон

Також я створив демонстрацію за допомогою queue.js, що функція dequeue насправді не видаляє елемент з черги, тому мені цікаво, чи припустимо, як це працює? Якщо так, то як ви можете отримати нову чергу після видалення попереднього елемента? codepen.io/adamchenwei/pen/VxgNrX?editors=0001
Ezeewei

схоже, що dequeue в queue.js також потребує додаткової пам’яті, оскільки він клонує масив зрізом.
Джато

Крім того, базовий масив стає все більшим і більшим з кожним доданим елементом. Хоча реалізація час від часу зменшує розмір масиву, загальний розмір збільшується.
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 не видаляє значення з верхнього (першого елемента) масиву. Він видаляє значення з нижнього (останнього елемента) масиву.
Майкл Геллер

21
@MichaelGeller Верхня частина стека - останній елемент масиву. Методи натискання та попсингу масиву поводяться так само, як стек.
mrdommyg

@mrdommyg Array.prototype.pop видаляє останній елемент масиву (див. developer.mozilla.org/en/docs/Web/JavaScript/Reference/… ). Останній у цьому контексті означає елемент з найвищим показником. Масив у JS не має нічого спільного зі стеком. Це не стек лише тому, що він має поп-метод. Поп просто означає "видалити останній елемент і повернути його". Звичайно, ви можете імітувати функціональність стека з масивом, але масив все ще не є стеком за визначенням. Це все ще список (об’єкт "список як" згідно MDN).
Майкл Геллер

5
@MichaelGeller Поведінка стека "перше, останнє". Якщо реалізувати його з допомогою масиву в JavaScript з його pushі popметодами, то проблема вирішена. Я не бачу тут вашої суті.
Ракс Вебер

2
@MichaelGeller Стек є концептуальним. Масив JS є (серед іншого) за визначенням стеком в силу реалізації семантики стека. Тільки тому, що він також реалізує семантику масиву, це не змінює. Ви можете використовувати масив JS, як стек з поля, і в цьому контексті те, що ви натискаєте і додаєте - це "верхній" елемент.
Ганс

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;
Перкінс

9
Ніколи не реалізовуйте подібну чергу, якщо у вас немає поважної причини для цього ... хоча це може здатися логічно правильним, процесори не працюють відповідно до абстракцій людини. Ітерація над структурою даних, що має вказівники всюди, призведе до помилок кешу в ЦП, на відміну від послідовного масиву, який є високоефективним. blog.davidecoppola.com/2014/05/… покажчики ненависті процесорів з палкою пристрастю - вони, ймовірно, є причиною пропусків кеш-1 та доступу до пам'яті з оперативної пам'яті.
Сентриль

1
це спокусливе рішення, але я не бачу, як створені Nodeфайли видаляються при появі / відключенні ... чи не просто вони будуть сидіти навколо навішування пам'яті, поки браузер не вийде з ладу?
cneuro

5
@cneuro На відміну від C ++, JavaScript є мовою зібраного сміття. У ньому є deleteключове слово, але це корисно лише для позначення властивості об'єкта як такої, що відсутня - що відрізняється від присвоєння undefinedвластивості . У JavaScript також є newоператор, але він використовується просто для встановлення thisнового порожнього об'єкта при виклику функції. У C ++ вам потрібно з’єднувати кожен newз a delete, але не в JavaScript, оскільки GC. Щоб перестати використовувати пам’ять у JavaScript, просто перестаньте посилатися на об’єкт, і він з часом буде повернений.
бінкі

Чи не потрібно також перевіряти стек на переповнення, встановивши максимальний розмір стека?
бджола

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 () повільний, особливо якщо міститься багато елементів. Я знаю два способи реалізації черги з амортизованою складністю 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 () проти 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
Короткий перелік конвенції про іменування: метод, який починається з великого капіталу, який вважається конструктором.
Павло

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 (), ви знаєте, що цей метод dequeue потребує постійного часу (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

Реалізація стека є тривіальною, як пояснено в інших відповідях.

Однак я не знайшов задовільних відповідей у ​​цій темі для реалізації черги в JavaScript, тому я зробив свій власний.

У цій нитці є три типи рішень:

  • Масиви - найгірше рішення, використання array.shift()великого масиву є дуже неефективним.
  • Список пов'язаних списків - це O (1), але використання об'єкта для кожного елемента трохи надмірне, особливо якщо їх багато і вони невеликі, як зберігання чисел.
  • Масиви затримки зсуву - Він складається з асоціації індексу з масивом. Коли елемент відміняється, індекс рухається вперед. Коли індекс досягне середини масиву, масив розрізається навпіл, щоб видалити першу половину.

Масиви із затримкою зсуву - це найбільш задовільне рішення на мою думку, але вони все ще зберігають все в одному великому суміжному масиві, що може бути проблематично, і додаток буде хитатися, коли масив нарізається.

Я зробив реалізацію, використовуючи пов'язані списки невеликих масивів (максимум 1000 елементів у кожному). Масиви ведуть себе як масиви із затримкою зсуву, за винятком того, що вони ніколи не розрізані: коли кожен елемент масиву видаляється, масив просто відкидається.

Пакет працює в npm з базовим функціоналом 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) можна легко видалити, щоб отримати код javascript ES6.


4

Якщо ви розумієте стеки з функціями push () та pop (), то черга - це просто зробити одну з цих операцій у прямому сенсі. Протилежність push () - це зміщення () і опозиція 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), і для великих черг буде повільним.
Руді Кершо

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 and 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, яка використовується для Stack та Queue у наведених вище прикладах, можна знайти тут на 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?
Чандан Кумар

2

Звичайна структура масиву в Javascript являє собою стек (перший в, останній) і також може використовуватися як черга (спочатку в, перший вихід) залежно від дзвінків, які ви робите.

Перевірте це посилання, щоб дізнатися, як зробити так, щоб масив діяв як черга:

Черги


2

З повагою,

У Javascript реалізація стеків та черг полягає в наступному:

Стек: Стек - це контейнер з об'єктами, які вставляються та вилучаються відповідно до принципу "останній-перший-вихід" (LIFO).

  • Push: Метод додає один або більше елементів до кінця масиву і повертає нову довжину масиву.
  • Pop: Метод видаляє останній елемент з масиву і повертає цей елемент.

Черга: черга - це контейнер об'єктів (лінійна колекція), які вставляються та вилучаються за принципом «перший-у-першому-виходженні» (FIFO).

  • Розміщення: метод додає один або більше елементів до початку масиву.

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

Сподіваюся, хтось вважає це корисним,

Ура,

Сту


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 та переваг String властивостей і методів на мові JavaScript, як показано нижче:

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());
    }
  }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.