首页 > 其他 > 详细

STL 基本入门笔记学习

时间:2016-02-25 01:35:42      阅读:292      评论:0      收藏:0      [点我收藏+]
1,C++Primer初级:
预处理(E查看)->编译(S查看)->连接

13_枚举:可以尽可能多用枚举,多个const变量,可以用枚举去做;

string name("aaa"); //定义,初始化
string::size_type size = name.size();  //字符个数,保证可以获得对应的大小,int size = name.size(); 这个不安全
name.empty() 判断是否为空
字符串相加,是表示将两个连接起来,但是两个不能都是字符串字面值
例如 name+name2,但是不能“aa”+“bb”
ispunct(name[i])判断某个字符是否是标点符号(头文件cctype)
字符串的输入,不能用cin要用getline,然后用for循环,检查输入的字符串的每一个字符

vector 动态数组,其实是个类类型,一般可以替换到普通的数组。
常用里面的empty(),vector<int>::size_type, v.size(),和v.push_back();
vector begin(),返回一个迭代器,vector<int>::iterator iter = v.begin; 迭代器实质上是一个指针,所以可以给该值赋值*iter=9;
一般用迭代器替代下标,例如用vector<int>::size_type idx=0;
可以for(vector<int>::iterator i=v.begin();i!=v.end();i++){
    cout <<"迭代器 "<<*i<<endl;//这样可以通过*i获得vector v中的元素;即迭代器是个指针,这比下标取元素简单多了,尽量多使用迭代器方式,少用下标形式取元素
}
常迭代器与非常迭代器,区别为,不可以与可以通过迭代你修改数据
例如 vector<int>::const_iterator i = v.begin(); 常迭代器常用来读取数值,不用常迭代器修改数据;

bitset<32> a(156) 将156按二进制存储,到32位大小空间中。
a.any(); 判断是否有1,a.none()判断没有一个1,a.count() a有几个1.a.size()获得a的大小;a.set(index) 设置某位为1。或者直接下标写法,a[index]; a.set() 设置所有的为1. reset是变为0;

void*指针,是万能指针,可以指向任意的类型。但是这种指针不能通过其操作对象。
常指针才能指向常对象;普通指针不行,常指针必须初始化。常指针(常用来传递参数,防止修改参数)可以指向非常对象,这样之后,不能通过指针来修改其对象的值,也不能修改其指向再指向其他的对象。
举例:
#typedef string *pstring;
const pstring cpst; 与string *const cpst1;等同(常指针,指向字符串,必须初始化),与const string *cpst2;不同,指向常字符串指针,不用必须初始化
int a[]={1, 2, 3, 6, 5, 4}
int *ip1=a; //指针可以可以看做数组的迭代器。
int *ip2 = a+4;
ptrdiff_t a=ip2-ip1;得到地址差。即a=4;相差四个数

引用声明时,必须初始化。指针可以不用

c风格的字符串,必须用\0结束。
char a1[] = {a, b, \0};是
char a2[] = "ab";是
char a3[] = {a, b} 不是,只是c风格的字符数组
const char *a4 = "ab";是
strlen(a2);计算结果不包括\0
c风格的字符比较,用strcmp;而c++风格的字符串string类型,可以直接比较。字符串string类型可以s1>s2,s1==s2。但是c风格的字符不能a1==a2等操作,这样操作的仅仅是地址。而不是内部的值;
c风格的字符不能用=做拷贝,必须用strcpy(a1,a2);。strcat(a1,a2);c风格的字符串连接,c++的string类型的连接直接用+号,
标准库中strcmp,strcpy,strcat等都比较危险。一般使用带n的方法,例如strncmp,strncpy,strncat等,strncpy(a1,a2,2);n制定了拷贝的大小。不然很多黑客可以利用这些漏洞,可以修改里面的东西(缓冲区溢出攻击)。尽可能使用c++风格的字符串string类型。

动态数组创建,c语言,malloc(n*sizeof(int)),free(a)。c++ new int[n]和delete[] a;
int *a = new int[10];没有初始化。int *a = new int[10]();初始化了
string *astr = new string[10];使用默认的构造函数进行初始化;
数组等的循环,一般用指针,专业点,可以认为指针是数组的迭代器。
int *ai = new int[10];
for(int *p= ai; p!=ai+10; ++p){
   *p=11;//通常通过指针作为迭代器,给数组ai循环初始化操作;
}

c与c++转换
string 和char相互转换:string类型用c_str()转换后赋值的时候,对象必须是const,const char *= st.c_str();
数组和vector转换:int a[6]={1,2,3,4,5,6}; vector<int> v(a, a+6); 复制的时候,后面的是不包括的,所以是a+6,而不是a+5,或者用迭代器vector<int>::const_iterator 
vector<int> ivec;
int ival; //tmp变量,很重要
while(cin>>ival){ivec.push_back(ival) }//input data to vector; 创建动态数组 int *a = new int[ivec.size()];动态创建一个数组
字符串数组的c实现为:
vector<string> svec;
string sval;
while(cin>>sval) svec.push_back(sval);
char **c = new char*[svec.size()]; //赋值时,注意最后一个是\0
赋值可用中间变量char *tmp = new char[svec.size()];
然后将c[i]=tmp; //因为c是二重指针,所以存放的是地址;释放的时候也得用for循环。

多重数组
int a[n1][n2]; int (*ip)[4];//注ip是一个指针
常常用typedef简化指向数组的指针,例如:#typedef int int_array[4];然后,写int_array *ip;与以上的ip一样;这样可以避免丢失括号而导致ip不是指针的问题,ip=a;表示指向a的第一行,即ip是一个指针,所以使用ip取a中值时,还得使用一个指针;
int *ip[4]; //ip是一个数组,区分以上的有括号的情况

算术运算符
double 10/3; 会等于3,除号是整除和小数除
cout<<-21/-8;会等于-5,如果一正一负,结果可能是正也可能是负 -21/8 c++中是不确定的

箭头操作符与指针
Dog *p;
p=new Dog();
p->foo(); 和(*p).foo();等同,其中,foo为类Dog的方法
指针的指针,一般用一个临时指针,将中间值赋值给它;
vector<string*> spvec;
string str;
while(cin>>str)
{ string *pstr = new string;//相当于临时指针
  *pstr=str;
spvec.push_back(pstr);
}
这里一定要释放
vector<*string>::iter = spvec.begin();
while(iter != spvec.end()){ delet e * iter;iter++;}  //一般不直接操作spvec,而是通过迭代器,操作。

条件操作符,一般if 类型的可以用这个替换(a>b)?a:b; 不过慎用,避免嵌套,看起来繁杂不好理解

new delete
new的时候,如果是内置类型,一般要用括号;
例如int *a = new int();调用默认构造函数初始化
如果int *a = new int; 如果是内置类型,则没有初始化,很危险。
如果是在类类型,在main中创建的,这是等同的;所有的new 一定要使用delete撤销

强制类型转换符
C++新式的static_cast dynamic_cast reinterpret_cast const_cast 和传统C风格的;
举例:double dPi=3.1415926; int nNum=static_cast<int>(dPi);//这种啰嗦的写法提醒作者注意,这里用了强制转换,其实是和C风格一样
避免使用强制类型转换,C++一般不提倡c风格的在转换,因为没有检查,而dynamic_cast等,如果转换成果,返回值不为空,如果为空,表示转换不成果,例如:int n = dynamic_cast<int>(val);可以使用if(n) 判断是否成功

文件操作,抛出异常try catch,throw相结合的方式
FILE *input=fopen("a.txt", "rb");//常常对fopen进行判断,是否打开成功
FILE *output=fopen("b.txt", "rb");
一定要记得关闭fclose(input);fclose(output);
int size = fread(dst, sizeof(float), num, input);//size为读取的实质大小,dst为目标存储位置,sizeof(float)每次读多大的大小,num是总共读多少,input为输入文件流
int size_out = fwrite(dst, sizeof(float), num, output);//这里
用if(input==NULL) throw 1;//抛出异常,可以输出,数字,字符串,类对象。
代替if(input==NULL) return 1;
int func(){FILE *input =fopen("a.txt","rb");if (input==NULL) throw 1;}然后用以下部分处理异常;
try{func();}catch(int e){printf("e:%d",e);} catch(const char *e){}

标准异常类:exception,runtime_error rang_error,invalid_argument在stdexcept中),bad_alloc在头文件<new>中,
例如:try{}catch(bad_alloc err){cout<<"allocate exception";}
int function(int a){if(a<0)throw out_of_range("data not lower zero");}//定义自己的异常程序。调用的时候,用try catch即可。
设计自己的异常类,可以在自己定义的类中,添加类成员,这个类成员一般可以继承已有的异常类,然后实现里面的what方法:virtual const char *what() const throw(){ return "your message";}
602653
使用预处理进行调试,
第一使用#ifndef NDEBUG 方式,二,assert(头文件cassert)
获取对应的信息,三,使用__FILE__ __LINE__ __DATE__ __TIME__ 直接和内部定义的宏一样返回对应的文件位置,行数,日期时间等,直接使用。assert(3==(1+2)),如果不相等,则返回详细错误信息。其中NDEBUG为内部定义的宏,不使用调试的意思,如果用了,assert也将不起作用

引用形参;目的:一为了修改值,能传递回来,第二,防止赋值,降低操作时间,第三,使用const,避免修改
function(string a); 如果传递进去的a过长a="aaaaaaaaaaaaaaaaaaaaaa";会导致效率低下,特别是对a还不做修改时,强烈建议使用const 引用。function(const string &a);
指针引用 function(int *&val)val是个引用类型,同时也是指针。
例如:定义交换指针函数 swap(int *&a, int *&b); int a=9; int b=8; int *pa=&a; int *pb=&b;
swap(pa, pb);最后pa指向了b,pb指向了a。

vector list deque作为形参的时候,一般不是直接传递进入的,而是使用迭代器作为形参
例如:function(vector<int>::iterator begin, vector<int>::iterator end);

返回值为引用或者指针的时候,一定要注意,不要反悔一个函数结束时,此变量就不存在的对象:例如:int * function(){ int a = 0return a;}//这是很危险的,因为函数结束的时候,a就不存在了。切记。常引用或指针,不能赋值给非常引用或指针;
举例:改变字符串中的某个字符
char & change_s(string &str, int i){return str[i];}
调用时 string strv("aaa"); char &c=change_s(str,1); c="i"; //结果str变为了aia;因为这里传递进去的是引用,返回的也是引用,多以对原来的变量进行了修改,也是对原来的引用变量修改。而不是赋值操作,一定要区别,并且返回为引用指针的时候,一定要小心; 

大量的递归调用会占用内存和时间。默认实参,一般在函数声明处写。

内联函数一般放在头文件中,节省时间开销,递归和大函数,避免使用内联函数,内联函数在编译的时候,会展开。可以理解为避免了调用操作,而是直接展开替代。内联函数的编译对编译器来说,必须是可见的,所以一般得放在头文件中。

class
要变成对象了,才能使用,在类的定义中,没有对象,一般用this(类似于参数)表示,也可以不写,写上更好,表示这个变量时当前对象的。
例如
class Sale{
private:
bool val;
publicbool function(const Sale sa){
    this->val = sa.val; //this表示这里Sale的对象,不是这里的sa
}
}
只有静态成员才能直接使用初始化,一般的变量只能通过构造函数进行初始化,初始化的时候,一般用初始化列表形式进行初始化例如上面的用Sale():val(true),val1(0){};多个变量可以使用""号隔开。初始化过程中,一般基本的数据类型都必须初始化,一些有默认进行初始化的类型,不用进行初始化,例如string类型,就可以不用初始化,会使用默认的初始值进行初始化

重载与作用域:
重载函数一定要写到一个作用域。防止函数被屏蔽或隐藏现象。
变量名和函数名同名,可能导致函数屏蔽:例如 int init = 0; int a = init();其中init()为函数,这样会导致函数init();函数不可见,会出错,这种现象叫函数隐藏或者屏蔽。function(int *const a);和function(int *a);不能构成重载,但是function(int *a); 和function(const int *a);构成重载;

指向函数的指针(函数指针变量)(一般用typedef简化其声明)
bool (*pf)(int a, int b);声明了一个指向函数的指针,表示指向函数类型为参数表为(int, int)返回值为bool类型的函数指针,这里的(*pf)不能去掉。调用的时候,就是
pf=functionname;或者pf=&functionname 然后直接使用pf(3,4);或者(*pf)(3,4);.和调用functionname(3,4)一样。因为使用函数指针的时候,写起来太复杂。所以一般使用typedef 简化。
例如:typedef bool (*dPf)(int a, int b); 在使用的时候,就直接使用dPf pf;声明函数指针变量,就像直接使用bool (*pf)(int a, int b);一样,并且可以方便的定义多个函数指针变量,dPf pf1, pf2;非常方便。函数指针因为是个变量,所以可以作为函数形参,例如一个函数调用另外一个函数的时候,可以将另外一个函数的指针传递进入,实现一个函数调用另外一个函数。函数指针的形参必须和指向的函数的参数类型精确匹配。

流对象是不能复制的,所以要传递流对象的时候,一般用引用类型或者指针。
int function(ofstream ofs); ofstream of; 使用的时候function(of)会失败,因为流对象不能复制。把函数改为int function(ofstream &ofs)后,则可以这么使用了。

流的条件状态。if(cin.bad()) cin.fail() cin.eof() cin.good() cin.ignore(200, "\n"),要么忽略前两百个,要么忽略到\n. cin.setstate(XXX), cin.rdstate()等等
如果输入int a; cin>>a,你输入的str,check这个流的状态的时候,可以知道cin.fail()为真,也就是这个输入是失败的。cin.clear()流状态清理到正常的 状态
流对象的字符串为C风格的字符串,例如ofstream f; f.open(str.c_str())
 
逗号运算符,是逗号后面的为条件。例如while(cin>>a, !cin.eof()),其实while(cin>>a)当eof fail bad的时候会结束输入。而while(cin>>a, !cin.eof())只有到流的末尾时,才结束。另外注意,文件流的状态不会因为close了,而跟新,所以连续的用某个流open文件的时候,一定要记得用clear来恢复流的状态,然后再使用。
ifstream fs("file.txt"); 或者 ifstream fs;fs.open("file.txt");两种方式,将ifstream绑定文件。

文件模式:
in,out,app后面添加,ate定位到文件最后的文件定位指针,trunc截断,覆盖,binary

字符串输入输出流 stringstream istringstream ostringstream 是内存操作;cout cin 显示在屏幕,不是内存操作

2,中级STL学习:

deque 
和vector差不多,可以在前端后端插入,一般用deque取代vector,vector只能在后端插入push_back()。deque还可以push_front()。
list:双向链表,不能使用下标,和数组vector deque不同。只能使用迭代器,来指示元素。push_front,push_back,insert(位置,值),位置一般用迭代器来指定位置,其中insert返回的是一个迭代器。例如lis.insert(a.begin, 12);返回的是一个迭代器。删除使用erase(位置);或者erase(重哪里a,到哪里b);其中a位置包括,而b位置是不包括的。

迭代器和迭代器范围
iter.begin是指向第一个,iter.end是指向最后一个的下一个,实质end是不包括的最后一个的,所以begin()=end()的时候,容器是空的。iter+n只有vector和deque可以有这种操作。list不可以。迭代器是个指针,所以const_iterator是迭代器指向的值不会变。通常用常迭代器作为for循环的迭代,相当于for(int i=0;)中的i。

堆栈(容器适配器)
stack,LIFO形式。可以使用deque(默认) vector list做堆栈,stack<int, deque<int>> s。有empty() size() pop() top() push(item);push和pop都是始终指向栈顶。p.pop是删除数据,不返回删除的值,p.top()查看并返回查看的值。

队列(容器适配器)(堆栈和队列都没有迭代器,因为不能再中间进行操作数据,只能在两头进行,所以不能修改中间的数据)
queue, FIFO形式, queue不能用vector做队列(因为要求必须在两边进行操作,先进先出)。例如queue<int, list<int>> q; 或者指定为deque<int>(默认为deque)。操作,q.empty();q.size();q.front();查看队首,q.back();查看队尾,q.pop();q.push(item);push是在队尾操作,pop是在队首操作。

优先级队列(容器适配器) 
priority_queue 不能使用list,有最大最小优先级队列。priority_queue<int, deque<int>> pq;或者可以使用deque,vector(默认为), 不能使用list。pq.push(item),始终按循序排序(最大值(默认),或者最小值排序)。pq.size();获取大小数据个数。pq.top();查看,pq.pop();删除,因为队列始终指向队首,所以每次删除都是最大的(最小值)。pq.empty();判断是否为空。使用最小值优先级队列priority_queue<int ,deque<int>, greater<int>> pq;关键字greater<int>指示为最小值优先级队列。

顺序容器和容器适配器
vector list deque;stack queue priority_queue(优先级队列)
初始化问题使用默认的构造函数,带参数的构造函数
不同容器之间赋值,可以使用迭代器实现。
vector<int> ivec(ivec0); 使用同一种类型的顺序容器ivec0初始化ivec,这里ivec0必须是vector<int>类型。
但是list<string>slist(svec.begin(), svec.end());可以使用迭代器方式,对不同的容器赋值,例如svec是vector<string>类型。svec.begin()返回的是迭代器。svec.begin()+svec.size()/2 是指向svec向量对应的中间的数据元素。
list<string> slist(64);初始化了64个空字符串。或者list<string> slist(64, "hello");初始化为64个hello字符串。定义一个类Foo,然后使用vector<Foo> a(10);初始化10个Foo对象,和vector<Foo> a;不一样,vector<Foo> a(10);调用默认的构造函数,所以如果Foo没有默认的构造函数,那就出错了。如果vector<Foo> a(10, 1);调用Foo的构造函数,对应的参数为1;后面的1为形参表。

顺序容器的操作(1)
vector list deque操作类似。容器定义的类型别名,vector<int>::size_type a1(常常替换for中的int a1); iterator const_iterator(const容器返回const迭代器) reverse_iterator(对应rbegin,rend) const_reverse_iterator difference_type value_type reference const_reference类型。
顺序容器的操作(2)
c.push_back(), c.push_front()(向量没有), c.insert(p, value),插在p所指元素的前面。 c.insert(p,num,value);在p的前面插入num个value。c.insert(p, beginp, endp);
顺序容器的操作(3)
关系运算,比较的容器必须具有相同的数据类型
顺序容易的操作(4)
size() 返回数据个数,max_size()返回最多保持多少数据,empty(), resize()等
顺序容器的操作(5)
访问元素(返回的是引用):c.back(),c.front(), c[n],c.at(n)后面两个只对vector和deque有效,对list没效果,并且使用at比用[]方式要好,特别是处理异常的时候。
而c.begin();返回的是迭代器,迭代器是指针。
vector<int>::reference a = ivec.front();
vector<int>::reference a = *ivec.begin();因为ivec.begin()返回的是迭代器,所以用指针。
顺序容易的操作(6)
删除元素 c.erase(p), c.erase(b, e), c.clear(),c.pop_back(),c.pop_front(). pop_front只适用于list和deque。
list<string>::iterator iter = find(b,e,"value"); e表示迭代器,删除中,不包括。s
顺序容器的操作(7)
赋值和交换c1=c2 c1.swap(c2)类型必须相同才能进行, c1.assign(b, t),类型兼容即可

vector容器的自增长
vector用数组做出来,但是有数组更多的优点。vecv.capacity()返回向量以供可以存放多少数据,但是这个容量是自增长的,每次 增加50%或者和使用的C++有关,不需要去控制,而vecv.size是数组里面存了多少数据。 reserve。

顺序容器的选用
vector deque(数组形式,所以插入删除操作会很慢,但是排序,查找很快) list是个链表,所以插入删除操作insert eraser很快,但是排序sort 查找binary_search很慢。  push_back对list很快。

构造string对象的方法
string s1(s2) s1(5, a) s1="str" s1(s.begin(), s.end())等等

修改string对象的方法
s.intert s.assign

string对象的比较
s.compare(s2)等等

map multimap也是容器,是红黑树结构
插入数据:map<int, string> a; a.insert(map<int, string>::value_type(1, "one")); a.insert(make_pair(-1, "two"));(最常用), a.insert(pair<int,string>(100, "one hundred")); a[1000]="one thousand";给map 插入数据赋值,通过键值对的方式;a.size();获取a有多少个键值对。所有容器都有迭代器都有对应的迭代器。可以通过迭代器获得对应的键值:map<int, string>::const_iterator i; i = a.begin(); i->first; i->second;获得对应的值,这里是int和string值;multimap 和map一样,只是需要放重复的数据的时候,得使用multimap,并且可以使用count(100)获取含有100的个数,另外第四种数组的形式,即a[1000]="one thounsand"不能在multimap中使用。
查找(因为map是红黑树结构,数据搜索查找会很快):map<int, string>::const_iterator i = a.find(100); if(i !=a.end()),{cout<<"no found the 100"}; 也可以直接映射,或者字典,或者关联数组。使用a[100]和使用a.find(100)一样,返回结果会是“one hundrred”。
删除:a.erase(100) if(a.rease(100)>0){cout<<"delete success"} a.erase(b, e); b和e分别是开始的迭代器和结束的迭代器。

set和multiset 是集和多集。也是一种容器,红黑树结构。set<int> a; 有操作insert, count find,erase。同样multiset也是可以允许重复,但是,set不允许重复。注意不能通过find进行修改,因为set和multiset每次插入数据,是自动进行了排序的。。

STL算法简介,100多种算法,函数对象,函数适配器,三个头文件#include <algorithm> <numeric> <functional>
函数对象简介
for_each(起始指针,结束指针,函数或者函数对象) ;例如for_each(ivec.begin(), ivec.end(), display()); greater<int>(), less<int>(),plus<int>() 等等,是一些预定义的函数对象。
将一个类作为函数对象,使用operator,函数对象的好处:一般比普通的函数要快,有自己的状态。
例如:以下是一个函数对象,调用的时候,可以直接PRINT();打印a的值,使用这个类,像使用函数一样
class PRINT{
public:
 void operator()(int elem) const{  //调用的时候,自动调用里面的operator函数方法
   cout<<elem<<‘‘;
 }
};
函数适配器 count_if(ivec.begin(). ivec.end(), bind2nd(greater<int>(), 4);其中bind2nd是预定义的函数适配器,表示大于4的数。

元素计算算法:
通用的count count_if 对所有的容器都可以用,速度相对慢些,例如count(ivec.begin(), ivec.end(), 4),计算这个ivec里面有几个4, count_if(ivec.begin(). ivec.end(), 函数或者函数对象),计算ivec中满足函数或者函数对象的数。关联容器的元素计算算法,例如set.count, map.count, multiset.count, multimap.count这个比通用的计算容器快些。
最小最大值算法:
min_element(b, e); min_element(b, e, op) 同理max。其中op为函数或者函数对象。
查找算法(1)
find find_if 查找效率比较慢,如果是已序空间的算法,一般用关联容器适配器自带的算法那。string类型不能使用find和find_if,查找的结果是一个迭代器。find(b, e, 4); 将找到的第一个4,返回对应的迭代器,指向相对应的值。
茶渣算法(2)
search_n(b, e, c, n)连续的大于n的数的起始位置。search_n(b, e, c, n,greaater<int>())连续c个大于n的数起始位置.
查找算法(3)
search() find_end(),是一对,search()重前面开始查找,find_end()从后面开始查找。search(l.begin(), l.end(), k.begin(),k.end());在l的开始到结束中,找k的开始到结束中的数据,例如从l(1 2 3 4 5 6)找k(4 5 6);返回在l中对应的起始位置。
查找算法(4)
find_first_of(b, e, sb, se); find_first_of(b, e, se, bp); 没有find_last_of(一般用逆向迭代器实现),在b,e之间找含有sb到se中的任意数,的起始位置,就可以了。所以存的是找到的在sb到se中第一个数据出现在b到e中的起始位置。
string查找函数和stl查找算法的比较,首先,这些方法都是string的成员函数,而stl中是对应的algorithm中的方法:string:find stl:find; string:rfind stl:find+逆向迭代器;string:find,stl:search;string:rfind, stl:find_end; string:find_first_of stl:find_first_of; string find_last_of,stl:find_first_of+逆向迭代器;逆向迭代器vector<int>::reverse_iter irve, irve.base();输出的是对应的正向的位置;string::npos,对应的string自定义的成员变量;
查找算法(5)
adjacent_find(b, e);查找连续两个相等的或者; adjacent_find(b, e, p);两个连续的复合谓词规则的两个;
查找算法要使用得当,例如,如果是已序区间,就用已序区间查找算法例如binary_search()等等。
查找算法(6)
已序区间查找,要求必须先排好序,这样查找就比较快,binary_search(b, e, v)二分法查找数字v,或者带有谓词p查找,binary_search(b, e, v, p); 区间查找:includes(b,e,sb,se)或者带有谓词includes(b,e,sb,se,p);,lower_bound(), upper_bound(), equal_range();
查找算法(7)(已序区间算法,都必须先排序)
lower_bound(b,e,v), upper_bound(b,e,v);lower找到值为v的第一个数的位置,这里返回的是index(从0开始),upper是找到值为v的最后一个位置,所以这两个算法主要用于查找到有序的数据中某个数据的位置后,方便插入运算。
equal_range()返回既包括lower_bound又包括upper_bound,返回的是一对迭代器,例如pair<list<int>::iterator, list<int::iterator>> range; range = equal_range(b, e, v);通过range.first()和range.second();
如果有关联式容器,那就不要用这些方法,因为关联式容器有对应的算法,性能更加;

for_each()算法:
for_each(b,e,p);可以遍历数据,和函数对象修改数据,以及使用for_each的返回值。如果p是函数对象,则返回值也是函数对象,例如 MeanValue mv = for_each(ivec.begin(),ivec.end(), MeanValue());

算法交换
swap_ranges(b,e,b2); 如果是全部数据交换,并且是相同数据类型交换,一把用容器的成员函数swap()

填充新值:(修改性算法)
fill(b,e,v),填充之后,原来的被替换掉了; fill_n(b,n,v) generate(b,e,p) generate_n(b,n,p)。v是值,p是函数对象。

替换算法:
replace(b,e,ov,nv); 把旧的值ov替换为新的值nv,replace_if(b,e,p,v) replace_copy(b1,e1,b2,ov,nv) replace_copy_if(b1,e1,b2,p,v)

删除算法(1):
remove(b,e,v) vemove_if(b,e,p) 这里是一种逻辑删除,不是真正的删除,这里返回的是删除的最后的一个元素的终点,因为,remove的删除操作仅仅是后面的复制到后面,来覆盖,没有移动的部分的值是不不变的。即list:1 2 3 4 5,remove(b,e,3)之后,变为1 2 4 5 4 5;
最后的两个一般使用容器的删除成员函数来删除,erase(end, list.end())才是真正的删除后面的4 5;
删除算法(2):
remove_copy() remove_copy_if(),把一个容器的数据复制到另外一个容器中,复制的过程中使用remove逻辑删除。
删除算法(3):
unique(b,e)或者 unique(b,e,p) unique_copy(b,e,newb) unique_copy(b,e,,newb,p);删除连续的重复的数字的算法或者删除连续的数字满足p条件的第二个数字的算法,注意没有unique_if和 unique_copy_if

逆转和旋转:
reverse() reverse_copy() rotate() rotate_copy()

算法排列组合:使用前,数据一般都需要先排序
next_permutation(b,e)下一个排列组合,如果返回值为true,表示排列组合还没有结束,还有排列组合,否则,就没有下一个排列组合了。 prev_permutation(b,e)与next

重排分区算法:
randon_shuffer(b,e)随机重排,就像洗扑克牌,重新打乱。 partition(b,e,p)把符合规则p的数据放在前面,其他的放在后面进行分区,并且分区以后,每个区域也是打乱重排了的,算法返回值为一个迭代器,即分区的分界的位置。stable_partition(b,e,p),稳定的分区,
即符合规则p的在前面,不符合规则的在后面,但是在每个区的相对顺序是不变的。

排序算法:
sort(b,e)默认从小到大排序 sort(b,e,p) stable_sort(b,e) stable_sort(b,e,p),注意:这里的排序算法不适合随机存取容器,因此不适合list容器,因为list容器不能随机存取。
局部排序:
partial_sort(b,se,e) b到e之间的数据排序,如果排序的序列中排到了se的位置,则后面的都不排序了,所以到底有多少个进行了排序不知道。partial_sort(b,se,e,p) partial_sort_copy(sb,se,db,de) partial_sort_copy(sb,se,db,de,p)
根据第n个元素进行排序:
nth_element(b,n,e) b到e之间排序,拍到第n个结束,所以知道有n个元素进行了排序。nth_element(b,n,e,p) 对比partial()算法。
堆排序算法:
make_heap(b,e)将向量变成堆,即二叉树规则进行排序。 push_heap(b,e)将一个数据加到堆里,这里前提是先将要push的数据push到原数据的对尾,然后进行二叉树排序形成新的堆。
pop_heap(b,e)将最大的,也就是树顶的元素放到了最后,其他的数据重新生成堆,进行了二叉树进行排序了。 sort_heap 对堆进行排序,形成普通的排序, 二叉树排序,

 

STL 基本入门笔记学习

原文:http://www.cnblogs.com/hansjorn/p/5215579.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!