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

C++ std::sort,它还跟踪每个级别的唯一条目数,c++,algorithm,std,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 std::sort将对其进行排序 1,1,3,3,4,4,5,5,6 我将如何进行排序,以便在排序的同时,它还计算同一级别上的数字数量。因此,除了排序之外,它还将编译以下字典[级别也是int] std::map<level, int>

假设我有一个std::vector。假设向量包含数字。让我们看一下这个std::vector

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

std::sort<std::less<int>> will sort this into
std::sort将对其进行排序
1,1,3,3,4,4,5,5,6

我将如何进行排序,以便在排序的同时,它还计算同一级别上的数字数量。因此,除了排序之外,它还将编译以下字典[级别也是int]

std::map<level, int>

<1, 2>
<2, 3>
<3, 2>
<4, 2>
<5, 1>
<6, 1>
std::map
所以有2个1,3个3,2个4,等等


我之所以需要它,是因为我不想对向量进行排序,然后再次计算每个级别的重复数。一次完成两项似乎更快


谢谢大家!!bjskishore123与我的要求最接近,但所有的回答都教育了我。再次感谢。

不用矢量

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

它在内部按排序顺序存储

存储每个数字时,请使用地图跟踪每个数字的出现次数

map<int, int> m;
因此,不需要另一个过程来计算出现次数,尽管您需要在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;
} 

而不是使用向量

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

它在内部按排序顺序存储

存储每个数字时,请使用地图跟踪每个数字的出现次数

map<int, int> m;
因此,不需要另一个过程来计算出现次数,尽管您需要在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;
} 

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

在映射中插入/搜索需要O(log(n))时间,而遍历向量需要O(n)时间。因此,算法是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";
}

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

在映射中插入/搜索需要O(log(n))时间,而遍历向量需要O(n)时间。因此,算法是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";
}

我认为你不可能一下子做到这一点。假设您提供了自己的自定义
比较器
,用于排序,它以某种方式尝试计数重复项

但是,您可以在分类器中捕获的唯一内容是当前正在比较的两个元素的值(可能是参考值,但不重要)。您没有其他信息,因为
std::sort
不会将任何其他信息传递给分拣机


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

我认为你不可能一下子做到这一点。假设您提供了自己的自定义
比较器
,用于排序,它以某种方式尝试计数重复项

但是,您可以在分类器中捕获的唯一内容是当前正在比较的两个元素的值(可能是参考值,但不重要)。您没有其他信息,因为
std::sort
不会将任何其他信息传递给分拣机


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

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

类似这样的内容(在c++11中):

#包括
#包括
#包括
#包括
标准::向量统一排序(常数标准::向量&v){
std::无序映射计数;
用于(自动&val:v)+计数[val];
向量结果(count.begin(),count.end());
排序(result.begin(),result.end());
返回结果;
}
这个主题有很多变化,具体取决于你需要什么。例如,您甚至不需要对结果进行排序;也许只要有计数图就足够了。或者,您可能希望结果是一个从int到int的排序映射,在这种情况下,您可以只构建一个常规的
std::map
。(那会
#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;
}