← Назад к вопросам

Для каких задач лучше использовать список

2.2 Middle🔥 181 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Для каких задач лучше использовать список

Выбор между массивом (Array), списком (List), и другими структурами данных зависит от конкретных требований приложения. Расскажу о нюансах и лучших практиках.

Когда использовать Array

1. Когда нужен быстрый доступ по индексу

const items = [10, 20, 30, 40, 50];
console.log(items[2]); // 30 - O(1) операция

2. Когда размер фиксирован

const pixels = new Array(1000000); // Много элементов фиксированного размера
for (let i = 0; i < pixels.length; i++) {
  pixels[i] = Math.random();
}

3. Для обработки последовательности элементов

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);     // [2, 4, 6, 8, 10]
const evens = numbers.filter(n => n % 2); // [2, 4]
const sum = numbers.reduce((a, b) => a + b); // 15

Когда использовать Linked List (Связный список)

1. Частые вставки/удаления в начале или середине

class Node {
  constructor(value) {
    this.value = value;
    this.next = null;
  }
}

class LinkedList {
  constructor() {
    this.head = null;
  }
  
  // Вставка в начало - O(1)
  insertAtBeginning(value) {
    const newNode = new Node(value);
    newNode.next = this.head;
    this.head = newNode;
  }
}

const list = new LinkedList();
list.insertAtBeginning(1); // Быстрая вставка
list.insertAtBeginning(2);
list.insertAtBeginning(3);

2. Когда неизвестен размер заранее и часто добавляются элементы

const tasks = [];

// JavaScript Array автоматически увеличивает размер
tasks.push("task1");
tasks.push("task2");
tasks.push("task3");
// Вернее: использовать Array с методом push()

3. Для реализации очереди (Queue)

class Queue {
  constructor() {
    this.head = null;
    this.tail = null;
  }
  
  enqueue(value) { // Добавить в конец - O(1)
    const newNode = new Node(value);
    if (!this.tail) {
      this.head = this.tail = newNode;
    } else {
      this.tail.next = newNode;
      this.tail = newNode;
    }
  }
  
  dequeue() { // Удалить из начала - O(1)
    if (!this.head) return null;
    const value = this.head.value;
    this.head = this.head.next;
    if (!this.head) this.tail = null;
    return value;
  }
}

Когда использовать Stack (Стек)

1. Для LIFO (Last In First Out) логики

class Stack {
  constructor() {
    this.items = [];
  }
  
  push(element) {
    this.items.push(element);
  }
  
  pop() {
    return this.items.pop();
  }
  
  peek() {
    return this.items[this.items.length - 1];
  }
}

// Пример: навигация в браузере (кнопка "Назад")
const history = new Stack();
history.push("/page1");
history.push("/page2");
history.push("/page3");
history.pop(); // Вернулись на /page2

2. Проверка сбалансированности скобок

function isBalanced(str) {
  const stack = new Stack();
  const pairs = { ')': '(', '}': '{', ']': '[' };
  
  for (let char of str) {
    if ('([{'.includes(char)) {
      stack.push(char);
    } else if (')}]'.includes(char)) {
      if (stack.pop() !== pairs[char]) return false;
    }
  }
  return stack.items.length === 0;
}

console.log(isBalanced("({}[])"));  // true
console.log(isBalanced("({[}])"));  // false

Когда использовать Set

1. Когда нужны уникальные элементы

const userIds = new Set();
userIds.add(1);
userIds.add(2);
userIds.add(1); // Игнорируется, уже есть

console.log(userIds.size); // 2

2. Для быстрой проверки наличия элемента

const allowedRoles = new Set(['admin', 'moderator', 'user']);

if (allowedRoles.has('admin')) {
  console.log('Доступ разрешен');
}
// Set.has() - O(1) быстрее чем Array.includes()

Когда использовать Map

1. Когда нужна пара ключ-значение с быстрым поиском

const cache = new Map();
cache.set('userId_1', { name: 'John', age: 30 });
cache.set('userId_2', { name: 'Jane', age: 25 });

const user = cache.get('userId_1'); // O(1)

2. Подсчет частоты элементов

function countFrequency(arr) {
  const freq = new Map();
  
  for (let item of arr) {
    freq.set(item, (freq.get(item) || 0) + 1);
  }
  
  return freq;
}

const result = countFrequency(['a', 'b', 'a', 'c', 'b', 'a']);
console.log(result); // Map { 'a' => 3, 'b' => 2, 'c' => 1 }

Сравнение сложностей

ОперацияArrayLinked ListSetMap
Доступ по индексуO(1)O(n)N/AO(1)
Поиск элементаO(n)O(n)O(1)O(1)
Вставка в началоO(n)O(1)O(1)O(1)
Вставка в конецO(1)O(1)O(1)O(1)
Удаление элементаO(n)O(n)O(1)O(1)

Практические рекомендации

Во Frontend разработке:

  • Array - 90% случаев (работа с UI элементами, результатами API)
  • Set - уникальные ID, избежание дубликатов
  • Map - кеширование, словари
  • Linked List - редко (в спецсценариях оптимизации)

Пример из реальной практики:

// Правильно: кеширование с Map
const userCache = new Map();

async function getUser(userId) {
  if (userCache.has(userId)) {
    return userCache.get(userId);
  }
  
  const user = await fetch(`/api/users/${userId}`);
  userCache.set(userId, user);
  return user;
}

// Работа со списком с фильтром и уникальностью
const tags = new Set();
const posts = [
  { id: 1, tags: ['javascript', 'react'] },
  { id: 2, tags: ['javascript', 'node'] }
];

posts.forEach(post => {
  post.tags.forEach(tag => tags.add(tag));
});

console.log([...tags]); // ['javascript', 'react', 'node']

Итог

Выбор структуры данных зависит от:

  • Частоты операций (поиск, вставка, удаление)
  • Требуемой сложности (O(1), O(n), O(log n))
  • Особенностей данных (уникальность, пары ключ-значение)

В 99% случаев во Frontend используй Array, Set и Map. Связные списки, деки и другие структуры нужны редко и только для специфических алгоритмических задач.