• 第五章 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

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

  • 相关阅读:
    ZOJ 3818 Pretty Poem
    HDU 4597 Play Game
    HDU 4497 GCD and LCM
    CSU 1335 高桥和低桥
    UVA 10791 Minimum Sum LCM
    CSU 1119 Collecting Coins
    CSU 1120 病毒
    UVA 12169 Disgruntled Judge
    HDU 1301 Jungle Roads
    POJ 1258 Agri-Net
  • 原文地址:https://www.cnblogs.com/Miubai-blog/p/12882973.html
Copyright © 2020-2023  润新知