Самый быстрый способ перебора самых старых элементов в массиве? (Самая быстрая реализация очереди)

#javascript #arrays #loops #queue #iteration

#javascript #массивы #циклы #очередь #итерация

Вопрос:

См. Также Редактирование

Я работаю на JavaScript, но читаемый псевдокод любого типа может ответить на мой вопрос.

Мне будет сложно описать это, поэтому, пожалуйста, не стесняйтесь комментировать пояснения — я отвечу на них и соответствующим образом доработаю свой пост.

По сути, у меня есть массив, который действует как очередь, элементы добавляются, и когда они обрабатываются, их нужно удалить, и в конечном итоге будет добавлено больше. Какой самый быстрый способ получить первый элемент в массиве, когда меня не волнует индекс? Я просто хочу выполнять итерацию на основе первого добавления без необходимости каждый раз сдвигать все записи в массиве вниз. Также стоит упомянуть, что я не перебираю массив, у меня есть главный цикл для моего приложения, который проверяет, есть ли в массиве элементы в каждом цикле, и если есть, он захватит эти данные, а затем удалит их из массива. В настоящее время для быстрого выполнения этого я использую pop, но теперь понимаю, что мне нужно каждый раз сначала получать самый старый элемент в очереди, а не самый новый.

Для получения дополнительных разъяснений, если это необходимо:

В моем приложении у меня есть блоки необработанных данных, которые сначала должны быть запущены через функцию, чтобы быть готовыми к использованию другими частями моего приложения. Каждый блок имеет уникальный идентификатор, который я передаю функции для его анализа. В целях оптимизации я анализирую блоки данных только по мере необходимости.

Чтобы сделать это, в моей текущей системе, когда я понимаю, что мне нужен блок для анализа, я помещаю его уникальный идентификатор в массив, затем непрерывный цикл в моем приложении постоянно проверяет указанный массив, проверяя, есть ли в нем элементы. Если это произойдет, он извлекает последний элемент массива и передает уникальный идентификатор в функцию синтаксического анализа.

По соображениям производительности на каждой итерации цикла может быть проанализирован только один блок данных. Проблема возникает, когда несколько блоков данных уже находятся в массиве очереди, и я добавляю больше элементов в массив до того, как цикл сможет завершить передачу функции уже существующих идентификаторов в массиве. По сути, новые идентификаторы, которые необходимо проанализировать, добавляются в конец массива, прежде чем мой цикл сможет их очистить.

Теперь это не так уж плохо, потому что новые данные требуются несколько реже, но когда это так, сразу добавляется множество идентификаторов, и это атрибут приложения, который я не могу изменить.

Поскольку я использую pop, очевидно, что самый последний добавленный идентификатор всегда анализируется первым, но я выбрал этот метод, поскольку считал, что это самый быстрый способ перебора такой очереди. Однако я пришел к выводу, что предпочел бы сначала проанализировать самые старые элементы в списке.

По сути, я ищу способ перебирать массив от самого старого к самому новому без необходимости каждый раз перестраивать массив. Индекс массива не важен, мне просто нужно сначала добавленное, сначала проанализированное поведение.

Например, я знаю, что всегда могу просто передать 0-й элемент в массиве своей функции, а затем сместить остальные записи вниз, однако я считаю, что необходимость сдвигать вниз остальные элементы в массиве слишком затратна для производительности и не стоит того. Если я просто тупой, и это не должно иметь реальных затрат, пожалуйста, дайте мне знать, но все же это похоже на исправление лейкопластыря. Я уверен, что есть лучшее решение.

Я открыт и для других структур данных, поскольку массив содержит только строки.

Спасибо

РЕДАКТИРОВАТЬ: при продолжении поиска в Google у меня возникает ощущение ладони, и я понял, что проблема, которую я описываю, — это стек против очереди. Но теперь мой вопрос переходит к тому, какова самая быстрая реализация очереди, когда индекс на самом деле не имеет для меня ценности?

Комментарии:

1. Массив с заголовочным индексом, который не подходит для ваших целей?

2. @hwsiewесли я правильно понимаю, что такое индекс заголовка, то нет, потому что я очищу массив, и он будет оставаться пустым в течение длительного времени, пока не будут добавлены пакеты. По этой причине я не обязательно вижу простой способ отслеживать индекс.

3. хм.. Я немного смущен, если вы можете подробнее рассказать. Очередь — это структура данных FIFO. индекс заголовка очереди равен нулю, когда он пуст, а индекс заголовка обновляется только при добавлении первого элемента или удалении элемента. это должна быть довольно простая операция с add() amp; remove()

4. Однако этот подход может занять больше места, поскольку никакие элементы фактически не удаляются из массива. Другой подход заключается в использовании связанного списка для реализации очереди.

5. FIFO — это именно то, что мне нужно, возможно, я перепутал себя выше. Допустим, я добавляю 10 новых элементов, упорядоченных с 1 по 10. В настоящее время элемент 10 обрабатывается и извлекается первым, но мне нужно, чтобы элемент 1 обрабатывался и удалялся первым. Я понимаю, что это делает метод сдвига, но мне не обязательно переиндексировать массив. Я думал, что будет лучшее решение, чем это.

Ответ №1:

Ниже приведена реализация очереди FIFO с использованием односвязного списка в javascript.

Для получения дополнительной информации о связанном списке -> https://www.geeksforgeeks.org/linked-list-set-1-introduction /

 // queue implementation with linked list
var ListNode = function(val,next = null){
  
  this.val  = val 
  this.next = next

};

var Queue = function(){
  
  let head = null;
  let tail = null;
  
  this.show = function(){
    
    let curr = head;
    let q = [];
    
    while(curr){
      q.push(curr.val);
      curr = curr.next;
    }
    
    return q.join(' -> ');
  }
  
  this.enqueue = function(item){
    
    let node = new ListNode(item);
    if(!head) {
      head = node;
      tail = node;
    } else {
      tail.next = node;
      tail = node;
    }
    
  }
  
  this.dequeue = function(){
    
    if(!head) return null;
    else {
    
      let first = head;
      head = head.next;
      
      first.next = null;
      
      return first;
    }
    
  }
  
}

var myQueue = new Queue();
myQueue.enqueue(1); // head -> 1 
console.log(myQueue.show())
myQueue.enqueue(2); // head -> 1 -> 2
console.log(myQueue.show())
myQueue.enqueue(3); // head -> 1 -> 2 -> 3
console.log(myQueue.show())
myQueue.dequeue(); // head -> 2 -> 3
console.log(myQueue.show()) 

Комментарии:

1. Я отмечу это как ответ, поскольку это работает и выполняется быстро из моего quick jsbench, но пакет в комментариях выше на самом деле еще быстрее, поэтому я в итоге пошел на это. Спасибо за вашу помощь!