每次修改排序的数组或对数组进行排序?

时间:2017-05-04 06:01:04

标签: c++ algorithm sorting stl

问题:给定大小为N的数组,使用连续元素打印大小为K的已排序子集。

N = 10, K = 4 
8 4 7 5 1 10 3 9 2 6
Output:
4 5 7 8, 1 4 5 7, 1 5 7 10, 1 3 5 10, ...

方法1:对所有子集进行排序并打印。

复杂性分析:

复制K个元素:O((N - K + 1)*(K))//子集的数量*子集的大小

排序子集:使用STL,对子集进行排序的最坏情况时间是O(K log K)。

因此,O((N - K + 1)*(K)+(N - K + 1)*(K log K))

方法2:从输出序列开始,连续的子集相差2个元素。因此,对于第二个子集,删除第一个元素并将第K + 1个元素插入到正确的位置。

复杂性分析:

创建第一个子集:K

删除并插入 - 线性搜索(这应该优化!):K

因此,O(K +(N-K + 1)*(K))

我想知道第二种方法是否更快?有显着的收益吗?是否值得不使用STL实现?这可以进一步改善吗?还有其他方法吗?以及对STL容器实施的任何建议。

3 个答案:

答案 0 :(得分:1)

是否允许重复?

如果不允许重复,请使用std::set,否则请使用std::multisetsetmultiset会一直对您的元素进行排序,每次插入都会在正确的有序位置进行。您不必担心何时对它们进行排序。

在插入过程中对所有内容进行排序实际上更便宜,因为当您必须搜索时,您不必与所有元素进行比较,而只需要与其中的一部分进行比较。

答案 1 :(得分:1)

使用std::multiset。这将简单而干净:

vector<int> v = input();
multiset<int> s;
for (int i = 0; i < k; ++i) {
    s.insert(v[i]);
}
print_set(s);

for (int i = 0; i < n-k; ++i) {
    s.erase(s.find(v[i]));
    s.insert(v[i+k]);

    cout << ",";
    print_set(s);
}

您可以尝试:http://ideone.com/moD3bg

使用multiset的所有操作的复杂性是O(nlogk)。但是请记住,打印所有这些数据的复杂性是O(n * k)。

答案 2 :(得分:0)

解决此问题的另一种方法是:

  int k=4;
  std::vector<int> v = {8,4,7,5,1,10,3,9,2,6};
  std::multiset<int> ss;
  for(auto itr=v.begin();itr<v.end();itr++)
  {
    size_t remaining(std::distance(itr+k, v.end())); 
    std::cout<<remaining<<std::endl;
    ss.insert(itr,itr+k);
    print_set(ss);
    if(remaining==0)
      break;
    ss.clear();
  }