【问题标题】:How can I get relative index of std::set?如何获得 std::set 的相对索引?
【发布时间】:2017-10-13 13:29:00
【问题描述】:

我最近遇到了一个问题。我想获取std::set 元素的相对索引。例如,如果std::set 存储{1, 2, 4, 6, 9, 15},我想找到元素{4} 并有效地获取它的相对索引{2}。当然,我可以写std::distance(myset.begin(), myiterator),但是这个操作的复杂度是O(n*logn)。如果我可以访问std::set 的真正红黑树,我会运行rb_tree_node_pos(见下文),即O(logn)。这正是相对索引。有谁知道我怎样才能得到真正的树? 下面是代码示例:

#include <iostream>
#include <set>
using namespace std ;
int rb_tree_node_pos(rb_tree_node *node) {
  //function that finds relative index of tree node
  if (node->parent==NULL) return rb_tree_size(node->left) ;
  else return rb_tree_node_pos(node->parent)+rb_tree_size(node->left)+1 ;_
}
int main () {
  set<int> myset ;
  //... reading some data in myset
  int find_int ;
  cin >> find_int ;
  set<int>::iterator myit=myset.find(find_int) ;
  int find_index=distance(myset.begin(), myit) ; // O(n*log(n)), to slow!!!
  find_index=rb_tree_node_pos(myit->get_rb_tree()) ; // that's O(logn)
  cout << find_index << endl ;
  return 0 ;
}

一般来说,我希望数据结构能够维护以下操作:1. 插入元素,2. 删除元素,3. 打印出元素的相对索引。我认为有一种方法可以从 STL 中“挖掘”它。

【问题讨论】:

  • 最好使用排序数组和二分查找。
  • 但是如何在有序数组中有效地插入一些东西?
  • 请注意,红黑树是一个实现细节,这意味着您的 std::set 甚至可能不会被实现为红黑树。这个问题闻起来像 XY 问题。您真正想要解决的问题是什么?
  • 可以在不维护每个节点的子树大小的情况下实现红黑树,因此使用“真正的”rb-tree 可以做的最好的事情是 O(n)。
  • 真正的问题:“我想要的数据结构将保持以下操作:1.插入元素,2.删除元素,3.打印出元素的相对索引”。我不想自己写吧。

标签: c++ stl set binary-tree red-black-tree


【解决方案1】:

感谢@Fanael,他找到了解决方案!我们可以使用 GNU Policy Based Data Structures (PBDS) 来实现这个数据结构。下面是代码示例:

#include <iostream>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

using namespace std;
using namespace __gnu_pbds;

typedef
tree<
  int,
  null_type,
  less<int>,
  rb_tree_tag,
  tree_order_statistics_node_update>
ordered_set;

int main()
{
  ordered_set myset;
  //....reading some data to myset
  int find_int ;
  cin >> find_int ;
  find_index=myset.order_of_key(find_int) ;
  cout << find_index << endl ;
  return 0;
}

您可以通过herehere 了解有关 GNU PBDS 的更多信息。感谢所有帮助过的人!

【讨论】:

    【解决方案2】:

    如果你使用std::set,你可以找到具有线性复杂度的元素的索引:

    int Search (const std::set<int>& a, int value)
    {
        int c=0;
        for(auto&& i: a)
        {
            if(i==value) return c;
            ++c;
        }
        return -1;
    }
    
    int main()
    {
        std::set <int> a{1, 2, 4, 6, 9, 15};
        std::cout << Search(a,4) << std::endl;
    }
    

    但是如果使用排序数组和二分查找,复杂度会是O(log(n))。

    int Binary_search (const std::vector<int>& a, int value)
    {
        int l=0;
        int r=a.size()-1;
        while(l<=r)
        {
            int m=(l+r+1)/2;
            if(a[m]==value) return m;
            else if(a[m]>value) r=m-1;
            else l=m+1;
        }
        return -1;
    }
    
    int main()
    {
        std::vector <int> a{1, 2, 4, 6, 9, 15};
        std::cout << Binary_search(a,4) << std::endl;
    }
    

    【讨论】:

    • 但是我不能有效地在有序数组中插入元素。
    猜你喜欢
    • 2020-05-11
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    相关资源
    最近更新 更多