c++ order range with values that doesn't fulfill strict weak ordering

时间:2018-09-19 08:22:40

标签: c++ algorithm

I need to order values in a range so the range represent a chain.

struct Link
{
   int id;
   int next;
};

The values of Link::id and Link::next are arbitrary, and do not provide any semantic meaning by them selves (not for the ordering algorithm any way).

The relationship between two links (after ordering) is: lhs.next is exactly rhs.id.

preconditions

  • The unordered range is guaranteed to hold values that can be ordered into exactly one chain.
  • It's guaranteed to be no recursion in the set of values (no loops)

Example:

std::vector< Link> range{ { 4, 1}, { 1, 5}, { 3, 4}, { 2, 3}};
auto chain = some_algorithm( range);
// expect the ordering to be: { { 2, 3}, { 3, 4}, { 4, 1}, { 1, 5}};

I can think of at least two approaches, but I suspect this has been solved in an idiomatic way. So, my question is: how to solve this in an idiomatic way?

3 个答案:

答案 0 :(得分:4)

I doubt that there is a idiomatic way because this isn't a common case.

Chaining is mostly done by pointers/iterators (e.g. std::list) and the actual chaining is mostly done while inserting.

The interesting thing would be to find the first link and what to do with circular chaining and with error cases.

答案 1 :(得分:0)

这是我想出的:

“概念” R是某种表现形式,类似于 range 的类型,可以是容器,也可以是其他类型。

如果range中有空格(链接方式),将对新链进行排序。我不想有一些“断言输出”或抛出。我仍然保持自己的目标,因为在用例中,我知道所有值都可以精确地形成一个链。

  template< typename R, typename ISP>
  R chain( R range, ISP is_link_predicate)
  {
     auto first = std::begin( range);
     auto current = first;
     const auto last = std::end( range);

     while( current != last)
     {
        const auto next = current + 1;

        // try to find a value in [next, last) that can be linked with *current.
        auto link = std::find_if( next, last, [current,is_link_predicate]( auto& value){
           return is_link_predicate( *current, value);
        });

        if( link != last)
        {
           using std::swap;
           swap( *next, *link);
           current = next;
        }
        else
        {
           // we need to check if some value in [next, last) can be "inserted" in the
           // beginning of the chain. That is, can form a link with *first.
           auto new_first = std::find_if( next, last, [first,is_link_predicate]( auto& value){
              return is_link_predicate( value, *first);
           });

           if( new_first != last)
           {
              // we got a new_first, we need to rotate it first
              //
              // C = current
              // N = next (not ordered).
              // - = ordered values
              // = = not ordered values
              // X = value to be "inserted" first, new_first
              //
              // -----CN====X===  we start with
              // X-----C========  we end up with
              //
              std::rotate( first, new_first, new_first + 1);
              current = next;
           }
           else
           {
              // no values in [next, last) is part of the current chain.
              // we start building the next chain.
              current = next;
              first = current;
           }
        }
     }

     return range;
  }

评论?

答案 2 :(得分:0)

首先,您要做的不是排序,因此请注意排序。您永远无法判断A是在B之前还是之后,您只能判断A可以在B之前精确地为1还是在A1..An之后精确地为1。因此,排序无法在这里为您提供帮助,甚至拓扑排序也无济于事。

一种算法:对链X进行回溯,搜索所有可以与其链接的元素A1..AnX,例如XA1..AnRewriteEngine On # If we receive a forwarded http request from a proxy... RewriteCond %{HTTP:X-Forwarded-Proto} =http [OR] # ...or just a plain old http request directly from the client RewriteCond %{HTTP:X-Forwarded-Proto} ="" RewriteCond %{HTTPS} !=on # Redirect to https version RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] ,然后对新链重复上述步骤。起始链是空链,任何元素都可以链接。