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

Можно ли отсортировать list?

1.7 Middle🔥 131 комментариев
#STL контейнеры и алгоритмы

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

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

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

Сортировка std::list

Да, std::list можно отсортировать, но это делается иначе, чем для std::vector. Различие обусловлено архитектурой этих контейнеров.

Способ 1: Метод list::sort() (рекомендуемый)

Классы std::list и std::forward_list имеют собственный метод sort(), который работает эффективнее, чем std::sort:

#include <list>
#include <iostream>

int main() {
    std::list<int> myList = {5, 2, 8, 1, 9, 3};
    
    // Сортировка в порядке возрастания
    myList.sort();
    
    // Вывод: 1 2 3 5 8 9
    for (int val : myList) {
        std::cout << val << " ";
    }
    
    return 0;
}

Сортировка с пользовательским компаратором

#include <list>

struct Person {
    std::string name;
    int age;
};

// Компаратор для сортировки по возрасту
bool compareByAge(const Person& a, const Person& b) {
    return a.age < b.age;
}

int main() {
    std::list<Person> people = {
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35}
    };
    
    // Сортировка с компаратором
    people.sort(compareByAge);
    
    // Или с лямбда-функцией
    people.sort([](const Person& a, const Person& b) {
        return a.name < b.name;  // По имени
    });
    
    return 0;
}

Почему не используется std::sort для list?

❌ std::sort работает неэффективно для list

std::list<int> myList = {5, 2, 8, 1, 9};

// Это РАБОТАЕТ, но неэффективно!
// std::sort требует random access, а list имеет только bidirectional access
std::sort(myList.begin(), myList.end());

// Компилятор может вывести ошибку или предупреждение
// Поскольку список имеет только bidirectional iterators

Причины неэффективности:

  1. Отсутствие random accessstd::sort использует алгоритм QuickSort, требующий индексирования элементов. std::list имеет только bidirectional iterators.

  2. Нарушение cache-локальности — элементы списка разбросаны в памяти, что приводит к частым cache miss.

  3. Дополнительные операции — std::sort может попытаться доступ к элементам по индексу, что для list требует пробежки по всем предыдущим элементам.

Почему list::sort() эффективнее

std::list<int> myList = {5, 2, 8, 1, 9};

// list::sort() использует алгоритм MergeSort
// Это оптимально для связанных списков
myList.sort();

// Сложность: O(n log n)
// Не требует random access
// Работает in-place с минимальными аллокациями

Почему MergeSort для list?

  • Стабильная сортировка — сохраняет относительный порядок эквивалентных элементов
  • Логарифмическая стабильность — не требует random access
  • Предсказуемая производительность — всегда O(n log n)
  • In-place — работает без дополнительных контейнеров

Сравнение производительности

#include <list>
#include <vector>
#include <algorithm>
#include <chrono>

int main() {
    const int N = 1000000;
    
    // list::sort() — оптимально
    std::list<int> list(N);
    // Заполнение случайными данными...
    auto start = std::chrono::high_resolution_clock::now();
    list.sort();  // Быстро!
    auto end = std::chrono::high_resolution_clock::now();
    
    // std::sort с vector — еще быстрее для целей сортировки
    std::vector<int> vec(N);
    // Заполнение...
    start = std::chrono::high_resolution_clock::now();
    std::sort(vec.begin(), vec.end());  // Очень быстро!
    end = std::chrono::high_resolution_clock::now();
    
    return 0;
}

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

Используйте list::sort() когда:

  • Нужна сортировка std::list
  • Требуется стабильная сортировка
  • Элементы часто удаляются/добавляются

Используйте std::vector + std::sort когда:

  • Много операций сортировки
  • Требуется максимальная производительность
  • Нужен random access к элементам

Полный пример с разными компараторами

#include <list>
#include <iostream>

struct Task {
    std::string name;
    int priority;  // 1 — высший приоритет
};

int main() {
    std::list<Task> tasks = {
        {"Task A", 3},
        {"Task B", 1},
        {"Task C", 2}
    };
    
    // По приоритету
    tasks.sort([](const Task& a, const Task& b) {
        return a.priority < b.priority;
    });
    
    // По имени (лексикографически)
    tasks.sort([](const Task& a, const Task& b) {
        return a.name < b.name;
    });
    
    // Обратный порядок
    tasks.sort([](const Task& a, const Task& b) {
        return a.priority > b.priority;
    });
    
    return 0;
}

Заключение

Да, std::list можно отсортировать, и для этого обязательно используйте встроенный метод list::sort(), а не std::sort. Это обеспечит оптимальную производительность и безопасность работы с bidirectional iterators. Алгоритм MergeSort, используемый в list::sort(), идеально подходит для структуры связанного списка.