STL的unique接口使用方法
时间: 2025-07-19 21:31:10 浏览: 2
<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)
```
阅读全文
相关推荐

















