C++ 关于unique的用法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 关于unique的用法相关的知识,希望对你有一定的参考价值。
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <list>
using namespace std;
bool same_elements(vector<int>a, vector<int> b)
sort(a.begin(),a.end());
sort(b.begin(),b.end());
return a == b;
void remove_duplicates(vector<int> a)
sort(a.begin(), a.end());
a.unique(); // 问题在这里, 用下面的方法就可以 问什么呢
// vector<int>::iterator it = unique(a.begin(), a.end());
// a.erase(it, a.end());
int main()
int a[9] = 1,4,9,16,9,7,4,9,11;
int b[9] = 11,1,4,9,16,9,7,4,9;
vector<int> va(a, a+9); // create vector va from array a
vector<int> vb(b, b+9); // create vector vb from array b
// check whether va and vb have same elements
cout << "The vectors va and vb have ";
if (!same_elements(va, vb)) cout << "not ";
cout << "the same elements.\n";
// remove duplicate elements from va
remove_duplicates(va);
copy(va.begin(), va.end(), ostream_iterator<int> (cout, " "));
system("pause");
return 0;
还有 请问unique 会返回什么值?
一.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
注意,words的大小并没有改变,依然保存着10个元素;只是这些元素的顺序改变了。调用unique“删除”了相邻的重复值。给“删除”加上引号是因为unique实际上并没有删除任何元素,而是将无重复的元素复制到序列的前段,从而覆盖相邻的重复元素。unique返回的迭代器指向超出无重复的元素范围末端的下一个位置。
注意:算法不直接修改容器的大小。如果需要添加或删除元素,则必须使用容器操作。
example:
#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对象中。
//将一个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;
参考技术A 一.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
注意,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;
参考技术B 看一看介绍STL的书
❥关于C++之stringstream典型用法
typedef basic_stringstream<char> stringstream;
类描述:
流类对字符串进行操作。
此类的对象使用包含字符序列的字符串缓冲区。可以使用成员str 作为string对象直接访问此字符序列。
可以使用输入和输出流上允许的任何操作来插入和/或从流中提取字符。
一个典型使用示例:
下面图片展示的是一个3D模型的OBJ格式的文件内容:
蓝色v 开头的是三角形顶点坐标(x, y, z);
红色vt 开头的是所有顶点的纹理坐标(纹理坐标列表比顶点列表长的原因是一些顶点参与多个三角形,并且在这些情况下可能使用不同的纹理坐标);
绿色vn 开头的是顶点法向量(该列表通常也比顶点列表长,尽管在该示例中不是这样,同样是因为一些顶点参与多个三角形,并且在那些情况下可能使用不同的法向量);
紫色f 开头的是面。
[面]格式表示的含义:
格式:f 顶点1/纹理1/法向量1 顶点2/纹理2/法向量2 顶点3/纹理3/法向量3,
其中:顶点1(纹理1,法向量1) — 顶点2(纹理2,法向量2) — 顶点3(纹理3,法向量3) 构成一个三角形。
现在编写程序,解析出OBJ文件中所有的顶点、顶点的纹理坐标、顶点的法向量,分类存储,以便可以用OpenGL程序绘制这个3D模型。
// parser.h
#ifndef PARSER_H_
#define PARSER_H_
#include <vector>
class ModelParser
private:
std::vector<float> vVals;// 所有单个的[顶点坐标]值
std::vector<float> vtVals;// 所有单个的[纹理坐标]值
std::vector<float> vnVals;// 所有单个的[法向量]值
std::vector<float> triangleVerts;// #三角形#数据
std::vector<float> textureCoords;// #纹理坐标#数据
std::vector<float> normals;// #法向量#数据
public:
void parseOBJ(const char* filePath);
int getNumVertices();
std::vector<float> getVertices();
std::vector<float> getTextureCoordinates();
std::vector<float> getNormals();
#endif
#include <fstream>
#include <stringstream>
#include <string>// std::string, std::stoi
#include "parser.h"
using namespace std;
void ModelParser::parseOBJ(const char* filePath)
float x, y, z;
string content;
ifstream fileStream(filePath, ios::in);
string line = "";
while (!fileStream.eof())
getline(fileStream, line);
if (line.compare(0, 2, "v ") == 0)
stringstream ss(line.erase(0, 1));
ss >> x; ss >> y; ss >> z;
vVals.push_back(x);
vVals.push_back(y);
vVals.push_back(z);
if (line.compare(0, 2, "vt") == 0)
stringstream ss(line.erase(0, 2));
ss >> x; ss >> y;
vtVals.push_back(x);
vtVals.push_back(y);
if (line.compare(0, 2, "vn") == 0)
stringstream ss(line.erase(0, 2));
ss >> x; ss >> y; ss >> z;
vnVals.push_back(x);
vnVals.push_back(y);
vnVals.push_back(z);
if (line.compare(0, 2, "f ") == 0)
string oneData, v, vt, vn;
stringstream ss(line.erase(0, 2));
for (int i = 0; i < 3; i++)
getline(ss, oneData, ' ');
stringstream oneDataS(oneData);
getline(oneDataS, v, '/');
getline(oneDataS, vt, '/');
getline(oneDataS, vn, '/');
int vertIndex = (stoi(v) - 1) * 3;
int textureIndex = (stoi(vt) - 1) * 2;
int normalIndex = (stoi(vn) - 1) * 3;
triangleVerts.push_back(vVals[vertIndex]);
triangleVerts.push_back(vVals[vertIndex + 1]);
triangleVerts.push_back(vVals[vertIndex + 2]);
textureCoords.push_back(vtVals[textureIndex]);
textureCoords.push_back(vtVals[textureIndex + 1]);
normals.push_back(vnVals[normalIndex]);
normals.push_back(vnVals[normalIndex + 1]);
normals.push_back(vnVals[normalIndex + 2]);
int ModelParser::getNumVertices() return (triangleVerts.size() / 3);
vector<float> ModelParser::getVertices() return triangleVerts;
vector<float> ModelParser::getTextureCoordinates() return textureCoords;
vector<float> ModelParser::getNormals() return normals;
本文不涉及OpenGL,下面用纯C++,给OpenGL编程做好数据准备:
// encapsulation.h
#include <vector>
#include <glm\\glm.hpp>// glm::vec2、glm::vec3
using namespace std;
class EncapModel
private:
int numVertices;
vector<glm::vec3> vertices;
vector<glm::vec2> texCoords;
vector<glm::vec3> normalVecs;
public:
ImportedModel()
ImportedModel(const char *filePath);
int getNumVertices();
vector<glm::vec3> getVertices();
vector<glm::vec2> getTextureCoords();
vector<glm::vec3> getNormals();
;
#include <glm\\glm.hpp>
#include "imported.h"
using namespace std;
EncapModel::EncapModel(const char *filePath)
ModelParser modelParser = ModelParser();
modelParser.parseOBJ(filePath);
numVertices = modelParser.getNumVertices();
std::vector<float> verts = modelParser.getVertices();
std::vector<float> tcs = modelParser.getTextureCoordinates();
std::vector<float> normals = modelParser.getNormals();
for (int i = 0; i < numVertices; i++)
vertices.push_back(glm::vec3(verts[i*3], verts[i*3+1], verts[i*3+2]));
texCoords.push_back(glm::vec2(tcs[i*2], tcs[i*2+1]));
normalVecs.push_back(glm::vec3(normals[i*3], normals[i*3+1], normals[i*3+2]));
int EncapModel::getNumVertices() return numVertices;
vector<glm::vec3> EncapModel::getVertices() return vertices;
vector<glm::vec2> EncapModel::getTextureCoords() return texCoords;
vector<glm::vec3> EncapModel::getNormals() return normalVecs;
至此,封装完成,可以直接获所有顶点的三维(vec3)坐标数据、所有顶点的二维(vec2)纹理坐标数据、所有顶点的三维(vec3)法向量数据。第个顶点vec3(x,y,z)都对应有一个纹理坐标vec(s,t)和一个法向量vec3(nx,ny,nz)。解析、封装完毕!
示例中一些成员函数分析:
#include <string>// getline、stoi
✎[v 1.000000 -1.000000 -1.000000]
line.compare(0, 2, "v ")
line.erase(0, 1)
✎[f 2/1/1 3/2/1 4/3/1]
getline(ss, oneData, ' ');
stringstream oneDataS(oneData);
getline(oneDataS, v, '/');
getline(oneDataS, vt, '/');
getline(oneDataS, vn, '/');
int vertIndex = (stoi(v) - 1) * 3;
——————————————————————————————
函数原型:int compare(size_t pos, size_t len, const string& str) const;
函数原型:string& erase(size_t pos = 0, size_t len = npos);
函数原型:istream& getline(istream&& is, string& str, char delim);
函数原型:int stoi(const string& str, size_t* idx = 0, int base = 10);// stoi:StringToInteger
##############################
#include <stringstream>
stringstream ss(line.erase(0, 1));
ss >> x; ss >> y; ss >> z;
——————————————————————————————
构造函数原型:
explicit stringstream(const string& str,
ios_base::openmode which = ios_base::in | ios_base::out);
std::istream::operator>>
运算符>>是从istream类继承而来,并未重载之,故和istream中的>>具有完全相同的功能和特性。
比如,和cin>>一样,默认使用空白(空格、制表符和换行符)来确定字符串的结束位置,并清除遇到的空白缓冲。
stringstream类还有一个公有成员str,用来get/set内容。
string str() const;
void str(const string& s);
————————————————————————————
第一种形式(1)返回一个字符串对象,其中包含流当前内容的副本。
第二种形式(2)将s设置为流的内容,丢弃之前的任何内容。
对象保留其打开模式:如果这包括ios_base::ate,则写入位置将移动到新序列的末尾。
在内部,该函数调用其内部字符串缓冲区对象的str成员。
// stringstream::str
#include <string>
#include <iostream>
#include <sstream>// std::stringstream, std::stringbuf
int main ()
std::stringstream ss;
ss.str("Example string");
std::string s = ss.str();
std::cout << s << '\\n';// 打印:Example string
return 0;
以上是关于C++ 关于unique的用法的主要内容,如果未能解决你的问题,请参考以下文章
使用 std::unique_ptr 的 C++ Pimpl Idiom 不完整类型