stl unique使用(二)

本文介绍了一个使用C++处理文本文件并去除重复单词的例子。通过读取文件内容、随机分配ID给每个单词、排序及去重,最终输出不重复的单词列表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

注意:在使用unique()之前一定要对容器元素进行排序, 因为unique()只是去比较相邻元素间是否有重复的...

<think>我们讨论的是C++ STL中的`unique`函数。这个函数用于移除容器中相邻的重复元素(只保留一个),并返回一个迭代器指向新的逻辑结尾。 注意:它不会改变容器的实际大小,而是将不重复的元素移动到容器的前面部分,然后返回一个迭代器指向这个不重复序列的末尾。通常我们随后会调用容器的`erase`方法来删除从该迭代器到原容器结尾之间的元素。 函数原型(来自<algorithm>): ```cpp template< class ForwardIt > ForwardIt unique( ForwardIt first, ForwardIt last ); template< class ForwardIt, class BinaryPredicate > ForwardIt unique( ForwardIt first, ForwardIt last, BinaryPredicate p ); ``` 第一种形式使用`operator==`来比较元素,第种形式使用元谓词p来比较相邻元素。 使用步骤: 1. 通常,在调用`unique`之前,先对容器进行排序(因为`unique`只移除相邻的重复元素,所以排序后相同的元素会相邻)。 2. 调用`unique`,它会覆盖重复的元素,并返回一个迭代器,该迭代器指向最后一个不重复元素的下一个位置。 3. 使用容器的`erase`方法删除从返回的迭代器到容器末尾的所有元素。 示例:使用`unique`移除`vector<int>`中的重复元素。 代码: ```cpp #include <iostream> #include <vector> #include <algorithm> // for sort, unique int main() { std::vector<int> v = {1, 2, 1, 2, 3, 3, 2, 2, 1}; // 先排序 std::sort(v.begin(), v.end()); // 此时v: {1,1,1,2,2,2,2,3,3} // 调用unique,移除相邻重复元素 auto last = std::unique(v.begin(), v.end()); // 此时v: {1,2,3, ...},其中last指向第三个元素(即3)的下一个位置,后面的元素是未定义的(通常是被移走的元素) // 删除未定义的部分 v.erase(last, v.end()); // 输出结果 for (int i : v) { std::cout << i << ' '; } std::cout << '\n'; // 输出:1 2 3 return 0; } ``` 解释: 1. 首先,我们对vector进行排序,使得相同的元素相邻。 2. 然后调用`unique`,它会将不重复的元素(每个值保留一个)按顺序移动到容器的前面,并返回一个迭代器,指向不重复序列的末尾(即第一个被覆盖的元素位置)。 3. 我们使用`erase`方法删除从该迭代器到原容器末尾的所有元素,这样容器的大小就变为不重复元素的个数。 注意:`unique`不会删除任何元素,它只是覆盖重复的元素,并将不重复的元素集中到容器的前面。因此,我们必须使用`erase`来实际删除多余的元素。 另外,`unique`也可以用于未排序的容器,但那样只能移除相邻的重复元素,所以通常需要先排序。 如果我们不想改变元素的顺序,可以使用辅助容器(如set)来去重,但这样会消耗额外空间。而`unique`是原地操作,不需要额外空间。 第种形式:使用自定义的元谓词。例如,我们想忽略大小写比较字符串,或者自定义比较规则。 示例:使用自定义谓词,移除相邻的重复元素(这里我们定义两个整数的绝对值相等则视为重复,但实际上这个例子中我们移除相邻的绝对值相等的元素,注意:这个规则可能不满足传递性,所以排序时要小心,但这里我们只用于`unique`,它只比较相邻元素)。 注意:这个例子可能不够严谨,仅用于演示谓词的用法。 代码: ```cpp #include <iostream> #include <vector> #include <algorithm> #include <cmath> // for abs int main() { std::vector<int> v = {1, -1, 2, -2, 3, 3, -3, 4, 5}; // 排序:我们按照绝对值排序,这样绝对值相同的数会相邻 std::sort(v.begin(), v.end(), [](int a, int b) { return std::abs(a) < std::abs(b); }); // 使用unique,并指定比较相邻元素是否相等的谓词:这里我们比较绝对值是否相等 auto last = std::unique(v.begin(), v.end(), [](int a, int b) { return std::abs(a) == std::abs(b); }); v.erase(last, v.end()); for (int i : v) { std::cout << i << ' '; } // 输出可能是:1 2 3 4 5 (注意:输出的顺序是绝对值排序后的,但去重后每个绝对值只保留第一个出现的数?) // 实际上,排序后可能是:1, -1, 2, -2, 3, -3, 3, 4, 5 -> 然后unique会保留每组相邻重复元素的第一个,所以保留1,2,3,4,5(但注意,排序后第一个1是正数,然后-1被覆盖了,所以最后保留的是1?) // 具体输出:排序后序列为:1, -1, 2, -2, 3, 3, -3, 4, 5 -> unique后:1,2,3,4,5(因为unique会覆盖重复的,所以保留每组第一个) // 所以输出:1 2 3 4 5 return 0; } ``` 注意:在自定义谓词去重时,排序的规则和去重的规则需要一致,否则去重可能不彻底。 总结:`unique`是STL中一个非常有用的去重函数,但通常需要与`sort`和`erase`配合使用。 §§相关问题§§: 1. 如果不先排序,直接使用`unique`会有什么结果? 2. 除了`vector`,`unique`还可以用于哪些STL容器? 3. 如何保留重复元素的顺序(即不排序)同时去重? 4. 在C++中,除了`unique`,还有哪些方法可以用于去重?</think>### STL `unique` 接口使用方法详解 `std::unique` 是 C++ STL 中的算法,用于**移除相邻的重复元素**(只保留第一个出现的元素)。它通常需要先对容器排序,然后与 `erase` 结合实现完整去重。以下是详细使用方法和示例: #### 基本用法 ```cpp #include <algorithm> #include <vector> #include <iostream> int main() { std::vector<int> vec = {1, 2, 2, 3, 3, 3, 4, 4, 5}; // 1. 排序(非必须,但需确保相同元素相邻) std::sort(vec.begin(), vec.end()); // 2. 使用 unique 移除相邻重复 auto last = std::unique(vec.begin(), vec.end()); // 3. 删除尾部无效元素 vec.erase(last, vec.end()); // 输出结果: 1 2 3 4 5 for (int n : vec) std::cout << n << " "; } ``` #### 关键点解析 1. **返回值**: `last` 是一个迭代器,指向去重后新逻辑结尾的下一个位置。 2. **容器修改**: `unique` 不会减少容器大小,只是将不重复元素移到前面,需配合 `erase` 删除尾部。 3. **时间复杂度**: O(n),其中 n 是区间长度(每个元素只比较一次)。 --- #### 自定义比较规则 通过元谓词自定义相等性判断: ```cpp struct CaseInsensitive { bool operator()(char a, char b) { return std::tolower(a) == std::tolower(b); } }; int main() { std::vector<char> letters = {'A', 'a', 'B', 'b', 'C', 'c'}; auto last = std::unique(letters.begin(), letters.end(), CaseInsensitive()); letters.erase(last, letters.end()); // 结果: 'A' 'B' 'C'(忽略大小写去重) } ``` --- #### 常见错误修复 **错误:未排序直接去重** ```cpp std::vector<int> vec = {3, 1, 2, 1, 3}; std::unique(vec.begin(), vec.end()); // 错误!结果: 3,1,2,1,3(未去重) ``` **修复**:先排序 ```cpp std::sort(vec.begin(), vec.end()); // {1,1,2,3,3} std::unique(vec.begin(), vec.end()); // 正确去重 ``` --- #### 适用容器 `std::unique` 适用于: - 顺序容器:`vector`, `deque`, `list`(需配合 `list::unique` 成员函数) - 数组:原生数组指针 ```cpp int arr[] = {1,1,2,3}; int* end = std::unique(std::begin(arr), std::end(arr)); // 新有效范围: [begin, end) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值