C++ stl向量中的唯一值

C++ stl向量中的唯一值,c++,vector,C++,Vector,我有下面的代码来计算向量中的唯一值 bool uniqueCompressVectorCompareFunction (unsigned int num1, unsigned int num2) { return (num1 == num2); } // redirect input from stream to file. std::ifstream inputFile("testinput.txt"); std::streambuf* pcurrRdBuf = std::cin.rd

我有下面的代码来计算向量中的唯一值

bool uniqueCompressVectorCompareFunction (unsigned int num1, unsigned int num2) {
  return (num1 == num2);
}


// redirect input from stream to file.
std::ifstream inputFile("testinput.txt");
std::streambuf* pcurrRdBuf = std::cin.rdbuf();
std::cin.set_rdbuf(inputFile.rdbuf());

unsigned int uiNoOfFishes = 0;
std::cin >> uiNoOfFishes;
std::vector<unsigned int> vecOfLenOfFishes(uiNoOfFishes);
std::vector<unsigned int> vecOfTimeHeadOfFishes(uiNoOfFishes);

// get length of fishes
for(unsigned int uiIdx = 0; uiIdx < uiNoOfFishes; uiIdx++) {
    std::cin >> vecOfLenOfFishes[uiIdx];
}

// get time head of fishes
for(unsigned int uiIdx = 0; uiIdx < uiNoOfFishes; uiIdx++) {
    std::cin >> vecOfTimeHeadOfFishes[uiIdx];
}

std::cout << "Actual input length of fishes: " << std::endl;
for(unsigned int uiIdx = 0; uiIdx <vecOfLenOfFishes.size(); uiIdx++) {
    std::cout << vecOfLenOfFishes[uiIdx] << "   ";
}
std::cout << std::endl;

std::cout << "Actual input time head of fishes: " << std::endl;
for(unsigned int uiIdx = 0; uiIdx <vecOfTimeHeadOfFishes.size(); uiIdx++) {
    std::cout << vecOfTimeHeadOfFishes[uiIdx] << "   ";
}
std::cout << std::endl;


std::vector<unsigned int> vecUniqueInputValues;
// copy length of fishes.
unsigned int uiUniqueVecIdx = 0;
for(; uiUniqueVecIdx < uiNoOfFishes; uiUniqueVecIdx++) {
    vecUniqueInputValues.push_back(vecOfLenOfFishes[uiUniqueVecIdx]);
}

// copy time head of fishes.
for(unsigned int uiIdx = 0; uiIdx < uiNoOfFishes; uiIdx++, uiUniqueVecIdx++) {
    vecUniqueInputValues.push_back( vecOfTimeHeadOfFishes[uiIdx]);
}

// using predicate comparison:
std::unique (vecUniqueInputValues.begin(), vecUniqueInputValues.end(), uniqueCompressVectorCompareFunction); 



std::cout << "compressInputData unique values sorted: " << std::endl;
for(unsigned int uiIdx = 0; uiIdx <vecUniqueInputValues.size(); uiIdx++) {
    std::cout << vecUniqueInputValues[uiIdx] << "   ";
}
std::cout << std::endl;
输出如下所示

Actual input length of fishes:
2   4   4   2   4
Actual input time head of fishes:
1   4   1   6   4
compressInputData total values:
2   4   4   2   4   1   4   1   6   4
compressInputData unique values sorted:
2   4   2   4   1   4   1   6   4   4
我希望压缩输入的唯一值应该是 1 2 4 6

我的代码中有什么bug?

根据it

[e] 从每个连续的等效元素组中删除除第一个元素以外的所有元素

我的

因此,它不会删除所有重复出现的值,只删除相邻的值,例如将[1 2 3 3 3 1 3 2 2]减少到[1 2 3 1 3 2]

如果只希望保持整体唯一元素,则应首先对向量进行排序:

std::sort(vecUniqueInputValues.begin(), vecUniqueInputValues.end());

// Vector is now [1, 1, 2, 2, .., 2, 4, .., 4, 5, ... ]

std::unique (vecUniqueInputValues.begin(), vecUniqueInputValues.end(), 
  uniqueCompressVectorCompareFunction); 
一些小问题 比较函数似乎有点多余——如果您不指定它的话

[e] 使用运算符==比较元素

还请注意,std::unique实际上只对元素进行洗牌,以便所有唯一的连续元素都位于向量的开头-您仍然可以在输出的末尾两次看到值4。您应该获取std::unique的结果-它是一个迭代器,指向唯一范围的末尾:

auto endOfUniqueRange = std::unique(...);

std::cout << "compressInputData unique values sorted: " << std::endl;
for(auto& uiIt = vecUniqueInputValues.cbegin(); uiIt != endOfUniqueRange ; ++uiIt) {
    std::cout << *uiIt << "   ";
}
std::cout << std::endl;
或者,迭代整个向量

for(unsigned int val : myVec) { 
  // Do something with val
}
据it部门称

[e] 从每个连续的等效元素组中删除除第一个元素以外的所有元素

我的

因此,它不会删除所有重复出现的值,只删除相邻的值,例如将[1 2 3 3 3 1 3 2 2]减少到[1 2 3 1 3 2]

如果只希望保持整体唯一元素,则应首先对向量进行排序:

std::sort(vecUniqueInputValues.begin(), vecUniqueInputValues.end());

// Vector is now [1, 1, 2, 2, .., 2, 4, .., 4, 5, ... ]

std::unique (vecUniqueInputValues.begin(), vecUniqueInputValues.end(), 
  uniqueCompressVectorCompareFunction); 
一些小问题 比较函数似乎有点多余——如果您不指定它的话

[e] 使用运算符==比较元素

还请注意,std::unique实际上只对元素进行洗牌,以便所有唯一的连续元素都位于向量的开头-您仍然可以在输出的末尾两次看到值4。您应该获取std::unique的结果-它是一个迭代器,指向唯一范围的末尾:

auto endOfUniqueRange = std::unique(...);

std::cout << "compressInputData unique values sorted: " << std::endl;
for(auto& uiIt = vecUniqueInputValues.cbegin(); uiIt != endOfUniqueRange ; ++uiIt) {
    std::cout << *uiIt << "   ";
}
std::cout << std::endl;
或者,迭代整个向量

for(unsigned int val : myVec) { 
  // Do something with val
}
发件人:

unique从范围[first,last]中的每个连续的等效元素组中消除除第一个元素以外的所有元素,并为范围的新逻辑端返回一个结束迭代器

请参见单词Continuous,这意味着仅当向量已排序且重复顺序为连续时,才会删除重复项

在从以下位置调用std::unique之前对向量进行排序:

unique从范围[first,last]中的每个连续的等效元素组中消除除第一个元素以外的所有元素,并为范围的新逻辑端返回一个结束迭代器

请参见单词Continuous,这意味着仅当向量已排序且重复顺序为连续时,才会删除重复项


在调用std::unique之前对向量进行排序

,正如其他答案所指出的,std::unique会删除连续的重复项。这允许它成为单次传递算法

如果要在不更改其余元素顺序的情况下删除非连续的重复项,则必须编写不同的函数来执行此操作。这通常需要在输入范围内进行多次传递

下面是一个简单的实现,用于匹配std::unique的签名


正如其他答案所指出的,std::unique删除了连续的重复项,这使得它成为一个单遍算法

如果要在不更改其余元素顺序的情况下删除非连续的重复项,则必须编写不同的函数来执行此操作。这通常需要在输入范围内进行多次传递

下面是一个简单的实现,用于匹配std::unique的签名


您必须在std::unique之前对向量进行排序:请参见示例:否则,您可以使用std::unordered_集来保持唯一值这可能是因为您减少了实际代码,但是函数uniquecompressvectorcomarefunction永远不应该存在。相反,如果您实际上只执行了一个等式,请省略functor参数mparison。这里回答了一个类似的问题:你必须在std::unique之前对向量进行排序:参见示例:否则,你可以使用std::unordered_集来保持唯一值。这可能是因为你减少了实际代码,但函数uniquecompressvectorcomarefunction永远不应该存在。相反,只需省略该函数即可参数,如果您实际上只是执行相等比较。这里回答了一个类似的问题:您仍然可以在一次传递中执行此操作。例如,您可以将看到的所有元素添加到哈希集中。在扫描向量时,您可能会遇到集合中已存在的元素并将其删除,或者遇到尚未看到的元素:保留它并将其添加到集合中。不是O1,而是单次传递。@需要可复制值和额外分配的CompuChip您仍然可以在单次传递中完成。例如,您可以添加所有t
他将您看到的元素转换为散列集。扫描向量时,您可能会遇到集合中已存在的元素并将其删除,或者遇到尚未看到的元素:将其保留并添加到集合中。不是O1,而是需要可复制值和额外分配的单通芯片
template <typename ForwardIterator>
ForwardIterator multipass_unique(ForwardIterator first, ForwardIterator last)
{
    for (; first != last; ++first)
    {
        // Search the whole range for values that are equal to the current
        // Any values removed shorten the range to search
        last = std::remove(std::next(first), last, *first);
    }
    return last;
}
template <typename ForwardIterator, typename BinaryPredicate>
ForwardIterator multipass_unique(ForwardIterator first, ForwardIterator last, BinaryPredicate pred)
{
    for (; first != last; ++first)
    {
        // Search the whole range for values that satisfy the predicate
        // Any values removed shorten the range to search
        last = std::remove_if(std::next(first), last, [=](auto val){ return pred(*first, val); });
    }
    return last;
}