第五章 C++与STL入门

第五章 C++与STL入门

学习目的:

C++博大精深,相应的也伴随着许多让人诟病的地方,对于参加算法竞赛来说,掌握一些C++的特性将事半功倍的效果。

1. 从C到CC++

  1. C++头文件的变更,即 在C的头文件前面加上一个小写字母c,然后去掉后缀.h,例如C语言头文件stdio.h在C++里面就变成了cstdio.

  2. C++特有的头部文件,标准输入输出流 iostream ,存在于名称空间std中。

    • 当然C++流不是完美的,最大的缺点就是运行太慢,当输入量大时,请不要使用C++流输入
    • 其次,解释下using namespace std的意思。C++有“名称空间(namespace)”的概念,用于缓解复杂程序的组织问题。将函数写到各自的名称空间里,然后调用。就相当于给其划定了“驻扎区”,要调兵时,直接对某驻扎下达命令就行了。如果代码和该名称空间的内容不重名,就可以用using namespace std的方法,将std里的名字导入到默认空间
    //推荐使用写法,使用using namespace std语句的方式
    #include <iostream>
    using namespace std;
    
    int main(){
        int n;
        cin >> n;//从输入流中读取一个int类型的数存放于n
        cout << n << endl;//输出n的值,并换行
        return 0;
    }
    
    //不用using namespace std语句的方式书写
    #include <iostream>
    
    int main(){
        std : :cin >> n;
        std : :cout << n << endl;
        return 0;
    }
    
    • 强调一点头文件iostream和提供常用算的头文件algorithm 里面定义的内容都是放在std名称空间里的
    //min函数就是在头文件algorithm中的
     #include <iostream>
     #include <algorithm>
     
     int main(){
         int a,b;
         cin >> a << b;
         cout << min(a,b) << endl;
         return 0;
     }
    
  3. 声明数组时,数组大小可以使用const声明的常数(C99中不允许),在C++中,更推荐这种写法

  4. C++与C最显著的区别就是多了个bool来表示布尔值,然后用true和false来分别表示真假,相对于用int值来表示真假来说,这样写更使得程序清晰。这里在注意一点Java中int值不能用来判断真假

  5. "引用":C++里面如果,在参数名前面加一个"&"符,就表示这个参数按照“传地址”的方式传递,而不是C语言中的传值传入。所以,在函数内改变的值也会修改函数的实参。C++中的引用就是变量的“别名”,它可以在一定程度上代替C的指针

  6. C++在sting 头文件里定义了string类型,直接支持流式读写,string有很多方便的函数和运算符,但速度较慢。另外string类型还可以像整数那样“相加”。

  7. stringstream在头文件sstream中,虽然它们很方便,但是sstreamstream更慢,应该谨慎使用。

  8. C++里面除了修改了C结构体的部分内容,同时还支持class类。一般用struct定义“纯数据类型,而class定义的是”拥有复杂行为“的类型。简单来说,复杂的内容用class就对了。

  9. C++中的结构体除了可以拥有成员变量(用a.x的方式来访问)之外,还可以拥有成员函数(用a.add(12的方式访问))。C++里sturct的很多概念和写法同样适用于class

  10. C++中结构体可以有一个或多个构造函数,在声明2变量是调用。

  11. C++中的函数(不只是构造函数)参数拥有默认值。

  12. 在C++结构体的成员函数中this是指向当前对象的指针,这一点结合java中this的用法及含义就明白了。

#include<iostream>
using namespace std;

struct Point{
    int x,y;
    
   //这样的函数称为构造函数,"=0"就是设置了0为默认值,如果这两个参数没有被指明,则就按照0来处理。
    Point(int x = 0 , int y  = 0) : x(x),y(y)){}//这里的x(x),相当于this.x = x
        
};

//"+"运算符的重载,重新定义了 "+"运算符。
Ponitn operator + (const Point& A,const Point& B){
    return Point (A.x+B.x,A.y+B.y);
}
  1. 模板:函数、结构体和类是可以带模板的。修改原有的函数,增加其使用范围,用法如下
//套用上面的结构体,就能使得其适用的范围更广
template <typename T>
struct Point {
    T x,y;
    Point (T x = 0 , T y = 0):x(x),y(y){}
}
//更改以后,就可以同时使用int型和double型的Point了

STL初步

STL是指C++标准模板库(Standard Template Library)。

排序与检索

  1. algorithm头文件中sort可以给任意对象排序,包括内置类型和自定义类型,前提是定义了"<"运算符。排序后可以用lower_bound查找大于或者等于x的第一个位置。待排序/查找的元素可以放在数组里,也可以放在vector里。

  2. sort的使用:sort(a,a+n),表示对a数组的前n个元素进行排序。当然,在vector中调用方式就为sort(v.begin() , v.end())

不定长数组 : vector

  1. `vector`是个不定长数组,具有”封装“的特性,如果`a`是个`vector`,那么可以用`a.size()`来读取它的大小,`a.resize()`来改变大小,`a.push_back()`像尾部添加元素,`a.pop_back()`来删除最后一个元素。

  2. `vector`是一个模板类,所以需要用`vector<int>a`或者`vector<double>b`这样的方式来声明一个`vector`。`vector<int>`是一个类似于`int a[]`的整数数组,而`vector<string>`就是一个类似于`string[]`的字符串数组。

  3. 取出指令之间的共同点,编写函数减少代码,是一种值得推荐到方法。

  4. `vector`头文件中的`vector`是一个不定长数组,可以用`clear()`清空,`push_back()`和`pop_back()`在尾部添加和删除元素,用`empty()`测试是否为空,`vector`之间可以直接赋值或者作为函数的返回值。

集合:set

  1. set就是数学上的集合,——每个元素最多出现一次。就和sout一样,自定义的类型就可以构造set,当必须定义”小于”运算符。

  2. iterator的意思是迭代器,是STL中的重要概念,类似于指针。

  3. set的全面用法参考C++参考手册

    //set的用法
    #include <iostream>
    #include <set>
    
    using namespace std;
    
    int mian(){
        set<int>s; //定义一个空集合s
        for(int i = 0; i < 8; i++){
            s.insert(i); //将i的值插入到集合s中
        }
        
        for(auto it = s.begin();it != s.end(); it++){
            cout << *it << endl; //输出s集合中所有的元素。注意,制力有一个 "*"。
        }
        if(s.find(5) != s.end() ) {  	//表示能找到5,因为s.end()表示的是最后一位元素的后一位。
            cout << "Found 5" << endl;
        }else {
            cout << "Not Found" << endl;
        }
    }
    
    

映射:map

  1. map就是键到值的映射,就类似于身份标记。map会自动将所有的键值对按照键从小到大的排序

  2. map重载了[]运算符,map像是数组的“高级版”

  3. set头文件中的setmap分别就是集合与映射。二者都支持insertfindcountremove操做。并且可以按照从大到小的顺序循环遍历其中的元素。map还提供了"[]"运算符,使得map可以像数组一样使用。事实上,map也成为“关联数组”

    //mapp的用法
    #include <iostream>
    #include <map>
    #include <string>
    using namespace std;
    int main(){
        map<string , int>m //定义一个新的键值对,键是string类型的,值是int类型。
        m["Miubai"] = 1234567;//将键为 "Miubai",值为 "1234567"的值放入map中
        cout << m["Miubai"] << endl;//输出map中Miubai所对应的值
        //遍历,输出map所有元素,键使用it->first获取,值用it->second获取
        for (auto it = m.begin(); it != m.end();i++){
            cout << it->first << " " << it->second << endl;
        }
        //输出map的第一个元素,输出它的键和值
        cout << m.begin()->first << " 值是 " << m.begin()->second << endl;
        //输出map元素的最后一个元素,及其键和值
        cout << m.rbegin->first << "值是" << m.rebin->second << endl;
        //输出map元素的个数
        cout << m.size() << endl;
        return 0;     
    }
    
    

栈、队列与优先队列

  1. 栈:就是符合“后进先出”的规则的数据结构。有压栈(PUSH)和弹栈(POP)两种操作。弹栈是将栈顶元素弹出。

  2. STL的栈定义在头文件stack中,用stack<int>s的方式定义,用push()pop()实现元素的入栈和出栈操做。top()取出栈顶元素(但不删除)。

    //栈的用法
    #include <iostream>
    #include <stack>
    using namespace std;
    int main() {
        stack<int>s;//定义一个空栈S
        for(int i = 0;i < 9;i++){
            s.push(i*20);//将i*20的值压栈进入栈s中
        }
        cout << s.top() << endl; //访问s的栈顶元素
        cout << s.size() << endl;//输出s的元素个数
        s.pop()//移除栈顶元素
         return 0;
    }
    
    
  3. STL的queue头文件提供了队列,用queue<int>s方式定义,用push()pop()进行元素的入队和出队操做,front()取出首元素(同样也不会删除)。

  4. STL的优先队列也定义在文件<queue>里,用priority_queue<int>pq来声明。其中pq是一个“越小的整数优先级越低的优先队列”。由于出对元素并不是最先进队的元素,出队的方法由queuefront()变成了top()

    //queue的使用
    #include <iostream>
    #include <queue>
    using namespace std;
    int main() {
        queue<int>Q //定义一个空队列Q
        int n;
        for(int i = 0; i < 10;i++){
            cin >> n;
            Q.push(n);//将n的值压入队列Q中
        }
        cout << Q.front() << "队尾元素:" << Q.back() << endl; //访问队首元素和队尾元素
        cout << Q.size() << endl; //输出队列元素的个数
        q.pop();//移除队列队首元素
        return 0;
    }
    

测试STL

库不一定没有bug,使用之前要养成测试库的好习惯

  1. 随机数发生器,其核心函数是ctdlib中的rand()。它能生成一个闭区间[0,RAND_MAX] (RAMND_MAX至少为32767)内的均匀随机整数,即该区间每个值被随机获取的概率一样。测试STL,此函数能提供不少的帮助。
  2. 不要在同一个程序每次生成随机数之前都重新调用一次srand,务必只在程序开头调用一次srand,而不要在同一个程序中多次调用。
  3. 可以用cstdlib中的srand函数初始化随机种子。如果需要程序每次执行时使用一个不同的种子,可以使用ctime中的time(NULL)为参数调用的srand,这样,在不同时间生成的随机数都是不一样的。一般来说,只在程序开头调用一次srand

文中部分参考过柳婼 の 的博客

原文地址:https://www.cnblogs.com/Miubai-blog/p/12882973.html