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 = 0; return 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; public: bool 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 对堆进行排序,形成普通的排序, 二叉树排序,
原文:http://www.cnblogs.com/hansjorn/p/5215579.html