C++ STL学习

参考:http://c.biancheng.net/stl/sequence_container/

零:string类:

1、介绍

string 类由头文件 支持,该类包含了大量方法及若干构造函数,用于将字符串赋给变量、合并字符串、比较字符串和访问各个元素的重载操作符、查找字符和子字符串的方法等。C++ 从 C 继承的字符串概念仍然是以 ‘\0’ 为结束符的 char 数组。C++ 标准库中的 string class 可以将 string 作为一个型别,可以实现复制、赋值和比较,不必担心内存大小及占用内存实际长度等具体问题。

2、成员函数

(1)构造函数和析构函数

常见的 string 类构造函数有以下几种形式:

string strs                     //生成空字符串
string s(str)                   //生成字符串str的复制品
string s(str, stridx)           //将字符串str中始于stridx到最后的部分作为构造函数的初值
string s(str, strbegin, strlen) //将字符串str中始于strbegin、长度为strlen的部分作为字符串初值
string s(cstr)                  //以C_string类型cstr作为字符串s的初值
string s(cstr,char_len)         //以C_string类型cstr的前char_len个字符串作为字符串s的初值
strings(num, c)                 //生成一个字符串,包含num个c字符
strings(strs, beg, end)         //以区间[beg, end]内的字符作为字符串s的初值

析构函数的形式如下:

~string() //销毁所有内存,释放内存

eg:

#include 
#include 

using namespace std;

int main ()
{
    string str ("12345678");
    char ch[ ] = "abcdefgh";
    
    string a; //定义一个空字符串
    string str_1 (str); //构造函数,全部复制
    string str_2 (str, 2, 5); //构造函数,从字符串str的第2个元素开始,复制5个元素,赋值给str_2
    string str_3 (ch, 5); //将字符串ch的前5个元素赋值给str_3
    string str_4 (5,'X'); //将 5 个 'X' 组成的字符串 "XXXXX" 赋值给 str_4
    string str_5 (str.begin(), str.end()); //复制字符串 str 的所有元素,并赋值给 str_5
   
    cout << str << endl;   //12345678
    cout << a   << endl;   //空
    cout << str_1 << endl; //12345678
    cout << str_2 << endl; //34567
    cout << str_3 << endl; //abcde
    cout << str_4 << endl; //XXXXX
    cout << str_5 << endl; //12345678
    
    return 0;
}

(2)获取字符串长度

String 类型对象包括三种求解字符串长度的函数:size() 和 length()、maxsize() 和 capacity():
1)size() 和 length():这两个函数会返回 string 类型对象中的字符个数,且它们的执行效果相同。
2)max_size():max_size() 函数返回 string 类型对象最多包含的字符数。一旦程序使用长度超过 max_size() 的 string 操作,编译器会拋出 length_error 异常。
3)capacity():该函数返回在重新分配内存之前,string 类型对象所能包含的最大字符数。

#include 
#include 

using namespace std;

int main ()
{
    int size = 0;
    int length = 0;
    unsigned long maxsize = 0;
    int capacity=0;
    
    string str ("12345678");
    string str_custom;
    
    str_custom = str;
    str_custom.resize (5);
    size = str_custom.size();
    length = str_custom.length();
    maxsize = str_custom.max_size();
    capacity = str_custom.capacity();
    
    cout << "size = " << size << endl;         // 5
    cout << "length = " << length << endl;     // 5
    cout << "maxsize = " << maxsize << endl;   // 2147483647
    cout << "capacity = " << capacity << endl; // 5
    
    return 0;
}

(3)获取字符串元素
  
  字符串中元素的访问是允许的,一般可使用两种方法访问字符串中的单一字符:下标操作符[] 和 成员函数at()。两者均返回指定的下标位置的字符。第 1 个字符索引(下标)为 0,最后的字符索引为 length()-1。

需要注意的是,这两种访问方法是有区别的:
  下标操作符 [] 在使用时不检查索引的有效性,如果下标超出字符的长度范围,会示导致未定义行为。对于常量字符串,使用下标操作符时,字符串的最后字符(即 ‘\0’)是有效的。对应 string 类型对象(常量型)最后一个字符的下标是有效的,调用返回字符 ‘\0’。
  函数 at() 在使用时会检查下标是否有效。如果给定的下标超出字符的长度范围,系统会抛出 out_of_range 异常。

#include 
#include 

int main()
{
    const std::string cS ("c.biancheng.net");
    std::string s ("abode");
    char temp   = 0;
    char temp_1 = 0;
    char temp_2 = 0;
    char temp_3 = 0;
    char temp_4 = 0;
    char temp_5 = 0;
    
    temp = s [2]; //"获取字符 'c'
    temp_1 = s.at(2); //获取字符 'c'
    temp_2 = s [s.length()]; //未定义行为,返回字符'\0',但Visual C++ 2012执行时未报错
    temp_3 = cS[cS.length()]; //指向字符 '\0'
    temp_4 = s.at (s.length ()); //程序异常
    temp_5 = cS.at(cS.length ()); //程序异常
    std::cout << temp <<temp_1 << temp_2 << temp_3 << temp_4 << temp_5 << std::endl;
    
    return 0;
}

(4)字符串比较
  
  string 类模板既提供了 >、<、==、>=、<=、!= 等比较运算符,还提供了 compare() 函数,其中 compare() 函数支持多参数处理,支持用索引值和长度定位子串进行比较。该函数返回一个整数来表示比较结果。如果相比较的两个子串相同,compare() 函数返回 0,否则返回非零值。

#include 
#include 

using namespace std;

int main ()
{
    string A ("aBcdEf");
    string B ("AbcdEf");
    string C ("123456");
    string D ("123dfg");
    
    //下面是各种比较方法
    int m=A.compare (B);        //完整的A和B的比较
    int n=A.compare(1,5,B);     //"Bcdef"和"AbcdEf"比较
    int p=A.compare(1,5,B,4,2); //"Bcdef"和"Ef"比较
    int q=C.compare(0,3,D,0,3); //"123"和"123"比较
    cout << "m = " << m << ", n = " << n <<", p = " << p << ", q = " << q << endl;
    cin.get();
    return 0;
}

(5)字符串内容修改

  1. assign()函数
    使用 assign() 函数可以直接给字符串赋值。该函数既可以将整个字符串赋值给新串,也可以将字符串的子串赋值给新串。
#include 
#include 

using namespace std;

int main()
{
    string str1 ("123456");
    string str;
    
    str.assign (str1);   //直接赋值
    cout << str << endl; //123456
    
    str.assign (str1, 3, 3); //赋值给子串
    cout  <<str << endl;     //456
    
    str.assign (str1,2,str1.npos);//赋值给从位置 2 至末尾的子串
    cout << str << endl;          //3456
    
    str.assign (5,'X');           //重复 5 个'X'字符
    cout << str << endl;          //XXXXX
    
    string::iterator itB;
    string::iterator itE;
    itB = str1.begin ();
    itE = str1.end();

    str.assign (itB, (--itE)); //从第 1 个至倒数第 2 个元素,赋值给字符串 str
    cout << str << endl;       //123456
    
    return 0;
}
  1. operator= 函数
    operator= 的功能就是赋值。

  2. erase()函数

#include 
#include 

using namespace std;

int main() 
{
    string str("Hello,World!");
    str.erase(5,6);  // 删除从索引位置 5 开始的 6 个字符
    cout << "str 为:" << str << endl;

    return 0;
}
  1. swap()函数
//交换两个字符串
#include 
#include 

using namespace std;

int main() 
{
    string str1 = "hello,world!";
    string str2 = "HELLO,WORLD!";

    str1.swap(str2);

    cout << str1 << endl;
    cout << str2 << endl;

    return 0;
}

5)insert()函数
string&insert(size_t pos,const string&str);   // 在位置 pos 处插入字符串 str

string&insert(size_t pos,const string&str,size_t subpos,size_t sublen); // 在位置 pos 处插入字符串 str 的从位置 subpos 处开始的 sublen 个字符

string&insert(size_t pos,const char * s);    // 在位置 pos 处插入字符串 s

string&insert(size_t pos,const char * s,size_t n); // 在位置 pos 处插入字符串 s 的前 n 个字符

string&insert(size_t pos,size_t n,char c);      // 在位置 pos 处插入 n 个字符 c

iterator insert (const_iterator p, size_t n, char c); // 在 p 处插入 n 个字符 c,并返回插入后迭代器的位置

iterator insert (const_iterator p, char c);       // 在 p 处插入字符 c,并返回插入后迭代器的位置

string A("ello");
string B ;
B.insert(1,A);
cout << B << endl;

A = "ello";
B = "H";
B.insert (1,"yanchy ",3);
cout<< B <<endl;

A = "ello";
B = "H";
B.insert (1,A,2,2);
cout << B << endl;

A="ello";
B.insert (1 , 5 , 'C');
cout << B << endl;

A = "ello";
string::iterator it = B.begin () +1;
const string:: iterator itF = A.begin();
const string:: iterator itG = A.end();
B.insert(it,itF,itG);
cout << B << endl;

6)append 函数
append() 函数的原型为:

basic_string& append (const E * s); //在原始字符串后面追加字符串s
basic_string& append (const E * s, size_type n);//在原始字符串后面追加字符串 s 的前 n 个字符
basic_string& append (const basic_string& str, size_type pos,size_type n);//在原始字符串后面追加字符串 s 的子串 s [ pos,…,pos +n -1]
basic_string& append (const basic_string& str);
basic_string& append (size_type n, E c); //追加 n 个重复字符
basic_string& append (const_iterator first, const_iterator last); //使用迭代器追加

7)字符串内容的替换

如果在一个字符串中标识出具体位置,便可以通过下标操作修改指定位置字符的值,或者替换某个子串。完成此项操作需要使用 string 类的成员函数 replace()。

replace() 函数的原型如下:

basic_string& replace (size_type p0, size_type n0, const E * s); //使用字符串 s 中的 n 个字符,从源串的位置 P0 处开始替换
basic_string& replace (size_type p0, size_type n0, const E *s, size_type n); //使用字符串 s 中的 n 个字符,从源串的位置 P0 处开始替换 1 个字符
basic_string& replace (size_type p0, size_type n0, const basic_string& str); //使用字符串 s 中的 n 个字符,从源串的位置 P0 处开始替换
basic_string& replace (size_type p0, size_type n0, const basic_string& str, size_type pos, size_type n); //使用串 str 的子串 str [pos, pos + n-1] 替换源串中的内容,从位置 p0 处开始替换,替换字符 n0 个
basic_string& replace (size_type p0, size_type n0, size_type n, E c); //使用 n 个字符 'c' 替换源串中位置 p0 处开始的 n0 个字符
basic_string& replace (iterator first0, iterator last0, const E * s);//使用迭代器替换,和 1) 用法类似
basic_string& replace (iterator first0, iterator last0, const E * s, size_type n);//和 2) 类似
basic_string& replace (iterator first0, iterator last0, const basic_string& str); //和 3) 类似
basic_string& replace (iterator first0, iterator last0, size_type n, E c); //和 5) 类似
basic_string& replace (iterator first0, iterator last0, const_iterator first, const_iterator last); //使用迭代器替换

该函数的使用方法参照下面的程序:

#include 
#include 
using namespace std;
int main ()
{
    string var ("abcdefghijklmn");
    const string dest ("1234");
    string dest2 ("567891234");
    var.replace (3,3, dest);
    cout << "1: " << var << endl;
    var = "abcdefghijklmn";
    var.replace (3,1, dest.c_str(), 1, 3);
    cout << "2: " << var << endl;
    var ="abcdefghijklmn";
    var.replace (3, 1, 5, 'x');
    cout << "3: " << var << endl;
    string::iterator itA, itB;
    string::iterator itC, itD;
    itA = var.begin();
    itB = var.end();
    var = "abcdefghijklmn";
    var.replace (itA, itB, dest);
    cout << "4: " << var << endl;
    itA = var.begin ();
    itB = var.end();
    itC = dest2.begin () +1;
    itD = dest2.end ();
    var = "abodefghijklmn";
    var.replace (itA, itB, itC, itD);
    cout << "5: " << var << endl;
    var = "abcdefghijklmn";
    var.replace (3, 1, dest.c_str(), 4); //这种方式会限定字符串替换的最大长度
    cout <<"6: " << var << endl;
    return 0;
}
程序执行结果为:
1: abc1234ghijklmn
2: abc234efghijklmn
3: abcxxxxxefghijklmn
4: 1234
5: 67891234efghijklmn
6: abc1234efghijklmn

(6)字符串查找

1)find()函数和 rfind()

//find() 函数的原型主要有以下 4 种:
size_type find (value_type _Chr, size_type _Off = 0) const;
//find()函数的第1个参数是被搜索的字符、第2个参数是在源串中开始搜索的下标位置
size_type find (const value_type* _Ptr , size_type _Off = 0) const;
//find()函数的第1个参数是被搜索的字符串,第2个参数是在源串中开始搜索的下标位置
size_type find (const value_type* _Ptr, size_type _Off = 0, size_type _Count) const;
//第1个参数是被搜索的字符串,第2个参数是源串中开始搜索的下标,第3个参数是关于第1个参数的字符个数,可能是 _Ptr 的所有字符数,也可能是 _Ptr 的子串宇符个数
size_type find (const basic_string& _Str, size_type _Off = 0) const;
//第1个参数是被搜索的字符串,第2参数是在源串中开始搜索的下标位置

rfind() 函数的原型和find()函数的原型类似,参数情况也类似。只不过 rfind() 函数适用于实现逆向查找。

#include 
#include 
using namespace std;
int main ()
{
    string str_ch (" for");
    string str (" Hi, Peter, I'm sick. Please bought some drugs for me.");
    string::size_type m= str.find ('P', 5);
    string::size_type rm= str.rfind('P', 5);
    cout << "Example - find() : The position (forward) of 'P' is: " << (int) m << endl;
    cout << "Example - rfind(): The position (reverse) of 'P' is: " << (int) rm << endl;
    string::size_type n = str.find (" some", 0);
    string::size_type rn = str.rfind (" some", 0);
    cout << "Example - find () : The position (forward) of 'some' is: " << (int) n << endl;
    cout << "Example - rfind () : The position (reverse) of 'some' is: " << (int) rn << endl;
    string::size_type mo = str.find (" drugs", 0, 5);
    string::size_type rmo = str.rfind (" drugs", 0, 5);
    cout << "Example - find(): The position (forward) of 'drugs' is: " << (int) mo << endl;
    cout << "Example - rfind(): The position (reverse) of 'drugs' is: " << (int) rmo << endl;
    string::size_type no = str.find (str_ch, 0);
    string::size_type rno = str.rfind(str_ch, 0);
    cout << "Example - find (): The position of 'for' is: " << (int) no << endl;
    cout << "Example - rfind(): The position of 'for' is: " << (int) rno << endl;
    cin.get ();
}
程序的运行结果为:
Example - find() : The position (forward) of 'P' is: 5
Example - rfind(): The position (reverse) of 'P' is: 5
Example - find () : The position (forward) of 'some' is: 35
Example - rfind () : The position (reverse) of 'some' is: -1
Example - find(): The position (forward) of 'drugs' is: 40
Example - rfind(): The position (reverse) of 'drugs' is: -1
Example - find (): The position of 'for' is: 46
Example - rfind(): The position of 'for' is: -1

2)find_first_of()函数和 find_last_of()函数

find_first_of() 函数可实现在源串中搜索某字符串的功能,该函数的返回值是被搜索字符串的第 1 个字符第 1 次出现的下标(位置)。若查找失败,则返回 npos。

find_last_of() 函数同样可实现在源串中搜索某字符串的功能。与find_first_of() 函数所不同的是,该函数的返回值是被搜索字符串的最后 1 个字符的下标(位置)。若查找失败,则返回 npos。

//上述两个函数的原型分别为:
size_type find_first_not_of (value_type_Ch, size_type_Off = 0) const; size_type find_first_of (const value_type* _Ptr, size_type _Off = 0) const;
size_type find_first_of (const value_type* _Ptr, size_type_Off, size_type_Count) const;
size_type find_first_of (const basic_string & _Str, size_type_Off = 0) const;
size_type find_last_of (value_type _Ch, size_type_Off = npos) const;
size_type find_last_of (const value_type* _Ptr, size_type_Off = npos) const;
size_type find_last_of (const value_type* _Ptr, size_type _Off, size_type _Count) const;
size_type find_last_of (const basic_string& _Str, size_type_Off = npos) const;

下面的程序示例详细阐述了 find_first_of() 函数和 find_last_of() 函数的使用方法。这两个函数和 find() 函数及 rfind() 函数的使用方法相同,具体参数的意义亦相同。

#include 
#include 
using namespace std;
int main ()
{
    string str_ch ("for");
    string str("Hi, Peter, I'm sick. Please bought some drugs for me. ");
    int length = str.length();
    string::size_type m = str.find_first_of ('P', 0);
    string::size_type rm = str.find_last_of ('P', (length - 1));
    cout << "Example - find_first_of (): The position (forward) of 'P' is: " << (int) m << endl;
    cout << "Example - find_last_of (): The position (reverse) of 'P' is: " << (int) rm << endl;
    string:: size_type n = str.find_first_of ("some", 0);
    string:: size_type rn = str.find_last_of ("some", (length -1));
    cout << "Example - find_first_of(): The position (forward) of 'some' is: " << (int) n << endl;
    cout << "Example - find_last_of(): The position (reverse) of 'some' is: " << (int) rn << endl;
    string:: size_type mo = str.find_first_of ("drugs", 0, 5);
    string:: size_type rmo = str.find_last_of ("drugs", (length-1), 5);
    cout << "Example - find_first_of () : The position (forward) of 'drugs' is: " << (int) mo << endl;
    cout << "Example - find_last_of () : The position (reverse) of 'drugs' is: " << (int) rmo << endl;
    string::size_type no = str.find_first_of (str_ch, 0);
    string::size_type rno = str.find_last_of (str_ch, (length -1));
    cout << "Example - find_first_of() : The position of 'for' is: " << (int) no << endl;
    cout << "Example - find_last_of () : The position of 'for' is: " << (int) rno << endl;
    cin.get();
    return 0;
}
程序执行结果:
Example - find_first_of (): The position (forward) of 'P' is: 4
Example - find_last_of (): The position (reverse) of 'P' is: 21
Example - find_first_of(): The position (forward) of 'some' is: 5
Example - find_last_of(): The position (reverse) of 'some' is: 51
Example - find_first_of () : The position (forward) of 'drugs' is: 8
Example - find_last_of () : The position (reverse) of 'drugs' is: 48
Example - find_first_of() : The position of 'for' is: 8
Example - find_last_of () : The position of 'for' is: 48

3)find_first_not_of()函数和 find_last_not_of()函数

//find_first_not_of() 函数的函数原型为:
size_type find_first_not_of (value_type _Ch, size_type_Off = 0) const;
size_type find_first_not_of (const value_type * _Ptr, size_type_Off = 0) const;
size_type find_first_not_of (const value_type* _Ptr, size_type_Off, size_type_Count) const;
size_type find_first_not_of (const basic_string & _Str, size_type_Off = 0) const;

find_first_not_of() 函数可实现在源字符串中搜索与指定字符(串)不相等的第 1 个字符;find_last_not_of() 函数可实现在源字符串中搜索与指定字符(串)不相等的最后 1 个字符。这两个函数的参数意义和前面几个函数相同,它们的使用方法和前面几个函数也基本相同。详见下面的程序:

#include < iostream >
#include 
using namespace std;
int main ()
{
    string str_ch (" for");
    string str ("Hi, Peter, I'm sick. Please bought some drugs for me.");
    int length = str.length ();
    string::size_type m= str.find_first_not_of ('P',0);
    string::size_type rm= str.find_last_not_of ('P', (length -1);
    cout << "Example - find_first_of (): The position (forward) of 'P' is: " << (int) m << endl;
    cout << "Example - find_last_of (): The position (reverse) of 'P' is: " << (int) rm << endl;
    string:: size_type n = str.find_first_not_of ("some", 0);
    string:: size_type rn = str.find_last_not_of ("some", (length -1));
    cout << "Example - find_first_of (): The position (forward) of 'some' is: " << (int) n << endl;
    cout << "Example - find_last_of (): The position (reverse) of 'some' is: " << (int) rn << endl;
    string:: size_type mo = str.find_first_not_of ("drugs", 0, 5);
    string:: size_type rmo = str.find_last_not_of ("drugs", (length-1), 5);
    cout << "Example - find_first_of (): The position (forward) of 'drugs' is: " << (int) mo << endl;
    cout << "Example - find_last_of (): The position (reverse) of 'drugs' is: " << (int) rno << endl;
    string::size_type no = str.find_first_not_of (str_ch, 0);
    string::size_type rno = str.find_last_not_of (str_ch, (length-1));
    cout << "Example - find_first_of (): The position of 'for' is: " << (int) no << endl;
    cout << "Example - find_last_of () : The position of 'for' is: " << (int) rno << endl;
    cin.get ();
    return 0;
}
程序运行结果为:
Example - find_first_of (): The position (forward) of 'P' is: 0
Example - find_last_of (): The position (reverse) of 'P' is: 52
Example - find_first_of (): The position (forward) of 'some' is: 0
Example - find_last_of (): The position (reverse) of 'some' is: 52
Example - find_first_of (): The position (forward) of 'drugs' is: 0
Example - find_last_of (): The position (reverse) of 'drugs' is: 52
Example - find_first_of (): The position of 'for' is: 0
Example - find_last_of () : The position of 'for' is: 52

一:vector:

1.解释:
   vector(向量):是一种顺序容器,事实上和数组差不多,但它比数组更优越。一般来说数组不能动态拓展,因此在程序运行的时候不是浪费内存,就是造成越界。而vector正好弥补了这个缺陷,它的特征是相当于可分配拓展的数组,它的随机访问快,在中间插入和删除慢,但在末端插入和删除快。
2.用法:
  1.头文件

#include  

2.定义方式

a) vector<int> v1;        //vector元素为 int 型  
b) vector<string> v2;     // vector元素为string型  
c) vector<node> v3;       //入队元素为结构体型,结构体可以自行定义
vector<int>::iterator it; //定义一个迭代器

3.常用操作

v1.push_back()      // 在容器的最后添加一个数据
v1.pop_back()       // 去掉容器中的最后一个数据 
v1.front()       // 返回第一个元素(栈顶元素)
v1.begin()          // 得到数组头的指针,用迭代器接受
v1.end()            // 得到数组的最后一个单元+1的指针,用迭代器接受
v1.clear()          // 移除容器中所有数据
v1.empty()          // 判断容器是否为空
v1.erase(pos)       // 删除pos位置的数据
v1.erase(beg,end)   // 删除[beg,end)区间的数据
v1.size()           // 回容器中实际数据的个数
v1.insert(pos,data) // 在pos处插入数据

3.例子

#include 
#include 
#include 
using namespace std;

int main()
{
    vector <int> v;                     //定义vector
    vector <int>::iterator it;          //定义一个vector迭代器
    for(int i = 10; i >= 1; i--)        //插入数据
        v.push_back(i);
    cout<<"输出:";
    for(it=v.begin();it!=v.end();it++)  //输出迭代器的值
        cout<<*it<<" ";
    cout<<endl;
    it-=1;
    cout<<"最后一个的值为:"<<*it<<" "<<endl;
    v.erase(it);                        //删除最后一个元素
    cout <<"元素个数:" <<v.size() << endl;    //输出元素个数
    sort(v.begin(), v.end());           //vector排序
    cout<<"排序后:";
    for(it=v.begin();it!=v.end();it++)  //输出vector元素
        cout << *it << " ";
    cout<<endl;
    v.insert(v.begin(),100) ;            //在pos位置插入一个elem
    cout<<"第一个元素为:" <<v.front()<<endl;//输出第一个元素
    v.pop_back();                         //去掉最后一个元素
    cout << "元素个数:" <<v.size() << endl;//输出元素个数
    v.clear();                            //vector清空
    cout <<"清空后元素个数:" << v.size() << endl;//输出元素个数
    return 0;
}

二:栈和队列
  1.头文件

#include  // 队列 
#include  //栈

2.定义方式

stack<int>  s;  //参数也是数据类型,这是栈的定义方式
queue<int>  q;  //参数是数据类型,这是队列的定义方式

3.常用操作

栈:
s.empty() //如果栈为空返回true,否则返回false  
s.size()  //返回栈中元素的个数  
s.pop()   //删除栈顶元素但不返回其值  
s.top()   //返回栈顶的元素,但不删除该元素  
s.push(X) //在栈顶压入新元素 ,参数X为要压入的元素


队列:
q.empty() // 如果队列为空返回true,否则返回false  
q.size()  // 返回队列中元素的个数  
q.pop()   //删除队列首元素但不返回其值  
q.front() // 返回队首元素的值,但不删除该元素  
q.push(X) //在队尾压入新元素 ,X为要压入的元素
q.back()  //返回队列尾元素的值,但不删除该元素  

4.例子

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
    queue<int> q;
    stack<char> s;
    q.push(1);
    cout << q.enpty() << endl;
    q.push(2);
    cout << q.front() << endl;
    q.pop();
    cout << q.front() << endl;
    q.pop();
    cout << q.empty() <<endl;
    s.push(a);
    cout << s.top() <<endl;
    s.push(b);
    cout << s.top();
    s,pop();
    cout << s.top();
}

三、set
1.解释
关于set,必须说明的是set关联式容器。 set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。

2.用法

1.头文件

#include  

2.常用操作

set<int> s    //定义一个set容器 类型为int型
s.begin()     //返回指向第一个元素的迭代器
s.clear()     //清除所有元素
s.count()     //返回某个值元素的个数
s.empty()     //如果集合为空,返回true
s.end()       //返回指向最后一个元素之后的迭代器,不是最后一个元素
s.erase()     //删除集合中的元素
s.find()      //返回一个指向被查找到元素的迭代器,如果没找到则返回end()
s.insert()    //在集合中插入元素
s.size()      //集合中元素的数目
s.swap()      //交换两个集合变量

3.例子:

#include 
#include 
using namespace std;
int main()
{
    int i;
    set<int> set1;
    for(i=0; i<10; ++i)
        set1.insert(i);
    set<int>::iterator it;
    for(it=set1.begin(); it!=set1.end(); it++)
        cout<<*it<<"\t";
    cout<<endl;
    set1.erase(5);
    if(set1.insert(3).second)//把3插入到set1中,插入成功则set1.insert(3).second返回1,否则返回0.
        cout<<"set insert success";
    else
        cout<<"set insert failed";
    cout<<endl;
    set<int>::iterator itr;
    for(itr=set1.begin(); itr!=set1.end(); itr++)
        cout<<*itr<<"\t";
    set1.clear();
    return 0;
}

四、pair

1.解释:
  pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同。如果一个函数有两个返回值的话,如果是相同类型,就可以用数组返回,如果是不同类型,就可以自己写个struct ,但为了方便就可以使用 c++自带的pair ,返回一个pair,其中带有两个值。除了返回值的应用,在一个对象有多个属性的时候 ,一般自己写一个struct ,如果就是两个属性的话,就可以用pair 进行操作。pair 可以省的自己写一个struct .如果有三个属性的话,其实也是可以用的pair 的 ,极端的写法 pair >写法极端。(后边的两个 > > 要有空格,否则就会是 >>位移运算符)

2.用法:

1.头文件

#include 

2.定义方法

pair<int, string> a;
/*表示a中有两个类型,第一个元素是int型的,第二个元素是string类型的,
如果创建pair的时候没有对其进行初始化,则调用默认构造函数对其初始化。*/
pair<string, string> a("James", "Joy");//直接初始化

3.常用操作

(1)对于pair类,由于它只有两个元素,分别名为first和second,因此直接使用普通的点操作符即可访问其成员

pair<string, string> a("Lily", "Poly"); 
string name;
name = pair.second;
/*a.first 返回Lily
a.second 返回 Poly*/

(2)生成新的pair对象,可以使用make_pair对已存在的两个数据构造一个新的pair类型

int a = 8;
string m = "James";
pair<int, string> newone;
newone = make_pair(a, m);

3.例子

#include 
#include 
using namespace std;
typedef pair<string, string> au;  //利用typedef简化其声明
int main()
{
    int flag;
    string x1,x2;
    pair<string, string> p1("a","bc"); /*创建一个pair对象,
                      它的两个元素分别为string和string类型,
                                 其中first成员初始化为“a”,
                               而second成员初始化为“ab”*/
    au p2("a","aa");
    au p3;
    string name;
    name=p1.second; //返回1中名为second的数据成员
    cout<<p1.first<<endl;
    cout<<name<<endl;
    flag=p1<p2;
    cout<<flag<<endl; //判断两个pair对象的大小按字典次序
    flag=p1>p2;
    cout<<flag<<endl;
    while(cin>>x1>>x2)
    {
        p3=make_pair(x1,x2); //生成一个新的pair对象
        cout<<p3.first<<"****"<<p3.second<<endl;
    }
    return 0;
}

五、map

1.解释:

Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。

2.用法:

1.头文件

#include

2.定义方法

Map<int, string> mapStudent; //定义一个用int作为索引,
                           //并拥有相关联的指向string的指针.

3.常用操作

  begin()           //返回指向map头部的迭代器
  clear(//删除所有元素
  count()           //返回指定元素出现的次数
  empty()           //如果map为空则返回true
  end()             //返回指向map末尾的迭代器
  erase()           //删除一个元素
  find()            //查找一个元素
  insert()          //插入元素
  max_size()        //返回可以容纳的最大元素个数
  size()            //返回map中元素的个数
  swap()            //交换两个map

3.例子:

#include
#include
using namespace std;
int main()
{
    map<char,int> a;//定义map函数
    a.insert(map<char,int>::value_type('c',1));//插入元素
    a.insert(map<char,int>::value_type('d',2));
    map<char,int>::iterator b=a.find('c');//查找元素
    a. clear();//删除所有元素
    return 0;
}

六、list

1.解释:

list是一种序列式容器。list容器完成的功能实际上和数据结构中的双向链表是极其相似的,list中的数据元素是通过链表指针串连成逻辑意义上的线性表,list不仅是一个双向链表,而其还是一个环状双向链表。所以它只需要一个指针,便可以完整实现整个链表。list有一个重要性质:插入操作(insert)和合并操作(splice)都不会 造成原有的list迭代器失效。甚至 list的元素删除操作(erase)也只有“指向被删除元素”的那个迭代器失效,其他迭代器不受任何影响。

1.常用操作:

1.头文件

#include

2.定义

list<string>  test; //定义一个string类型的list

3.常用函数

push_front(x)//把元素x推入(插入)到链表头部
push_back(x)//把元素x推入(插入)到双向队列的尾部
pop_front()//弹出(删除)双向队列的第一个元素
pop_back()//弹出(删除)双向队列的最后一个元素
begin()//返回向量中第一个元素的迭代器
clear()//清空list中的所有元素。
empty()//利用empty() 判断list是否为空。
front()//获得list容器中的头部元素
back()//获得list容器的最后一个元素。

3.例子

#include 
#include
#include
using namespace std;
typedef list<string> LISTSTR;
int  main()
{
    LISTSTR test;

    test.push_back("back");                 //back
    test.push_front("middle");              //middle back
    test.push_front("front");               //front  middle back

    cout<<test.front()<<endl;               //front
    cout<<*test.begin()<<endl;              //front

    cout<<test.back()<<endl;                //back
    cout<<*(test.rbegin())<<endl;           //back

    test.pop_front();                       //middle back
    test.pop_back();                        //middle

    cout<<test.front()<<endl;               //middle

}

七、优先队列
1.解释:

优先队列是队列的一种,不过它可以按照自定义的一种方式(数据的优先级)来对队列中的数据进行动态的排序,每次的push和pop操作,队列都会动态的调整,以达到我们预期的方式来存储。

例如,将元素5 3 2 4 6依次push到优先队列中,规定顺序为从大到小并输出,输出顺序为6 5 4 3 2

2.用法

1.头文件

#include//与队列相同,不必引入vector的头文件

2.定义方式

priority_queue<int> p;//最大值优先,是大顶堆一种简写方式
priority_queue<int,vector<int>,greater<int>>q1;//最小值优先,小顶堆
priority_queue<int,vector<int>,less<int> >q2;//最大值优先,大顶堆

//其中第一个参数是数据类型,第二个参数为容器类型。第三个参数为比较函数。
//在使用时,我们会有很多时间用到根据结构体的某一个元素进行排序,下面给出定义结构体的优先级比较方式

struct node
{
    string name;
    int price;
    friend bool operator< (node a, node b)
    {
        return a.price < b.price; // 相当于less,这是大顶堆,反之则是小顶堆,最大值优先
    }
} stu; //定义结构体变量

这样直接可以:
priority_queue<node > q;

可以将比较运算符外置,方法如下

struct node
{
    string name;
    int price;
} stu; //定义结构体变量

struct cmp
{
    bool operator () (node a, node b) // 重载括号
    {
        return node.price < node.price; // 相当于less,大顶堆
    }
};

3.常用操作:

q.push(x) //将x加入队列中,即入队操作

q.pop() //出队操作(删除队列首元素),只是出队,没有返回值

q.top() //返回第一个元素(队首元素)优先队列的队首用top,而普通队列的队首用front

q.size() //返回栈队列中的元素个数

q.empty() //当队列为空时,返回 true

3.举例

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

struct node
{
    friend bool operator< (node n1, node n2)
    {
        return n1.priority < n2.priority;
    }
    int priority;
    int value;
};
int main()
{
    const int len = 5;
    int i;
    int a[len] = {3,5,9,6,2};
    //示例1:从大到小输出
    priority_queue<int> qi;
    for(i = 0; i < len; i++)
        qi.push(a[i]);
    for(i = 0; i < len; i++)
    {
        cout<<qi.top()<<" ";
        qi.pop();
    }
    cout<<endl;
    //示例2:从小到大输出
    priority_queue<int, vector<int>, greater<int> >qi2;
    for(i = 0; i < len; i++)
        qi2.push(a[i]);
    for(i = 0; i < len; i++)
    {
        cout<<qi2.top()<<" ";
        qi2.pop();
    }
    cout<<endl;
    //示例3:按优先级输出
    priority_queue<node> qn;
    node b[len];
    b[0].priority = 6; b[0].value = 1;
    b[1].priority = 9; b[1].value = 5;
    b[2].priority = 2; b[2].value = 3;
    b[3].priority = 8; b[3].value = 2;
    b[4].priority = 1; b[4].value = 4;

    for(i = 0; i < len; i++)
        qn.push(b[i]);
    cout<<"优先级"<<'\t'<<"值"<<endl;
    for(i = 0; i < len; i++)
    {
        cout<<qn.top().priority<<'\t'<<qn.top().value<<endl;
        qn.pop();
    }
    return 0;
}

八、双端队列
1.解释

Deque(双端队列)是一种具有队列和栈的性质的数据结构。双端队列的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。

2.常用操作:

1.头文件

#include 

2.定义

a) deque<int>s1;  
b) deque<string>s2; 
c) deque<node>s3; /*node为结构体,可自行定义。*/

3.常用操作

//a) 构造函数
deque<int> ideq

//b)增加函数
ideq.push_front( x):双端队列头部增加一个元素X
ideq.push_back(x):双端队列尾部增加一个元素x

//c)删除函数
ideq.pop_front():删除双端队列中最前一个元素
ideq.pop_back():删除双端队列中最后一个元素
ideq.clear():清空双端队列中元素

//d)判断函数
ideq.empty() :向量是否为空,若true,则向量中无元素

//e)大小函数
ideq.size():返回向量中元素的个数

3、举例

#include 
#include 
#include 
using namespace std;
int main()
{
    deque<int> ideq(20); //Create a deque ideq with 20 elements of default value 0
    deque<int>::iterator pos;
    int i;

    //使用assign()赋值  assign在计算机中就是赋值的意思
    for (i = 0; i < 20; ++i)
        ideq[i] = i;

    //输出deque
    printf("输出deque中数据:\n");
    for (i = 0; i < 20; ++i)
        printf("%d ", ideq[i]);
    putchar('\n');

    //在头尾加入新数据
    printf("\n在头尾加入新数据...\n");
    ideq.push_back(100);
    ideq.push_front(i);

    //输出deque
    printf("\n输出deque中数据:\n");
    for (pos = ideq.begin(); pos != ideq.end(); pos++)
        printf("%d ", *pos);
    putchar('\n');

    //查找
    const int FINDNUMBER = 19;
    printf("\n查找%d\n", FINDNUMBER);
    pos = find(ideq.begin(), ideq.end(), FINDNUMBER);
    if (pos != ideq.end())
        printf("find %d success\n", *pos);
    else
        printf("find failed\n");

    //在头尾删除数据
    printf("\n在头尾删除数据...\n");
    ideq.pop_back();
    ideq.pop_front();

    //输出deque
    printf("\n输出deque中数据:\n");
    for (pos = ideq.begin(); pos != ideq.end(); pos++)
        printf("%d ", *pos);
    putchar('\n');
    return 0;
}

九、Binary search

1.解释

以前遇到二分的题目都是手动实现二分,不得不说错误比较多,关于返回值,关于区间的左闭右开等很容易出错,最近做题发现直接使用STL中的二分函数方便快捷还不会出错,不过对于没有接触过的同学,二分函数确实是一个头疼的部分,自己查的内容又有点乱,找不到具体的使用方法,有必要自己总结一份完整的以后备用。

2.常用操作

1.头文件

#include 

2.使用方法

1.binary_search:查找某个元素是否出现。
  a.函数模板:binary_search(arr[],arr[]+size ,  indx)
  b.参数说明:
    arr[]: 数组首地址
    size:数组元素个数
    indx:需要查找的值
  c.函数功能:在数组中以二分法检索的方式查找,若在数组(要求数组元素非递减)中查找到indx元素则真,若查找不到则返回值为假。

2.lower_bound:查找第一个大于或等于某个元素的位置。
  a.函数模板:lower_bound(arr[],arr[]+size ,  indx):
  b.参数说明:
    arr[]: 数组首地址
    size:数组元素个数
    indx:需要查找的值
  c.函数功能:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置(注意是地址)。如果所有元素都小于val,则返回last的位置
  d.举例如下:
   一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标,则
   /*注意因为返回值是一个指针,所以减去数组的指针就是int变量了*/
   pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。
   pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。
   pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。
  e.注意:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!
      返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置
3.upper_bound:查找第一个大于某个元素的位置。
  a.函数模板:upper_bound(arr[],arr[]+size ,  indx):
  b.参数说明:
    arr[]: 数组首地址
    size:数组元素个数
    indx:需要查找的值
  c.函数功能:函数upper_bound()返回的在前闭后开区间查找的关键字的上界,返回大于val的第一个元素位置
    例如:一个数组number序列1,2,2,4.upper_bound(2)后,返回的位置是3(下标)也就是4所在的位置,同样,如果插入元素大于数组中全部元素,返回的是last。(注意:数组下标越界)
    返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置 。

3、代码

#include
#include
using namespace std;
int main()
{
    int a[100]= {4,10,11,30,69,70,96,100};
    int b=binary_search(a,a+9,4);//查找成功,返回1
    cout<<"在数组中查找元素4,结果为:"<<b<<endl;
    int c=binary_search(a,a+9,40);//查找失败,返回0
    cout<<"在数组中查找元素40,结果为:"<<b<<endl;
    int d=lower_bound(a,a+9,10)-a;
    cout<<"在数组中查找第一个大于等于10的元素位置,结果为:"<<d<<endl;
    int e=lower_bound(a,a+9,101)-a;
    cout<<"在数组中查找第一个大于等于101的元素位置,结果为:"<<e<<endl;
    int f=upper_bound(a,a+9,10)-a;
    cout<<"在数组中查找第一个大于10的元素位置,结果为:"<<f<<endl;
    int g=upper_bound(a,a+9,101)-a;
    cout<<"在数组中查找第一个大于101的元素位置,结果为:"<<g<<endl;
}

十、全排列

1、概念

从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。如果这组数有n个,那么全排列数为n!个。

比如a,b,c的全排列一共有3!= 6 种 分别是{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a}。

2、常用操作

1.头文件

#include 

2.使用方法

这里先说两个概念:“下一个排列组合”和“上一个排列组合”,对序列 {a, b, c},每一个元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b大,它的下一个序列即为{a, c, b},而{a, c, b}的上一个序列即为{a, b, c},同理可以推出所有的六个序列为:{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}没有上一个元素,{c, b, a}没有下一个元素。

1)next_permutation:求下一个排列组合
   a.函数模板:next_permutation(arr, arr+size);
   b.参数说明:
    arr: 数组名
    size:数组元素个数
   c.函数功能: 返回值为bool类型,当当前序列不存在下一个排列时,函数返回false,否则返回true,排列好的数在数组中存储

   d.注意:在使用前需要对欲排列数组按升序排序,否则只能找出该序列之后的全排列数。
    比如,如果数组num初始化为2,3,1,那么输出就变为了:{2 3 1} {3 1 2} {3 2 1}

2)prev_permutation:求上一个排列组合
   a.函数模板:prev_permutation(arr, arr+size);
   b.参数说明:
    arr: 数组名
    size:数组元素个数
   c.函数功能: 返回值为bool类型,当当前序列不存在上一个排列时,函数返回false,否则返回true
   d.注意:在使用前需要对欲排列数组按降序排序,否则只能找出该序列之后的全排列数。

3、代码

#include 
#include 
using namespace std;
int main ()
{
    int arr[] = {3,2,1};
    cout<<"用prev_permutation对3 2 1的全排列"<<endl;
    do
    {
        cout << arr[0] << ' ' << arr[1] << ' ' << arr[2]<<'\n';
    }
    while ( prev_permutation(arr,arr+3) );      ///获取上一个较大字典序排列,如果3改为2,只对前两个数全排列

    int arr1[] = {1,2,3};
    cout<<"用next_permutation对1 2 3的全排列"<<endl;
    do
    {
        cout << arr1[0] << ' ' << arr1[1] << ' ' << arr1[2] <<'\n';
    }
    while ( next_permutation(arr1,arr1+3) );      ///获取下一个较大字典序排列,如果3改为2,只对前两个数全排列
    ///注意数组顺序,必要时要对数组先进行排序

    return 0;
}

4、全排列递归思路

我们可以将这个排列问题画成图形表示,即排列枚举树,比如下图为{1,2,3}的排列枚举树,此树和我们这里介绍的算法完全一致;

算法思路:
(1)n个元素的全排列=(n-1个元素的全排列)+(另一个元素作为前缀);
(2)出口:如果只有一个元素的全排列,则说明已经排完,则输出数组;
(3)不断将每个元素放作第一个元素,然后将这个元素作为前缀,并将其余元素继续全排列,等到出口,出口出去后还需要还原数组;
代码:

public class hello {
    public static int arr[] = new int[]{1,2,3};
    public static void main(String[] args) {
        perm(arr,0,arr.length-1);
    }
    private static void swap(int i1, int i2) {
        int temp = arr[i2];
        arr[i2] = arr[i1];
        arr[i1] = temp;
    }

    /**
     * 对arr数组中的begin~end进行全排列
     * 
     * 比如:
     *     arr = {1,2,3}
     *  第一步:执行 perm({1,2,3},0,2),begin=0,end=2;
     *      j=0,因此执行perm({1,2,3},1,2),begin=1,end=2;
     *          j=1,swap(arr,0,0)-->arr={1,2,3},  perm({1,2,3},2,2),begin=2,end=2;
     *               因为begin==end,因此输出数组{1,2,3}
     *           swap(arr,1,1) --> arr={1,2,3};
     *           j=2,swap(arr,1,2)-->arr={1,3,2},  perm({1,3,2},2,2),begin=2,end=2;
     *               因为begin==end,因此输出数组{1,3,2}
     *           swap(arr,2,1) --> arr={1,2,3};
     *       j=1,swap(arr,0,1) --> arr={2,1,3},      perm({2,1,3},1,2),begin=1,end=2;
     *           j=1,swap(arr,1,1)-->arr={2,1,3}   perm({2,1,3},2,2),begin=2,end=2;
     *               因为begin==end,因此输出数组{2,1,3}
     *           swap(arr,1,1)--> arr={2,1,3};
     *           j=2,swap(arr,1,2)后 arr={2,3,1},并执行perm({2,3,1},2,2),begin=2,end=2;
     *               因为begin==end,因此输出数组{2,3,1}
     *           swap(arr,2,1) --> arr={2,1,3};
     *       swap(arr,1,0)  --> arr={1,2,3}
     *       j=2,swap(arr,2,0) --> arr={3,2,1},执行perm({3,2,1},1,2),begin=1,end=2;
     *           j=1,swap(arr,1,1) --> arr={3,2,1} , perm({3,2,1},2,2),begin=2,end=2;
     *               因为begin==end,因此输出数组{3,2,1}
     *           swap(arr,1,1) --> arr={3,2,1};
     *           j=2,swap(arr,2,1) --> arr={3,1,2},并执行perm({2,3,1},2,2),begin=2,end=2;
     *               因为begin==end,因此输出数组{3,1,2}
     *           swap(arr,2,1) --> arr={3,2,1};
     *       swap(arr,0,2) --> arr={1,2,3}
     *       
     */
    public static void perm(int arr[], int begin,int end) {
        if(end==begin){            //一到递归的出口就输出数组,此数组为全排列
            for(int i=0;i<=end;i++){
                System.out.print(arr[i]+" ");
            }
            System.out.println();
            return;
        }
        else{
            for(int j=begin;j<=end;j++){    
                swap(begin,j);        //for循环将begin~end中的每个数放到begin位置中去
                perm(arr,begin+1,end);    //假设begin位置确定,那么对begin+1~end中的数继续递归
                swap(begin,j);        //换过去后再还原
            }
        }
    }
}

你可能感兴趣的:(C++,STL)