unique函数(先记下来)

本文深入探讨了C++ STL库中的unique和unique_copy算法,详细阐述了如何利用这些算法去除序列中的重复元素。通过实例演示,展示了在不同场景下使用unique和unique_copy实现高效数据去重的过程,包括排序前后的应用、不同容器类型间的转换及优化。重点强调了排序的必要性以及如何结合STL函数实现复杂数据结构的精准操作。

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

来源http://www.cnblogs.com/heyonggang/archive/2013/08/07/3243477.html

 一.unique函数

类属性算法unique的作用是从输入序列中“删除”所有相邻的重复元素

该算法删除相邻的重复元素,然后重新排列输入范围内的元素,并且返回一个迭代器(容器的长度没变,只是元素顺序改变了),表示无重复的值范围得结束。


// sort words alphabetically so we can find the duplicates 
sort(words.begin(), words.end()); 
     /* eliminate duplicate words: 
      * unique reorders words so that each word appears once in the 
      *    front portion of words and returns an iterator one past the 
unique range; 
      * erase uses a vector operation to remove the nonunique elements 
      */ 
 vector<string>::iterator end_unique =  unique(words.begin(), words.end()); 
 words.erase(end_unique, words.end());

在STL中unique函数是一个去重函数, unique的功能是去除相邻的重复元素(只保留一个),其实它并不真正把重复的元素删除,是把重复的元素移到后面去了,然后依然保存到了原数组中,然后 返回去重后最后一个元素的地址,因为unique去除的是相邻的重复元素,所以一般用之前都会要排一下序。

若调用sort后,vector的对象的元素按次序排列如下:

sort  jumps  over quick  red  red  slow  the  the turtle

则调用unique后,vector中存储的内容是:

 

 

 

 

 

 

注意,words的大小并没有改变,依然保存着10个元素;只是这些元素的顺序改变了。调用unique“删除”了相邻的重复值。给“删除”加上引号是因为unique实际上并没有删除任何元素,而是将无重复的元素复制到序列的前段,从而覆盖相邻的重复元素。unique返回的迭代器指向超出无重复的元素范围末端的下一个位置。

注意:算法不直接修改容器的大小。如果需要添加或删除元素,则必须使用容器操作。

example:

#include <iostream>
#include <cassert>
#include <algorithm>
#include <vector>
#include <string>
#include <iterator>
 using namespace std;

 int main()
{
    //cout<<"Illustrating the generic unique algorithm."<<endl;
    const int N=11;
    int array1[N]={1,2,0,3,3,0,7,7,7,0,8};
    vector<int> vector1;
    for (int i=0;i<N;++i)
        vector1.push_back(array1[i]);

    vector<int>::iterator new_end;
    new_end=unique(vector1.begin(),vector1.end());    //"删除"相邻的重复元素
    assert(vector1.size()==N);

    vector1.erase(new_end,vector1.end());  //删除(真正的删除)重复的元素
    copy(vector1.begin(),vector1.end(),ostream_iterator<int>(cout," "));
    cout<<endl;

    return 0;
}

运行结果为:

 

二、unique_copy函数

算法标准库定义了一个名为unique_copy的函数,其操作类似于unique。

唯一的区别在于:前者接受第三个迭代器实参,用于指定复制不重复元素的目标序列。

unique_copy根据字面意思就是去除重复元素再执行copy运算。

编写程序使用unique_copy将一个list对象中不重复的元素赋值到一个空的vector对象中。

//使用unique_copy算法
//将一个list对象中不重复的元素赋值到一个空的vector对象中
#include<iostream>
#include<list>
#include<vector>
#include<algorithm>
using namespace std;

int main()
{
    int ia[7] = {5 , 2 , 2 , 2 , 100 , 5 , 2};
    list<int> ilst(ia , ia + 7);
    vector<int> ivec;

    //将list对象ilst中不重复的元素复制到空的vector对象ivec中
    //sort(ilst.begin() , ilst.end());  //不能用此种排序,会报错
    ilst.sort();  //在进行复制之前要先排序,切记
    unique_copy(ilst.begin() , ilst.end() , back_inserter(ivec));

    //输出vector容器
    cout<<"vector: "<<endl;
    for(vector<int>::iterator iter = ivec.begin() ; iter != ivec.end() ; ++iter)
        cout<<*iter<<" ";
    cout<<endl;

    return 0;
}

假如

list<int> ilst(ia , ia + 7);
改为:vector<int> ilst(ia , ia + 7);

则排序时可用:

sort(ilst.begin() , ilst.end());

 这里要注意list和vector的排序用什么方法。

《Effective STL》里这些话可能有用处:
item 31
  
  “我们总结一下你的排序选择:
   ● 如果你需要在vector、string、deque或数组上进行完全排序,你可以使用sort或stable_sort。
   ● 如果你有一个vector、string、deque或数组,你只需要排序前n个元素,应该用partial_sort
   ● 如果你有一个vector、string、deque或数组,你需要鉴别出第n个元素或你需要鉴别出最前的n个元素,而不用知道它们的顺序,nth_element是你应该注意和调用的。
   ● 如果你需要把标准序列容器的元素或数组分隔为满足和不满足某个标准,你大概就要找partition或stable_partition。
   ● 如果你的数据是在list中,你可以直接使用partition和stable_partition,你可以使用list的sort来代替sort和stable_sort。如果你需要partial_sort或nth_element提供的效果,你就必须间接完成这个任务,但正如我在上面勾画的,会有很多选择。
  
  另外,你可以通过把数据放在标准关联容器中的方法以保持在任何时候东西都有序。你也可能会考虑标准非STL容器priority_queue,它也可以总是保持它的元素有序。





<think>好的,我现在需要回答用户关于`make_reference`函数的使用说明或实现细节的问题。首先,我要确认用户提到的`make_reference`是否是标准库中的某个函数。根据我的知识,C++标准库中并没有名为`make_reference`的函数,常见的类似名称的有`std::make_shared`、`std::make_unique`,以及可能涉及引用的其他模板函数,比如`std::ref`。因此,用户可能混淆了函数名称,或者指的是某个特定库或框架中的自定义函数。 接下来,我需要考虑可能的误解方向。用户可能在寻找创建引用包装器的方法,类似`std::ref`,或者是希望将对象转换为引用类型。另外,也有可能用户误将`std::make_shared`或`std::make_unique`记成了`make_reference`。为了覆盖这些可能性,我应该解释标准库中相关的引用包装器,并指出标准库中没有`make_reference`,但可以指导如何实现类似功能的函数。 另外,用户提供的引用内容中提到了`std::forward`和`unique_ptr`,这可能与完美转发或智能指针相关,但需要确认这些引用是否与`make_reference`有关联。比如,`std::forward`用于完美转发,而`unique_ptr`用于管理指针,但用户的问题是关于引用的创建,所以可能需要结合这些知识来解释如何正确使用引用或转发引用。 然后,我需要构造一个合理的回答结构,首先指出标准库中没有`make_reference`,然后解释可能的替代方案,比如`std::ref`,或者如何手动创建引用包装器。同时,可能需要提到模板编程中引用的处理,比如使用`std::add_reference`类型特征,或者通过完美转发来保持引用类型。 在实现细节部分,如果需要自定义`make_reference`函数,可能需要展示一个模板函数,返回对象的引用,并注意引用折叠和完美转发的规则。例如: template<typename T> constexpr T&& make_reference(T&& t) noexcept { return std::forward<T>(t); } 不过,这样的函数可能并不实用,因为直接传递引用即可,或者用户可能需要的是包装引用的工具,比如`std::reference_wrapper`,这时可以提到`std::ref`和`std::cref`的使用。 最后,需要确保回答准确,避免误导用户,同时提供足够的信息帮助用户理解相关的概念,如引用包装器、完美转发、类型推导等,并生成相关问题以引导进一步学习。</think>关于`make_reference`函数,目前C++标准库中并未直接提供该函数。根据您提供的引用内容和常见用法,可能涉及以下两种解释方向: ### 1. 可能的误解:与引用包装器相关 标准库中与引用相关的工具是`std::reference_wrapper`,可通过`std::ref`和`std::cref`函数创建: ```cpp #include <functional> int main() { int value = 42; auto ref = std::ref(value); // 生成可复制的引用包装器 ref.get() = 100; // 修改原值 } ``` 此处的`std::ref`返回一个可存储、可复制的引用包装对象,常用于模板编程中传递引用语义[^1]。 ### 2. 自定义实现参考 若需实现类似`make_reference`的功能(例如返回参数的引用),可结合完美转发: ```cpp template<typename T> constexpr decltype(auto) make_reference(T&& t) noexcept { return std::forward<T>(t); // 保持值类别(左值/右值) } ``` 此模板会根据输入参数的类型(左值或右值)返回对应的引用类型,利用引用折叠规则保留原始类型特性[^1]。 ### 3. 与智能指针的对比 标准库中`std::make_unique`和`std::make_shared`用于创建智能指针对象,与引用无直接关联,但体现了工厂函数的设计模式: ```cpp auto ptr = std::make_unique<int>(10); // 创建unique_ptr if (ptr) { /* 检查非空 */ } // 通过operator bool判断有效性[^2] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值