Подтвердить что ты не робот

Есть ли отсортированный контейнер в STL?

Есть ли отсортированный контейнер в STL?

Я имею в виду следующее: у меня есть std::vector<Foo>, где Foo - это пользовательский класс. У меня также есть какой-то компаратор, который будет сравнивать поля класса Foo.

Теперь, где-то в моем коде я делаю:

std::sort( myvec.begin(), myvec.end(), comparator );

который будет сортировать вектор в соответствии с правилами, которые я определил в компараторе.

Теперь я хочу вставить элемент класса Foo в этот вектор. Если бы я мог, я хотел бы просто написать:

 mysortedvector.push_back( Foo() );

и то, что случилось бы, - то, что вектор поместит этот новый элемент согласно компаратору на его место.

Вместо этого прямо сейчас я должен написать:

myvec.push_back( Foo() );
std::sort( myvec.begin(), myvec.end(), comparator );

это просто пустая трата времени, поскольку вектор уже отсортирован, и все, что мне нужно, это правильно разместить новый элемент.

Теперь, из-за характера моей программы, я не могу использовать std::map<> как у меня нет пар ключ/значение, просто простой вектор.

Если я использую stl::list, мне снова нужно вызывать sort после каждой вставки.

4b9b3361

Ответ 1

Да, std::set, std::multiset, std::map, и std::multimap все отсортированы используя std::less в качестве операции сравнения по умолчанию. Основная используемая структура данных обычно представляет собой сбалансированное двоичное дерево поиска, такое как красно-черное дерево. Поэтому, если вы добавите элемент в эти структуры данных и затем перейдете по содержащимся элементам, результат будет в отсортированном порядке. Сложность добавления N элементов в структуру данных будет O (N log N) или такая же, как сортировка вектора из N элементов с использованием любой общей сложности O (log N).

В вашем конкретном сценарии, поскольку у вас нет пар ключ/значение, std::set или std::multiset, вероятно, лучший выбор.

Ответ 2

Я хотел бы подробнее остановиться на ответе Джейсона. Я согласен с Джейсоном, что std::set или std::multiset - лучший выбор для вашего конкретного сценария. Я хотел бы привести пример, чтобы помочь вам еще больше сузить выбор.

Предположим, у вас есть следующий класс Foo:

class Foo {
public:
    Foo(int v1, int v2) : val1(v1), val2(v2) {};
    bool operator<(const Foo &foo) const { return val2 < foo.val2; }
    int val1;
    int val2;
};

Здесь Foo перегружает оператор <. Таким образом, вам не нужно указывать явную функцию сравнения. В результате вы можете просто использовать std::multiset вместо std::vector следующим образом. Вам просто нужно заменить push_back() на insert():

int main()
{
    std::multiset<Foo> ms;
    ms.insert(Foo(1, 6));
    ms.insert(Foo(2, 5));
    ms.insert(Foo(3, 4));
    ms.insert(Foo(1, 4));

    for (auto const &foo : ms)
        std::cout << foo.val1 << " " << foo.val2 << std::endl;

    return 0;
}

Выход:

3 4
2 4
1 5
1 6

Как видите, контейнер отсортирован по члену val2 класса Foo на основе оператора <. Однако, если вы используете std::set вместо std::multiset, вы получите другой вывод:

int main()
{
    std::set<Foo> s;
    s.insert(Foo(1, 6));
    s.insert(Foo(1, 5));
    s.insert(Foo(3, 4));
    s.insert(Foo(2, 4));

    for (auto const &foo : s)
        std::cout << foo.val1 << " " << foo.val2 << std::endl;

    return 0;
}

Выход:

3 4
1 5
1 6

Здесь второй объект Foo где val2 равен 4, отсутствует, потому что std::set допускает только уникальные записи. Если данные уникальны определяются на основе предоставленного < оператора. В этом примере оператор < сравнивает члены val2 друг с другом. Следовательно, два объекта Foo равны, если их члены val2 имеют одинаковое значение.

Таким образом, ваш выбор зависит от того, хотите ли вы хранить объекты Foo которые могут быть равными, в зависимости от оператора <.

Код на Ideone

Ответ 3

Я не думаю, что функциональность существует в STL, std::vector может сортировать только раздел, nth_element, stable_partition, partial_sort, stable_sort и сортировка.

Однако вы можете создать обертку для std::vector

#include <vector>

template <class T>
class VectorSortWrapper
{
public:
    std::vector<T> m_VectorSorted;

    void InsertSortedAscending(T item)
    {
        for(int i = 0; i < m_VectorSorted.size(); i++)
        {
            if( item.GetOrderValue() <= m_VectorSorted[i].GetOrderValue() )
            {
                m_VectorSorted.insert(m_VectorSorted.begin() + i, item);
                break;
            }       
        }
    }

    void InsertSortedDecending(T item)
    {
        for(int i = 0; i < m_VectorSorted.size(); i++)
        {
            if( item.GetOrderValue() >= m_VectorSorted[i].GetOrderValue() )
            {
                m_VectorSorted.insert(m_VectorSorted.begin() + i, item);
                break;
            }       
        }
    }

};