如何快速从已排序的向量中获取已排序的子向量

时间:2010-11-29 22:52:11

标签: c++ sorting vector large-data

我有这样的数据结构:

struct X {
  float value;
  int id;
};

那些(大小 N (想想100000)的向量,按排序(在程序执行期间保持不变):

std::vector<X> values;

现在,我想写一个函数

void subvector(std::vector<X> const& values, 
               std::vector<int> const& ids, 
               std::vector<X>& out /*, 
               helper data here */);

使用的已排序子集填充 out 参数,由传递的 ID (大小 M >&lt; N (约0.8倍 N ),(内存不是问题,这将重复进行,因此构建lookuptables(来自函数参数的辅助数据)或其他只做一次的事情就完全可以了。)

到目前为止我的解决方案:
构建包含 id 的可查找表 lut - &gt; 中的偏移量(准备,因此恒定运行时间)
创建std::vector<X> tmp,大小为N,填充无效ID( N 中的线性)
对于每个ID,请将values[lut[id]]复制到tmp[lut[id]] M 中的线性) 循环遍历 tmp ,将项目复制到 out (线性在 N

这在 N 中是线性的(因为它大于 M ),但是临时变量和重复复制会让我感到困惑。有没有办法比这更快?请注意, M 将接近 N ,因此O( M log N )的内容不利。

编辑:http://ideone.com/xR8Vp是所提算法的一个示例实现,为了使所需的输出清晰并证明它在线性时间内是可行的 - 问题是关于避免临时变量或加速它的可能性换句话说,非线性的东西并不快:)。

3 个答案:

答案 0 :(得分:2)

您可以尝试的另一种方法是使用哈希表而不是向量来查找ID:

void subvector(std::vector<X> const& values, 
               std::unordered_set<int> const& ids, 
               std::vector<X>& out) {

    out.clear();
    out.reserve(ids.size());
    for(std::vector<X>::const_iterator i = values.begin(); i != values.end(); ++i) {
        if(ids.find(i->id) != ids.end()) {
            out.push_back(*i);
        }
    }
}

这是以线性时间运行的,因为unordered_set::find是恒定的预期时间(假设我们没有问题哈希值)。但是我怀疑它在实践中可能没有你最初使用矢量描述的方法那么快。

答案 1 :(得分:1)

由于您的向量已经排序,并且您希望它的子集以相同的方式排序,我假设我们可以在不重新排列的情况下切出所需的块。

为什么不只使用find_if()两次。一旦找到你想要的范围的开始,一次找到范围的结束。这将为您提供子向量的开始和结束迭代器。使用这些迭代器构造一个新的向量。其中一个向量constructor重载需要两个迭代器。

那个或partition算法应该有用。

答案 2 :(得分:0)

如果我理解你的问题,你实际上会尝试创建一个线性时间排序算法(取决于数字M的输入大小)。 那是不可能的。

您当前的方法是获得可能值的排序列表。 这需要线性时间到可能值N的数量(理论上,假设地图搜索花费O(1)时间)。

您可以做的最好的事情是使用快速排序方法(O(MlogM)fe quicksort,mergesort等)对值(您从地图中找到)进行排序,以获得较小的M值,并且可以对较大的值进行线性搜索M.的价值观 例如,如果N为100000且M为100,则使用排序算法要快得多。

我希望你能理解我说的话。如果您仍有疑问,我会尝试回答:)

编辑:(评论) 我会进一步解释我的意思。 假设您知道您的号码范围是1到100。 你把它们排序到某个地方(实际上它们是“自然”排序的)你想要以排序的形式得到它们的一个子集。 如果可以比O(N)或O(MlogM)更快地执行,则排序算法将仅使用此方法进行排序。

F.e。通过拥有一组数字{5,10,3,8,9,1,7},知道它们是有序数字集的子集{1,2,3,4,5,6,7,8 ,9,10}你仍然不能比O(N)(N = 10)或O(MlogM)(M = 7)更快地对它们进行排序。