【问题标题】:Order a container by member with STL使用 STL 按成员订购容器
【发布时间】:2010-07-25 18:03:28
【问题描述】:

假设我有一些数据存储在unique_ptrs 的容器中:

struct MyData {
    int id;  // a unique id for this particular instance
    data some_data; // arbitrary additional data
};

// ...

std::vector<std::unique_ptr<MyData>> my_data_vec;

my_data_vec 的顺序很重要。假设现在我有另一个 MyDatas 的 ID 向量:

std::vector<int> my_data_ids;

我现在想重新排列my_data_vec,使元素按照my_data_ids 指定的顺序排列。 (不要忘记移动 unique_ptr 需要使用 std::move() 移动语义。)

实现这一点的算法效率最高的方法是什么,是否有任何 STL 算法能够很好地实现这一点?我看不出std::sort 有什么帮助。

编辑:我可以使用 O(n) 内存空间(不太担心内存),但 ID 是任意的(在我的具体情况下,它们实际上是随机生成的)。

【问题讨论】:

  • ids 是任意的,还是恰好是 0...n-1?
  • 编辑了问题以回答这些问题。

标签: c++ stl c++11 containers


【解决方案1】:
  1. 创建一个映射,将 ID 映射到它们在 my_data_ids 中的索引。
  2. 创建一个函数对象,该对象根据 std::unique_ptr&lt;MyData&gt; 在该映射中的 ID 索引进行比较。
  3. 使用std::sort 使用该函数对象对my_data_vec 进行排序。

这是一个草图:

// Beware, brain-compiled code ahead!
typedef std::vector<int> my_data_ids_type;
typedef std::map<int,my_data_ids_type::size_type> my_data_ids_map_type;

class my_id_comparator : public std::binary_function< bool
                                                    , std::unique_ptr<MyData>
                                                    , std::unique_ptr<MyData> > {
public:
  my_id_comparator(const my_data_ids_map_type& my_data_ids_map)
    : my_data_ids_map_(my_data_ids_map) {}

  bool operator()( const std::unique_ptr<MyData>& lhs
                 , const std::unique_ptr<MyData>& rhs ) const
  {
     my_data_ids_map_type::const_iterator it_lhs = my_data_ids_map_.find(lhs.id);
     my_data_ids_map_type::const_iterator it_rhs = my_data_ids_map_.find(rhs.id);
     if( it_lhs == my_data_ids_map_.end() || it_rhs == my_data_ids_map_.end() )
       throw "dammit!"; // whatever
     return it_lhs->second < it_rhs->second;
  }
private
  my_data_ids_map_type& my_data_ids_map_;
};

//...

my_data_ids_map_type my_data_ids_map;
// ...
// populate my_data_ids_map with the IDs and their indexes from my_data_ids
// ...
std::sort( my_data_vec.begin(), my_data_vec.end(), my_id_comparator(my_data_ids_map) );

如果内存不足,但时间并不重要,您可以取消映射并在 my_data_ids 向量中搜索 ID 以进行每次比较。但是,您必须真的非常渴望内存才能做到这一点,因为每次比较的两个线性复杂操作将非常昂贵。

【讨论】:

  • 这是一个非常好的解决方案,谢谢!不认为sort 会适用,但你证明我错了:)(顺便说一句,我使用的是 C++0x,所以我在排序中使用了 lambda - 让事情更整洁)
  • @James:我不确定在这个地方投掷std::exception 是否正确。问题的呈现方式似乎必须my_data_ids 中为每个ID 提供一个条目。如果是这样,那么这可能应该是一个断言,因为失败将表明先决条件不成立。由于我对这个问题知之甚少,所以我做了一些明显错误的事情并附上了该评论,希望很明显这需要更多考虑。但也许你是对的。 “照我说的做,而不是照我做的” 通常效果不佳。你有什么建议?
  • @sbi: 我只是开玩笑 :-) (然后我觉得这不好笑所以我删除了它)至于我的意见,在这种情况下,我倾向于抛出一个@ 987654330@ 或从中派生的东西。
  • @James:没有冒犯,但我总是对发布实际上错误的代码或做不应该做的事情保持警惕。正如我所说的“照我说的做,而不是照我做的”行不通,我从教学中知道这一点。
  • 我认为这个解决方案的时间复杂度可能比你想象的要高。每次比较都是 O(log n) 而不是 O(1),所以总时间是 O(n*(log n)^2) 而不是通常的 O(n*log(n))。这可能无关紧要,但如果确实如此,那么使用 std::unordered_map 而不是 std::map 会更好。
【解决方案2】:

您为什么不尝试将数据移动到 STL Set 中?您只需要实现比较功能,您将很快得到一组完美有序的数据。

【讨论】:

  • 好主意 - 但 my_data_vec 的顺序是重要且任意的。订购信息被一组丢失。
  • "为什么不尝试将数据移动到 STL 集中?"因为那样他们就不会按照my_data_ids指定的顺序。
【解决方案3】:

为什么不直接使用map&lt;int, unique_ptr&lt;MyData&gt;&gt;(或multimap)?

【讨论】:

    猜你喜欢
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    • 2017-07-14
    • 1970-01-01
    • 2020-05-02
    • 1970-01-01
    • 2017-06-04
    • 2013-04-20
    相关资源
    最近更新 更多