std :: sort,它还跟踪每个级别的唯一条目数

时间:2013-05-13 19:49:20

标签: c++ algorithm std

说我有一个std :: vector。说矢量包含数字。我们来看看这个std :: vector

1,3,5,4,3,4,5,1,6,3

std::sort<std::less<int>> will sort this into

1,1,3,3,3,4,4,5,5,6,

我如何修改排序,以便在排序的同时,它还计算同一级别的数量。所以说除了排序之外,它还会编译以下字典[level is int]

std::map<level, int>

<1, 2>
<2, 3>
<3, 2>
<4, 2>
<5, 1>
<6, 1>

所以有2个1个,3个3个,2个4个,依此类推。

我认为我需要这个的原因是因为我不想对矢量进行排序,然后再次计算每个级别的重复数量。在一次通过中这样做似乎更快?

谢谢大家! bjskishore123是我最接近的问题,但所有的反应都教育了我。再次感谢。

4 个答案:

答案 0 :(得分:1)

而不是使用矢量,

在逐个存储数字时,使用 std :: multiset 容器

它以排序顺序存储在内部。

在存储每个号码时,使用地图来跟踪每个号码的出现次数。

map<int, int> m;

每次添加数字都

m[num]++; 

因此,不需要另外的传递来计算出现次数,尽管你需要在map中迭代以获得每次出现次数。

=============================================== ==============================

以下是不推荐的替代解决方案。 当你提出使用STD :: SORT 的方式时给予它。

下面的代码使用比较函数来计算出现次数。

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;

struct Elem
{
    int index;
    int num;
};

std::map<int, int> countMap; //Count map
std::map<int, bool> visitedMap;
bool compare(Elem a, Elem b)
{
    if(visitedMap[a.index] == false)
    {
        visitedMap[a.index] = true;
        countMap[a.num]++;
    }
    if(visitedMap[b.index] == false)
    {
        visitedMap[b.index] = true;
        countMap[b.num]++;
    }
    return a.num < b.num;
}

int main()
{
    vector<Elem> v;
    Elem e[5] = {{0, 10}, {1, 20}, {2, 30}, {3, 10}, {4, 20} };
    for(size_t i = 0; i < 5; i++)
        v.push_back(e[i]);

    std::sort(v.begin(), v.end(), compare);

    for(map<int, int>::iterator it = countMap.begin(); it != countMap.end(); it++)
        cout<<"Element : "<<it->first<<" occurred "<<it->second<<" times"<<endl;
} 

<强>输出:

Element : 10 occurred 2 times
Element : 20 occurred 2 times
Element : 30 occurred 1 times

答案 1 :(得分:1)

如@ bjskishore123所述,您可以使用地图来保证集合的正确顺序。作为奖励,您将有一个优化的结构搜索(当然,地图)。

在地图中插入/搜索需要O(log(n))时间,而遍历向量需要O(n)。因此,alghorithm是O(n * log(n))。与任何需要比较元素的排序算法具有相同的复杂性:例如,合并排序或快速排序。

以下是您的示例代码:

int tmp[] = {5,5,5,5,5,5,2,2,2,2,7,7,7,7,1,1,1,1,6,6,6,2,2,2,8,8,8,5,5};
std::vector<int> values(tmp, tmp + sizeof(tmp) / sizeof(tmp[0]));
std::map<int, int> map_values;
for_each(values.begin(), values.end(), [&](int value)
{
    map_values[value]++;
});

for(std::map<int, int>::iterator it = map_values.begin();  it != map_values.end(); it++)
{
    std::cout << it->first << ": " << it->second << "times";
}

输出:

1: 4times
2: 7times
5: 8times
6: 3times
7: 4times
8: 3times

答案 2 :(得分:1)

我认为你不能一次性做到这一点。假设您提供自己的自定义comparator进行排序,以某种方式尝试计算重复项。

然而,您可以在分拣机中捕获的唯一内容是当前要比较的两个元素的值(可能参考但无关紧要 / strong>即可。您没有其他信息,因为std::sort没有将任何其他内容传递给分拣机。

现在std::sort的工作方式将继续交换元素,直到它们到达排序向量中的正确位置。这意味着单个成员可以多次发送到分拣机,从而无法准确计算。 您可以计算某个元素和所有其他元素的值等于已被移动的次数但不确切地知道它们中有多少个。

答案 3 :(得分:1)

如果您有大量重复项,完成此任务的最快方法可能是首先使用哈希映射(O(n)计算重复项,然后对地图进行排序,即O(m log m)其中m是唯一值的数量。

像这样(在c ++ 11中):

#include <algorithm>
#include <unordered_map>
#include <utility>
#include <vector>

std::vector<std::pair<int, int>> uniqsort(const std::vector<int>& v) {
  std::unordered_map<int, int> count;
  for (auto& val : v) ++count[val];
  std::vector<std::pair<int, int>> result(count.begin(), count.end());
  std::sort(result.begin(), result.end());
  return result;
}

主题有很多变化,具体取决于您的需求。例如,您甚至可能不需要对结果进行排序;也许只有计数地图就足够了。或者您可能希望结果是从int到int的有序映射,在这种情况下,您可以只构建常规std::map。 (那将是O(n log m)。)或者你可能知道一些值使它们更快排序的事情(比如它们是已知范围内的小整数。)等等。