基于其他 int 数组的 C++ 排序

Posted

技术标签:

【中文标题】基于其他 int 数组的 C++ 排序【英文标题】:C++ Sort based on other int array 【发布时间】:2014-08-25 13:21:10 【问题描述】:

假设我有两个向量

std::vector<int>vec_int = 4,3,2,1,5;

std::vector<Obj*>vec_obj = obj1,obj2,obj3,obj4,obj5;

我们如何根据已排序的 vec_int 位置对 vec_o​​bj 进行排序? 所以目标可能是这样的:

std::vector<int>vec_int = 1,2,3,4,5;

std::vector<Obj*>vec_obj = obj4,obj3,obj2,obj1,obj5;

我一直在尝试创建新的 vec_array:

for (int i = 0; i < vec_int.size(); i++) 

    new_vec.push_back(vec_obj[vec_int[i]]);

但我认为这不是正确的解决方案。我们如何做到这一点?谢谢

std 库可能是最好的解决方案,但我找不到正确的解决方案来实现 std::sort

【问题讨论】:

我会创建一个std::map&lt; int, Obj* &gt; - 它的条目会自动按键排序。之后,您可以再次丢弃键并将值放回向量中。 edit 将此作为答案。 zip iterators 的可能重复项。 vec_int 是否总是包含索引的排列,或者它可能是 obj 的一些一般属性,在排序时用作键?您想就地执行排序吗? 在这个线程中有一个非常好的 lambda 解决方案 [***.com/questions/1577475/… [1]: ***.com/questions/1577475/… 不,我想推送所有元素,稍后再排序 【参考方案1】:

您不必致电std::sort,您需要的操作可以在线性时间内完成(前提是索引是从 1 到 N 并且不重复)

std::vector<Obj*> new_vec(vec_obj.size());
for (size_t i = 0; i < vec_int.size(); ++i) 
    new_vec[i] = vec_obj[vec_int[i] - 1];

当然,对于这个解决方案,您需要额外的 new_vec 向量。

如果索引是任意的和/或您不想分配另一个向量,则必须使用不同的数据结构:

typedef pair<int, Obj*> Item;
vector<Item> vec = 4, obj1, 3, obj2, 2, obj3, 1, obj4, 5, obj5;
std::sort(vec.begin(), vec.end(), [](const Item& l, const Item& r) -> bool return l.first < r.first;);

【讨论】:

【参考方案2】:

也许有更好的解决方案,但我个人会使用 std::map 中的项目自动按键排序的事实。这给出了以下可能性(未经测试!)

// The vectors have to be the same size for this to work!
if( vec_int.size() != vec_obj.size() )  return 0; 

std::vector<int>::const_iterator intIt = vec_int.cbegin();
std::vector<Obj*>::const_iterator objIt = vec_obj.cbegin();

// Create a temporary map
std::map< int, Obj* > sorted_objects;
for(; intIt != vec_int.cend(); ++intIt, ++objIt )

    sorted_objects[ *intIt ] = *objIt;


// Iterating through map will be in order of key
//  so this adds the items to the vector in the desired order.
std::vector<Obj*> vec_obj_sorted;
for( std::map< int, Obj* >::const_iterator sortedIt = sorted_objects.cbegin();
  sortedIt != sorted_objects.cend(); ++sortedIt )

  vec_obj_sorted.push_back( sortedIt->second );

【讨论】:

【参考方案3】:

[不确定这是否适合您的用例,但将元素放入地图将默认存储按键排序的元素。]

如果创建新向量是问题,您可以使用简单的交换技巧(如选择排序)来避免这种情况

//Place ith element in its place, while swapping to its position the current element.
for (int i = 0; i < vec_int.size(); i++) 
    if (vec_obj[i] != vec_obj[vec_int[i])
        swap_elements(i,vec_obj[i],vec_obj[vec_int[i]])

【讨论】:

【参考方案4】:

这种形式的一般形式称为“根据重新排序”,它是循环排序的一种变体。与您的示例不同,索引向量需要具有从 0 到 size-1 的值,而不是 4,3,2,1,5 它需要是 3,2,1,0,4 (否则您必须调整下面的示例代码)。重新排序是通过根据索引向量或数组中的“循环”旋转元素组来完成的。 (在我调整后的示例中,有 3 个“周期”,第一个周期:索引 [0] = 3,索引 [3] = 0。第二个周期:索引 [1] = 2,索引 [2] = 1。第三个周期索引 [ 4] = 4)。索引向量或数组也在该过程中进行排序。如果要保留原始索引向量或数组,可以保存原始索引向量或数组的副本。以模板形式根据 vI 重新排序 vA 的示例代码:

template <class T>
void reorder(vector<T>& vA, vector<size_t>& vI)  

size_t i, j, k;
T t;
    for(i = 0; i < vA.size(); i++)
        if(i != vI[i])
            t = vA[i];
            k = i;
            while(i != (j = vI[k]))
            // every move places a value in it's final location
                vA[k] = vA[j];
                vI[k] = k;
                k = j;
            
            vA[k] = t;
            vI[k] = k;
        
    

简单的仍然是根据vI将vA复制到另一个向量vB:

    for(i = 0; i < vA.size(); i++)
        vB[i] = vA[vI[i]];

【讨论】:

以上是关于基于其他 int 数组的 C++ 排序的主要内容,如果未能解决你的问题,请参考以下文章

内部排序算法总结(下)C++实现

C++声明一个基于非常量变量的数组?

如何在 Iphone SDK 中基于单个数组对多个数组进行排序

C++ 冒泡排序负数

c++排序二维数组编译失败

键/值数组的双调排序