set 获取元素的位置

Posted

技术标签:

【中文标题】set 获取元素的位置【英文标题】:set get position of an element 【发布时间】:2013-08-10 12:44:54 【问题描述】:

我想解决以下问题:给定一个包含 n 个元素的向量,找出插入排序算法需要排序的交换次数。

例如: n = 5 2 1 3 1 2 答案:4

解释(插入排序算法的逐步说明): 初始:2 1 3 1 2 1 2 3 1 2 ; 1 交换 1(1 向左) 1 2 3 1 2 ; 0 次交换 1 1 2 3 2 ; 2 交换(1 左 2 位) 1 1 2 2 3 ; 1 交换(2 去 1 位左)

我的解决方案

我将每个项目的位置保留在初始数组中,以便稍后根据值和位置从集合中删除。(第一个 for 循环) 然后我计算小于当前数字的元素的数量,将它们添加到计数器并从集合中删除该元素。 (第二个 for 循环)

如您所见,问题在于 std::distance 具有 linear complexity 原因集具有双向迭代器。如何在不必实现自己的树的情况下获得 O(1) 复杂度?

int count_operations(vector<int> &v)

    set<pair<int, int>> s;
    // O(N * logN)
    for(int i = 0; i < (int) v.size(); ++i)
    
        s.insert(make_pair(v[i], i));
    
    int cnt = 0;
    // desired: O(N * log N) ; current O(N^2)
    for(int i = 0; i < (int) v.size(); ++i)
    
        auto item = make_pair(v[i], i);
        auto it = s.find(item);
        int dist = distance(s.begin(), it);//O(N); I want O(1)
        s.erase(it);
        cnt += dist;
    
    return cnt;

【问题讨论】:

我不知道如何在不扩展树结构来存储额外数据的情况下修改距离计算,但是我可以给你另一种解决方案来计算插入排序期间的交换次数,你写是吗? 你为什么要构建set 看起来您需要一个平衡树,其中每个节点都跟踪其子树的大小。 std::set 实现使用的树结构没有。毕竟,恐怕你得自己动手了。 @pkacprzak,当然,这也是我发布问题的原因。我还没有找到比 O(NlogN) 更好的解决方案 @Igor。这就是我想要避免的。 set 是最接近红黑树实现的。 【参考方案1】:

问题是获取集合中每个元素的排名,这可以通过顺序统计树(使用 gnu libc++ 中的 pbds 库)来完成,如下所示。

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <vector>
#include <utility>
using namespace std;
using namespace __gnu_pbds;

typedef tree<
    pair<int, int>, /* key type */
    null_mapped_type, /* value type */
    less< pair<int, int> >, /* comparison */
    rb_tree_tag, /* for having an rb tree */
    tree_order_statistics_node_update> order_set;

int count_ops(std::vector<int> &v)

    order_set s;
    int cnt = 0;
    /* O(N*log(N)) */
    for(int i = 0; i < v.size(); i++)
        s.insert(pair<int, int>(v[i], i));
    for(int i = 0; i < v.size(); i++)
    
        /* finding rank is O(log(N)), so overall complexity is O(N*log(N)) */
        cnt += s.order_of_key(pair<int, int>(v[i], i));
        s.erase(pair<int, int>(v[i], i));
    
    return cnt;

【讨论】:

很有趣,从来不知道这个库,但是我在环境中无法访问这个库。我最终自己实现了这棵树,并想知道是否有一种方法可以仅使用 std 算法和容器来解决问题。 嗯,PBDS 库确实是一个模板。因此,您可以下载所有相关文件并直接在您的应用程序中使用它们,而无需额外的库。这些文件将成为 GNU libstdc++ 版本的一部分。 它有效。与我的自定义实现相比,它在没有优化标志的情况下表现更差。但是当 -O2 处于活动状态时,它会变得非常接近。为什么对pb_ds知之甚少?它比 stl 更具可配置性。

以上是关于set 获取元素的位置的主要内容,如果未能解决你的问题,请参考以下文章

Java—集合框架Set

List集合和set集合

Java类集 1 List, Set基本使用

如何获取 List 或 Set 的第一个元素? [复制]

java容器 Set

如何获取jQuery集合的某一项