对已排序容器中的一个元素进行排序

时间:2016-03-16 16:30:11

标签: c++ sorting

我有一个已排序对象的向量。在某些时候,其中一个对象会更新,并且该元素(仅)必须再次排序。

最好的方法是什么?整个容器上的std :: sort()(如果容器已经排序,是否更快?)或者擦除()对象并将它插入()它应该在哪里?

编辑:在这种情况下,我必须使用矢量容器

3 个答案:

答案 0 :(得分:3)

理论上,您应该使用std::lower_boundstd::insert的组合,如下例所示:

#include <iostream>
#include <vector>
#include <algorithm>

template<typename T>
void insert(T value, std::vector<T>& data) {
  auto it = std::lower_bound(data.begin(), data.end(), value);
  data.insert(it, value);
}

template<typename C>
void show(const C& data) {
  for(const auto & item : data) {
    std::cout << item << " ";
  }
  std::cout << "\n";
}

int main() {

  std::vector<int> data { 1, 2, 4, 5, 7, 9 };
  show(data);
  insert(3, data);
  show(data);
  insert(6, data);
  show(data);
}

输出:

$ g++ example.cpp -std=c++14
./a.out
1 2 4 5 7 9
1 2 3 4 5 7 9
1 2 3 4 5 6 7 9

std::lower_bound(beg, end, val)将找到指向范围[beg, end)中第一个元素的迭代器,该元素不小于(即大于或等于)值(参见cppreference);它只适用于已分类的容器。它的复杂性在std::distance(beg, end)中是对数的。

std::vector<T>::insert(it, value)会在value之前插入it

在实践中(对于相对较少数量的元素),您可能最好使用线性搜索直到插入点,然后std::insert。换句话说:线性搜索为O(N)std::lower_boundO(log N),但对于具有约10-50个元素的向量,线性搜索更快(由于缓存效应)(您的里程可能会有所不同) )。

答案 1 :(得分:1)

如果向量已经排序,您可以通过二分法轻松找到更新值的新位置(与大小+ 2处的值进行比较并迭代...)。然后你在新旧地方之间移动所有元素。

这是一种相当优化的方式,因为旧位置和新位置之间的转换是一个将std::erasestd::insert组合在一起的压缩操作,但编写和测试会更加繁琐...

答案 2 :(得分:1)

  • std::sort的复杂程度为O(n log n)
  • 删除和插入的复杂程度为O(n)
  • 轮播的复杂程度为O(log n) + O(length_of_rotation)

您可以使用std::lower_bound查找新地点,使用std::rotate修复订单:

void update(std::vector<int>& v, std::vector<int>::iterator old_it, int new_value)
{
    if (old_it == v.end()) {
        return;   
    }
    auto it = std::lower_bound(v.begin(), v.end(), new_value);
    *old_it = new_value;

    if (old_it < it) {
        std::rotate(old_it, old_it + 1, it);
    } else if (it < old_it) {
        std::rotate(it, old_it, old_it + 1);
    }
}

Demo

std::rotate vs remove / insertion的优势是复制/移动的数量: 如果你只需要交换2个第一个元素,std::rotate只进行交换,而删除移位所有元素,并再次插入移动另一边的元素。