在排序之后找到未排序数组中元素位置的最佳方法

时间:2015-06-11 04:45:21

标签: c++ algorithm

我们有一个未排序的数组,需要打印每个元素的位置,假设它被排序。

例如:我们有一个数组。

arr[] = {3, 2, 6, 1, 4}
//index: 1  2  3  4  5  Index of elements 1-based

//Sorted {1, 2, 3, 4, 6}  List after sorting
//index:  4  2  1  5  3  Index of elements from original array

它应该打印

  

4 2 1 5 3

6 个答案:

答案 0 :(得分:6)

将数组{1, 2, 3, ..., N}与给定数组并行排序。因此,在您的示例中,{3, 2, 6, 4}将被排序,每个交换都会影响该数组和数组{1, 2, 3, 4}。对于第一个数组,最终结果为{2, 3, 4, 6},对于第二个数组,最终结果为{2, 1, 4, 3};后一个数组就是你问题的答案。

如果不清楚,这里有一个更长的例子:

5 2 1 4 3
1 2 3 4 5

2 5 1 4 3
2 1 3 4 5

2 1 5 4 3
2 3 1 4 5

2 1 4 5 3
2 3 4 1 5

2 1 4 3 5
2 3 4 5 1

2 1 3 4 5
2 3 5 4 1

1 2 3 4 5
3 2 5 4 1

我使用冒泡排序:-)对顶行进行排序,并将底行与顶行平行交换。但是这个想法应该适用于任何排序方法:只需与你在顶行执行的操作(交换或其他)并行操作底行。

答案 1 :(得分:4)

将数组元素的数据和索引存储为一对,并对数组进行排序。现在只打印索引部分。

// Original array
int arr[] = {3, 2, 6, 4};
// Size of original array
const int sz = static_cast<int>(sizeof arr / sizeof arr[0]);
// Array of pair {.first = item, .second = 1-based index
std::vector< pair<int, int> > vp(sz); // std::array if size is fixed
for(int i = 0; i < sz; ++i) vp[i] = make_pair(arr[i], i + 1);  /* Can be done in a more fancy way using std::transform + lambda */
// Sort the array, original array remains unchanged
std::sort(vp.begin(), vp.end());
// Print the result
for(int i = 0; i < sz; ++i) cout << ' ' << vp[i].second;

Live code

代码的时间复杂度: O(N log N)其中N是数组中元素的数量

由于N的值很大且所有数字都不同,因此您可以使用以下代码段

int maxn = maximum value of a number;
int positions[maxn] = {0};  // Or choose a sparse array with constant update time
int arr[] = {3, 2, 6, 4};
const int sz = static_cast<int>(sizeof arr / sizeof arr[0]);
for(int i = 0; i < sz; ++i) {
  assert( arr[i] >= 0 );
  position[ arr[i] ] = i + 1;
}

for(int i = 0; i < maxn; ++i) {
  if(position[i]) cout << ' ' << position[i];
}

Live code

代码的时间复杂度: O(N)其中N是数字的最大值

答案 2 :(得分:3)

您可以创建一个数组perm,其中包含第一个数组arr的索引,并根据perm arr数组进行排序>

int arr[] = {3, 2, 6, 4};

int compare (const void * a, const void * b) {
    int diff = arr[*(int*)a] - arr[*(int*)b];
    return  diff;
}

int main(void) {
    int perm[4], i;

    for (i = 0 ; i != 4 ; i++) {
        perm[i] = i ;
    }
    qsort (perm, 4, sizeof(int), compare);

    for (i = 0 ; i != 4 ; i++) {
        printf("%d ", perm[i] + 1);
    }
    return 0;
}

输出:

2 1 4 3

链接http://ideone.com/wH1giv

答案 3 :(得分:1)

我不知道这是否是最有效的方式,但我会创建一个array of nodes。每个node都有valuepos。然后,根据您可以检索位置的值进行排序。

struct node{
     int value;
     int pos;
}

正如我所说,它会奏效,但我怀疑这是最有效的方式

答案 4 :(得分:0)

我不懂C ++,所以我不能给你确切的代码,但下面的伪代码应该有用。

1. Given input array
2. Take another empty array of equal length (This will be the output array of positions)
3. Fill the output array with zero (initially all values will be zero in the array)
4. while (output array does not contain zero)
    a. loop through input array and find maximum number in it.
    b. get the position of maximum number from input array and set it at the same position in output array
    c. ignore the element in input array ,if corresponding index in output array is not zero (if it is not zero, then it means index is already filled up)
5. Repeat setps a,b and c until all the elements in output array becomes non zero

该算法的复杂性为O(n2)。我没有找到比这更好的方法。 如果您有任何疑问,请告诉我。

答案 5 :(得分:0)

您可以使用以下内容:

template <typename T>
std::vector<std::size_t> compute_ordered_indices(const std::vector<T>& v)
{
    std::vector<std::size_t> indices(v.size());
    std::iota(indices.begin(), indices.end(), 0u);
    std::sort(indices.begin(), indices.end(), [&](int lhs, int rhs) {
        return v[lhs] < v[rhs];
    });
    return indices;
}

Live Demo