基本语法 auto:在C++中,auto可以自动推导类型。 1 2 3 4 5 #include <vector> std::vector <int > v; - for (std::vector::iterator it = v.begin ();it!=v.end ();it++) - for (auto vtest : v)
&为引用,加&与否取决于是否要修改原值或避免拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <iostream> #include <vector> std::vector <int > v{0 ,1 ,2 ,3 ,4 ,5 }; int main () { for (auto &v1:v) { v1 = v1+1 ; } for (auto v1:v) { std::cout<<v1<<std::endl; } }
建议都加std::
string
1 2 3 4 5 6 7 8 9 10 std::string a.find () std::string abbrevName (std::string name) { std::string s = "" ; s += toupper (name[0 ]); s += '.' ; s += toupper (name[name.find (' ' )+1 ]); return s; }
new和delete 释放动态的指针,如果释放一个值,就是delete p;如果释放的是一个数组,就是delete []p;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <iostream> using namespace std;int main () { int * p = new int (42 ); cout << "单个int: " << *p << endl; delete p; int * arr = new int [5 ]; for (int i = 0 ; i < 5 ; ++i) { arr[i] = i * 10 ; } cout << "数组内容: " ; for (int i = 0 ; i < 5 ; ++i) { cout << arr[i] << " " ; } cout << endl; delete [] arr; return 0 ; }
STL——set set 有insert,erase,count,find,size等用法,通常用于查找的时候不用find(因为要返回迭代器的值),而是用count,set底层是红黑树,可以实现自动除重,比如insert(6)两次,只会有一个,所以count()的值只会是0和1;用于判断是否存储在里面。
1 2 3 set.insert (); set.erase (); set.count ();
unordered_set和set大体上一样,但是是用哈希表实现的,所以里面是无序的,但是查找很快,O(1)级,set的查找是O(logN);
set插入vector的元素很方便,使用迭代器,同时通过assign分配新值给nums替换旧值。
1 2 3 4 5 6 7 8 class Solution {public : int removeDuplicates (vector<int >& nums) { set <int > s (nums.begin (),nums.end ()); nums.assign (s.begin (),s.end ()); return nums.size (); } };
给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution {public : bool containsDuplicate (vector<int >& nums) { int n = nums.size (); set <int > s; for (auto a:nums){ s.insert (a); } int ns = s.size (); if (n!=ns) return true ; return false ; } };
判断前后两次的size是否相同,不同则有重复插入。
map map是一个映射,由Key->Value,内部是用pair实现。 常见的用法有
m[] = ;
m.erase();
m.count(); //用于查找有没有值,return1/0; 可以看到map也像set一样会自动排序,且后来者会覆盖,count返回的是0和1。
冒泡排序 外层循环a.size()-1次,内层循环a.size()-i-1次;加引用和不加引用的区别在于:通过引用传递,函数内部对向量的修改会直接反映在原始向量上,这正是冒泡排序需要的效果,即直接在原数组上排序。
1 2 3 4 5 6 7 8 9 10 11 12 void bubble (vector<int > &a) { for (int i = 0 ;i<a.size ()-1 ;i++){ for (int j = 0 ;j<a.size ()-1 -i;j++){ if (a[j]>a[j+1 ]){ int temp = a[j+1 ]; a[j+1 ] = a[j]; a[j] = temp; } } } }
指针 指针是一种数据类型 ,在32为系统性size = 4,64 = 8.指针存放的是内存
意思是p指针现在存储的是a的地址,可以使用解引用号来访问*p存储的这个地址的值 。
常量指针 const为常量,加在指针前就称之为常量指针 const int *p
1 2 3 4 int a = 10 ;int b = 20 ;const int *p = &a;*p = 200 ;
这是一个非法的操作 ,常量指针可以改变指向的地址 ,但不能改变指向地址的值 。
1 2 3 4 int a = 10 ;int b = 20 ;const int *p = &a;p = &b;
这是一个合法的操作,现在p指向的就是b的地址。
指针常量 1 2 3 int a = 0 ;int b = 0 ;int * const p = &a;
指针常量和常量指针作用刚好相反,要这样理解:const后面跟着谁谁就无法改变 ,在指针常量中,int *const p,const后面跟着的是地址,所以地址就不能改;在常量指针中,const int *p,const后面跟的是int值,所以值不可以改。 所以当const int *const p两个都不可以改。快速记忆:遇到英文翻译中文,const int *p,const是常量,后面是指针,所以常量指针;int *const p,先遇到指针,再遇到常量,所以叫指针常量。
引用 引用就是取别名,本质是指针,让b的地址和a的地址相同,但记住在这里引用类似于常量指针,不允许再更改成其他的地址了,但可以改值。引用必须初始化 。
引用不要返回局部变量 1 2 3 4 5 6 7 8 9 10 11 int &test () { int a = 10 ; return a; } int main () { int &ref = test (); cout<<ref; }
第一次的时候可以正常输出10,但第二次就不行了,因为局部变量存放在栈区,会被释放。
1 2 3 4 5 6 7 8 9 10 11 int &test () { static int a = 10 ; return a; } int main () { int &ref = test (); cout<<ref; }
static关键字让他是静态变量,存放在全局区 ,全局区上的数据在程序结束后释放。
类和对象 类有属性 和行为 ,比如一个学生类,属性就是学生的名字/学生的学号,行为就是打印出名字和学号,也可以用行为来给学生的属性赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class student { public : int m_num; string m_name; void Print () { cout<<m_num<<" " <<m_name; } void GetNum (int num) { m_num = num; } void GetName (string name) { m_name = name; } };
成员私有化之后可以实现只读/只写/可读可写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class student { private : int m_age = 18 ; string m_name; string m_lover; public : void get_age () { cout<<m_age<<endl; } void set_age (int age) { if (age>150 ||age<0 ){ return ; } m_age = age; } }; int main () { student s; s.set_age (160 ); s.get_age (); }
圆类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 #include <iostream> using namespace std;class point { public : void setm_x (int x) { m_x = x; } int getm_x () { return m_x; } void setm_y (int y) { m_y = y; } int getm_y () { return m_y; } private : int m_x; int m_y; }; class circle { public : void setm_r (int r) { m_r = r; } int getm_r () { return m_r; } void setm_center (point p) { m_center = p; } point getm_center () { return m_center; } private : int m_r; point m_center; }; void Relation (circle &c,point &p) { int dx = c.getm_center ().getm_x ()-p.getm_x (); int dy = c.getm_center ().getm_y ()-p.getm_y (); cout<<dx<<" " <<dy; int rdistance = c.getm_r ()*c.getm_r (); int distance = dx*dx+dy*dy; if (distance==rdistance){ cout<<"在圆上" ; } else if (distance>rdistance){ cout<<"在圆外" ; } else cout<<"在圆内" ; } int main () { point p; circle c; c.setm_r (10 ); point center; center.setm_x (10 ); center.setm_y (0 ); c.setm_center (center); p.setm_x (10 ); p.setm_y (10 ); Relation (c,p); }
构造函数与析构函数 没有返回值,不用写void,函数名与类名相同,构造函数可以有参数,可以发生重载,创建对象的时候会自动调用,而且只调用一次。 析构函数前加一个~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class person { public : person () { cout<<"构造" ; } ~person () { cout<<"析构" ; } }; int main () { person p; person p1; }
继承 可以省略冗余的代码,继承父类。 继承语法: class 子类 : 继承方式 父类 class cpp : public header ; ; 子类可以缩小权限范围,但不能扩大权限范围。
类初始化 类初始化在构造函数后面打一个冒号
1 2 3 4 5 6 class circle {public : Point (int xx,int yy):x (xx),y (yy); private : float x,y; };
上面这一行代码等价于下面这一行代码
1 2 3 4 5 6 7 8 9 10 11 12 13 class Point { public : Point (int xx, int yy) { x = xx; y = yy; cout << "Constructor of Point" << endl; } private : float x, y; };
但是区别不同 上面两段代码对应于初始化类成员的两种方式:(1)使用初始化列表;(2)在构造函数体内进行赋值操作。 但严格来说,上面两段代码只是能实现相同的功能(初始化Point类的对象),它们的本质并不相同,下面来说明原因。 构造函数的执行分为两个阶段: (1)执行初始化列表:初始化类中的数据成员; (2)执行构造函数体:一般是对类中的数据成员进行赋值操作。 初始化与赋值是不同的,所以上面两段代码只是功能上相同,但本质并不相同,前一个是初始化,后一个是赋值。
STL–deque deque(double ended queue)双端队列 好处:两端都开口 ,想要在头部插入元素很方便。
有四种拷贝构造
dequedeqT 默认构造
dequed1(d); 拷贝构造
dequed2(d.begin(),d.end()) 把[begin,end)区间的元素给d2
dequed3(10,100) //10个100 将n个elem拷贝给自身
有三种赋值
deque d = d1 等号赋值
deque d3; d3.assign(d1.begin(),d1.end())
d3.assign(10,100) 给10个100 和vector一样。
大小 函数原型: deque.empty(); //判断容器是否为空 deque.size(); //返回容器中元素的个数 deque.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。 deque.resize(num, elem);//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。
插入和删除 两端插入操作: push_back(elem); //在容器尾部添加一个数据 push_front(elem); //在容器头部插入一个数据 pop_back(); //删除容器最后一个数据 pop_front(); //删除容器第一个数据 指定位置操作: insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置。 insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值。 insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值。 clear();//清空容器的所有数据 erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置。 erase(pos); //删除pos位置的数据,返回下一个数据的位置。
排序 sort(d.begin(),d.end())
STL–queue 先进先出,很像尾插法。不允许遍历!只能访问队头队尾! 入队:q.push() 出队:q.pop() 基本操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <iostream> using namespace std;bool compare (int a, int b) { cout << "compare_int_int" << endl; return a > b; } bool compare (double a, double b) { cout << "compare_double_double" << endl; return a > b; } const char * a = "hello" ; bool compare (const char *a, const char *b) { cout << "compare_char*_char*" << endl; return strcmp (a,b)>0 ; } int main () { compare (10 , 20 ); compare (10.0 , 20.0 ); compare ("aaa" , "bbb" ); }