使用c ++中的公共/重复元素对向量进行分组和排序

时间:2018-03-19 09:07:32

标签: c++ c++11 vector stl

假设我有一个矢量如下

std::vector<int> v = {3, 9, 7, 7, 2};

我想对这个元素向量进行排序,以便将向量存储为77932.首先,我们存储公共元素(7),然后我们将其余元素从最高到最低排序。

如果我有一个矢量如下

std::vector<int> v = {3, 7, 7, 7, 2};

在这里,它将导致77732.

相同
std::vector<int> v = {7, 9, 2, 7, 9};

它应该导致99772,因为9s高于7s。

最后一个例子

std::vector<int> v = {7, 9, 7, 7, 9};

它应该导致77799,因为7s比9s多。

实现此目的的最快算法是什么?

5 个答案:

答案 0 :(得分:5)

使用std::multiset为您计算。然后使用简单的自定义比较器进行排序,使用std::tie实现的打破平局逻辑:

std::vector<int> data = {7, 9, 2, 7, 9};
std::multiset<int> count(data.begin(), data.end());
std::sort(
    data.begin()
,   data.end()
,   [&](int a, int b) {
        int ca = count.count(a);
        int cb = count.count(b);
        return std::tie(ca, a) > std::tie(cb, b);
    }
);
std::copy(data.begin(), data.end(), std::ostream_iterator<int>(std::cout, " "));

Demo 1

编辑: count(n) std::multiset的函数在重复数量上是线性的,这可能会降低排序算法的性能。您可以在其位置使用std::unordered_map来解决此问题:

std::vector<int> data = {7, 9, 2, 7, 9};
std::unordered_map<int,int> count;
for (auto v : data)
    count[v]++;
std::sort(
    data.begin()
,   data.end()
,   [&](int a, int b) {
        return std::tie(count[a], a) > std::tie(count[b], b);
    }
);
std::copy(data.begin(), data.end(), std::ostream_iterator<int>(std::cout, " "));

Demo 2.

答案 1 :(得分:1)

你需要一个辅助频率计数结构,然后你可以定义一个比较器lambda并使用你喜欢的任何类型,std::sort是一个合理的默认值

std::unordered_map<int, size_t> frequency;
std::for_each(v.begin(), v.end()
            , [&](int i) { ++frequency[i]; });
std::sort(v.begin(), v.end()
        , [&](int lhs, int rhs)
          { 
            return std::tie(frequency[lhs], lhs) < std::tie(frequency[rhs], rhs);
          }); 

答案 2 :(得分:0)

如果候选人为这项任务提出了辅助地图,我不会感到满意 - 很明显,这种工作的大部分工作,辅助结构应该是一个载体(或者,在我实际尝试之后)实现它,2个向量):

void custom_sort(vector<int> &v)
{
if (v.size() < 2)
    return;

sort(v.begin(), v.end(), std::greater<int>());

vector<int> dupl;
vector<int> singl;
int d;
bool dv = false;
for (int i = 1; i < v.size(); ++i)
{
    if (!dv)
    {
        if (v[i - 1] == v[i])
        {
            d = v[i];
            dv = true;
            dupl.push_back(d);
        }
        else
        {
            singl.push_back(v[i - 1]);
        }
    }
    else
    {
        dupl.push_back(d);
        if (v[i] != d)
            dv = false;
    }
}

if (!dv)
    singl.push_back(v.back());
else
    dupl.push_back(d);

auto mid = copy(dupl.begin(), dupl.end(), v.begin());
copy(singl.begin(), singl.end(), mid);
}

但是,是的,分支是棘手的 - 如果你想将它用于更多的inverview,请测试它...: - )

答案 3 :(得分:0)

编辑这回答了该问题的早期版本。

如果元素是小整数,即范围有限,我们可以扩展counting sort算法(因为这里的键是元素,我们不需要单独建立起始位置)。

$row['30']

答案 4 :(得分:0)

有O(N Log(N))算法和额外的O(N)存储器。

Random r = new Random();
int[] array = IntStream.generate(() -> r.nextInt(100)).limit(1000).toArray();
long odd = 0;
long even = 0;
long divisibleBy3 = 0;
long start = System.nanoTime();
//for (int i: array) {
//    if (i % 2 == 1) {
//        odd++;
//    }
//    if (i % 2 == 0) {
//       even++;
//    }
//    if (i % 3 == 0) {
//        divisibleBy3++;
//    }
//}
even = Arrays.stream(array).parallel().filter(x -> x % 2 == 0).toArray().length;
odd = Arrays.stream(array).parallel().filter(x -> x % 2 == 1).toArray().length;
divisibleBy3 = Arrays.stream(array).parallel().filter(x -> x % 3 == 0).toArray().length;
System.out.println(System.nanoTime() - start);