Создание вектора индексов отсортированного вектора

Переменная x является вектором n ints, и я хочу отсортировать вектор в порядке возрастания. Однако по причинам, выходящим за рамки этого вопроса, я хочу, чтобы вектор оставался нетронутым. Поэтому вместо того, чтобы сортировать содержимое x, я хочу создать еще один вектор индексов n, где каждый индекс ссылается на соответствующее значение в x, если x должны были быть отсортированы.

Например:

std::vector<int> x = {15, 3, 0, 20};
std::vector<int> y;
// Put the sorted indices of x into the vector y
for (int i = 0; i < 4; i++)
{
    std::cout << y[i];
}

Должен выдавать результат:

2
1
0
3

Соответствует значениям в x:

0
3
15
20

Я могу думать о множестве своевременных способов реализации этого, но мне интересно, имеет ли STL что-то встроенное для эффективного выполнения этого для меня?

Ответ 1

1) Создайте y как вектор индекса (целочисленный диапазон)

2) Сортируйте этот диапазон с помощью компаратора, который возвращает элементы индексов из x Использование стандартной библиотеки, которая дает:

#include <iostream>
#include <vector>
#include <algorithm>

int main() {

    std::vector<int> x = {15, 3, 0, 20};

    std::vector<int> y;

    std::vector<int> y(x.size());
    std::size_t n(0);
    std::generate(std::begin(y), std::end(y), [&]{ return n++; });

    std::sort(  std::begin(y), 
                std::end(y),
                [&](int i1, int i2) { return x[i1] < x[i2]; } );

    for (auto v : y)
        std::cout << v << ' ';

    return 0;
}

Живая демонстрация.

Ответ 2

Заполните y всеми индексами x, затем используйте std::sort на y, но предоставите компаратор, который сравнивает соответствующие элементы в x:

  std::vector<int> y(x.size());
  std::iota(y.begin(), y.end(), 0);
  auto comparator = [&x](int a, int b){ return x[a] < x[b]; };
  std::sort(y.begin(), y.end(), comparator);

Ответ 3

Вы можете предоставить свой собственный компаратор, который проверяет значения целевого вектора при сортировке вектора индексов, а именно:

#include <vector>
#include <iostream>
#include <algorithm>

struct IdxCompare
{
    const std::vector<int>& target;

    IdxCompare(const std::vector<int>& target): target(target) {}

    bool operator()(int a, int b) const { return target[a] < target[b]; }
};

int main()
{
    std::vector<int> x = {15, 3, 0, 20};
    std::vector<int> y;

    // initialize indexes
    for(size_t i = 0; i < x.size(); ++i)
        y.push_back(i);

    std::sort(y.begin(), y.end(), IdxCompare(x));

    std::cout << "\nvector x: " << '\n';
    for(size_t i = 0; i < x.size(); ++i)
        std::cout << x[i] << '\n';

    std::cout << "\nvector y: " << '\n';
    for(size_t i = 0; i < x.size(); ++i)
        std::cout << y[i] << '\n';

    std::cout << "\nvector x through y: " << '\n';
    for(size_t i = 0; i < x.size(); ++i)
        std::cout << x[y[i]] << '\n';
}

ВЫВОД:

vector x: 
15
3
0
20

vector y: 
2
1
0
3

vector x through y: 
0
3
15
20

Ответ 4

Мы можем напрямую использовать подход "ссылаться" и использовать массив указателей на значения в исходном векторе.

#include <iostream>
#include <vector>
#include <algorithm>

int main(int argc, const char * argv[]) {
    //a source vector, who order shouldn't be changed
    std::vector<int> values = {15, 4, 20, 25, 0, 19, -5};
    //a vector of pointers to the values in the source vector
    std::vector<int *> pointersToValues;
    pointersToValues.reserve(values.size());

    for(auto& value : values){
        pointersToValues.push_back(&value);
    }

    //two comparators in form of lambda functions
    auto descendingOrderSorter = [](int * i, int * j){
        return *i > *j;
    };

    auto ascendingOrderSorter = [](int * i, int * j){
        return *i < *j;
    };

    //examples of usage
    std::cout<<"Sorting in a descending order"<<std::endl;
    std::sort( pointersToValues.begin(), pointersToValues.end(), descendingOrderSorter);
    for(int i = 0; i < pointersToValues.size(); ++i) {
        std::cout << "index: " << i << ", value: " << *pointersToValues[i] << std::endl;
    }

    std::cout<<"Sorting in an ascending order"<<std::endl;
    std::sort( pointersToValues.begin(), pointersToValues.end(), ascendingOrderSorter);
    for(int i = 0; i < pointersToValues.size(); ++i) {
        std::cout << "index: " << i << ", value: " << *pointersToValues[i] << std::endl;
    }

    return 0;
}

pointersToValues ​​[i] даст вам указатель на исходное значение, * pointersToValues ​​[i] даст вам значение.

Ответ 5

Вы можете сделать сортировку в другом списке, затем сравнить с несортированным списком, а затем третий список, в котором вы можете сохранить индексы i.e nlog(n) + n^2 или просто O(n^2)

Примечание: это псевдокод

vector<int> x = {15, 3, 0, 20};
vector<int> y = sort(x);
vector<in> z;
for(int i = 0; y < y.size(); i++){
   for(int j = 0; j < y.size(); j++){
      if(y[i] == x[j]){
         z.push_back(j);
      }
   }
}