C++知识
- 概念
1 面向对象与面向过程区别
- 面向过程就是将事物分为不同的步骤,根据这些步骤去完成编程。面向对象的设计思路则是将问题分解成各个对象,并给对象赋予属性和行为
- 由于面向对象有三大特性:封装、继承、多态。也就带来了三个特点:易维护、易复用、易扩展。但因为类调用时需要实例化,所以性能方面比较低。
2 封装,隐藏内部实现
继承,复用现有代码
多态,根据你传入的不同对象,去做同一样的事情,产生不同的结果和行为
- 运行时多态: 继承中要构成多态的两个条件:
a.必须通过基类的指针或者引用调用虚函数;
b.派生类必须对基类的虚函数进行重写(相同函数名,参数,返回值); - 编译时多态(静态多态),通过函数重载或函数模板实现,重载是同一作用域中声明几个同名函数,这些同名函数的形参列表(个数,类型,顺序)必须不同
3 指针: 1) int a; int *p; p = &a;
指向类的指针访问成员与结构体一样用->
2) 初始化指针时所创建的字符串常量被定义S为只读。如果试图通过指针修改这个字符串的值,程序就会出现未定义的行为。通过字符串数组chars[]="AAA"定义可以通过s[]修改
Eg: char* s="AAA"; s[0]='B'(错误,s为常量);
- C++指针用-> Java指针用.
4 结构体
- Struct的默认成员和继承属性是公有;class的默认成员和继承属性是私有
2)c++中类和c语言中struct的区别:
a. c++中的类默认的成员是私有的,struct默认的是共有的。
b. c++中的类可以定义成员函数,struct只能定义成员变量。
5 范围解析运算符 ::
:: 运算符之前必须使用类名。类用:: 对象用 .
6 public private protected
- public修饰的成员变量在程序的任何地方都可以由类的实例直接访问,不需要通过成员函数。
- private修饰的成员变量只有类内可直接访问(可以被友元函数访问),私有的,类的实例要通过成员函数才可以访问,这个可以起到信息隐藏
- protected是受保护变量,类内和子类可直接访问,但类的实例需要通过成员函数才能访问,也就是说,基类中有protected成员,子类继承于基类,那么也可以访问基类的protected成员,要是基类是private成员,则对于子类也是隐藏的,不可访问
- 在public公有派生下,继承而来的成员访问权限不变.protected派生下,public和protected都变成protected,private派生下,所有的继承下来都是private了
- 普通成员变量如果是每个对象私有的,一般通过类的构造函数进行赋值,
构造函数名字与类名相同
静态成员在类外定义 无论创建多少个类的对象,静态成员都只有一个副本
静态常成员变量:可以直接在类中初始化和声明,在类定义体外进行定义
7 构造函数和拷贝构造函数 classname (const classname &obj) { }
1)类的构造函数在创建一个新的对象时调用,用于新建对象的初始化工作。类的析构函数在删除对象时调用,完成一些清理工作,比如:释放内存等。
构造函数:
2)构造函数可以是私有的(private);一个类中可以有多个构造函数;无论何时,只要类的对象被创建,就会执行构造函数;构造函数没有返回类型;
3)当基类指针指向派生类的时候,构造函数,会首先构造父类构造函数,再构造子类构造函数,而在析构时,只析构父类的析构函数:基类构造->子类构造->基类析构。
4)当派生类指针指向派生类的时,基类构造->子类构造->子类析构->基类析构。
5)当基类指针指向派生类的时,如果类函数为是虚函数的时候,则访问派生类的函数,如果类函数不是虚函数,则调用基类函数。
6)父类的虚析构的作用是什么:防止内存泄露,防止在用父类的指针 *** 作派生类对象后,在析构的时候只回收了基类的资源,没有析构派生类函数。
10) MyClass c1,*c2; MyClass *c3=new MyClass; MyClass &c4=c1;
c1要调用一次构造函数;c2只是一个指针,用来动态描述对象,不会调用类的构造函数;c3的右边新创建一个对象会调用构造函数。c4是一个对象引用,是c1的一个别名,所以不会调用构造函数
8 C++中定义一个空类,编译器可能会加什么:
默认构造函数
析构函数
拷贝构造函数
赋值运算符(operator=)
取址运算符(operator&)(一对,一个非const的,一个const的)
当然,所有这些只有当被需要才会产生。
9 C++ 接口(抽象类)
- C++接口是使用抽象类来实现的,如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。抽象类不能实例化出对象。其派生类只有重写纯虚函数,才能实例化出对象。纯虚函数也规范了派生类必须重写。
- 纯虚函数是指在基类中声明的虚函数,它在基类中没有定义,但要求派生类中都要定义自己的实现方法。方法是函数原型后加“=0”eg:
virtual void funtion1()=0;
10、变量的声明和定义区别:
声明变量不分配空间,定义变量要分配空间。声明主要是告诉编译器,后面的引用都按声明的格式。定义其实包含了声明的意思,同时要分配内存空间。
11、memset ,memcpy 的区别:
memset用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为’\0′。 memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;
12、程序什么时候使用线程,什么时候单线程效率高:
1) 耗时的 *** 作使用线程,提高应用程序响应
2) 并行 *** 作时使用线程,如C/S架构的服务器端并发线程响应用户的请求。
3) 多CPU系统中,使用线程提高CPU利用率
4) 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。其他情况都使用单线程。
13、介绍一下模板和容器。如何实现?(也许会让你当场举例实现)
【参考答案】: 模板可以说比较古老了,但是当前的泛型编程实质上就是模板编程。 它体现了一种通用和泛化的思想。 STL有7种主要容器:vector,list,deque,map,multimap,set,multiset.
vector: 向量容器, 获取元素效率很高,插入和删除的效率很低,支持下标访问和vector.at() *** 作。连续内存,便于随机存取,超过内存,整体重新分配拷贝。
deque: 双向队列容器, 获取元素效率较高,插入和删除的效率较高。底层数据结构:类似一个二维数组的缓冲区,缓冲区指的是后面实际存储数据的地方。
list : 双向列表, 增加和获取元素效率很低,插入和删除的效率很高
set : 集合, 键(关键字)和值(数据)相等, 键唯一,元素默认按升序排列,底层用红黑树(平衡二叉树),便于查找。
unordered_set底层是哈希表,元素无序唯一,插入、删除、查找元素的时间是常量
multiset :多重集合, 1.键和值相等,键可以不唯一,元素默认按升序排列
map : 映射, 键和值分开, 键唯一, 元素默认按键的升序排列,底层红黑树
multimap: 多重映射, 键和值分开, 键可以不唯一, 元素默认按键的升序排列
1、如果你需要高效的随机存取,而不在乎插入和删除的效率,使用vector。
2、如果你需要大量的插入和删除,而不关心随机存取,则应使用list。
3、如果你需要随机存取,而且关心两端数据的插入和删除,则应使用deque。
4、如果你要存储一个数据字典,并要求方便地根据key找value,那么map是较好的选择。
5、如果你要查找一个元素是否在某集合内存中,使用set存储这个集合比较好。
14、内存的分配方式的分配方式有:
1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
附:C/C++内存模型:
4) C++派生类内存分配:C++ - 类的内存分配_bailang_zhizun的博客-CSDN博客_c++ 类的内存分配
- 对象obj的地址和第一个成员变量 m1 的地址是一样的,m2地址=m1地址+ 4
- 成员函数的地址是和成员变量的地址是没有关系的,而且各成员函数的关系也没有一定的关联性。但static修饰的静态变量:不占用内容,放在静态区。
- 当类中包含了虚函数时,该类就自动包含了一个 vptr指针(指向虚函数表的指针),通常vptr指针存放在类对象内存空间的首地址,也即是类对象的地址。其中虚函数表中存放了指向该类中定义的所有的虚函数的指针(函数指针)
- 派生类先存放基类的成员变量,然后再存放自己(派生类)的成员变量,成员函数的地址依然没有什么关联。
- 派生类不重写基类虚函数:派生类不继承基类的vptr指针,只有一个自己的vptr指针,但是在派生类的虚函数表中,存储的继承自基类的虚函数指针与基类中存储的虚函数指针完全一致,这说明,如果派生类没有重写基类的虚函数,那么在进行多态 *** 作时,如果调用派生类的虚函数(与基类同名的虚函数),是不会发生多态行为的,调用的仍然是基类的虚函数!
- 当派生类重写了基类的虚函数时,也只有一个自己的vptr指针,虚函数表中存放的虚函数指针是不一样的。
- 含有虚函数的类的多重继承,有多个vptr指针,成员变量放在对应vptr下面,派生类自己的成员变量放最后。
15如何处理内存泄漏
- 单例造成的内存泄漏, 由于单例的静态特性使得其生命周期和应用的生命周期一样长,长生命周期对象持有短生命周期对象导致短生命周期对象无法被回收。从而导致了内存泄漏。 方法:把当前类的上下文,改为application就行。
- 集合容器中的内存泄露 方法: 退出程序前,clear集合里的东西,置为null
- 资源未关闭内存泄漏 方法: 不使用的时候,调用它的close()函数将其关闭
- 线程造成的内存泄漏 方法:使用静态内部类
- 非静态内部类创建静态实例造成的内存泄漏,重复创建相同的数据资源。
- 使用ListView造成的内存泄漏 方法:使用缓存的convertView构造Adapter
附:如何检测:
- Visual Studio系列IDE中,可使用_CrtSetDbgFlag函数来检测内存泄漏,在刚进入main函数时调用,可检测在_CrtSetDbgFlag(...)和return 0之间的所有内存泄漏
- 对象计数:在对象构造时计数++,析构时–,每隔一段时间打印对象的数量。
- 使用微软的detours库,hook分配内存的系统Api:HeapAlloc/HeapRealloc/HeapFree(new/malloc的底层调用),记录分配点,定期打印。
- 使用DiagLeak检测,微软出品的内存泄漏分析工具
15 static关键字在局部变量、全局变量以及类中变量、函数间的作用及区别
局部变量变静态变量后改变为静态存储方式,改变了其生命周期。只初使化一次
全局变量改变为静态变量后是改变作用域,只能在本文件使用,本程序外文件不能用。全局变量和static全局变量都只初使化一次。
static函数与普通函数 作用域不同。仅在本文件中使用。static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
类中静态数据/函数成员是属于整个类的,而不是属于某个对象,故静态数据成员必须在类外初始化。静态成员函数只能访问静态成员,不可以访问非静态成员
static 成员变量是在初始化时分配内存的,程序结束时释放内存。
15头文件中的 #ifndef/#define/#endif : 预处理, 防止头文件被重复引用
16 1) new、delete、malloc、free关系
【答】: delete会调用对象的析构函数,和new对应free只会释放内存,new调用构造函数。malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
2) malloc映射到内存的话主要是调用mmap()和munmap()显示的分配和释放堆内存,或者使用sbrk()函数。sbrk()函数将通过内核的brk指针增加incr来扩展和收缩堆。涉及到是mmap()、munmap()、sbrk()函数都是内核上的函数,当程序使用malloc申请内存的时候,就直接调用系统函数,然后映射到对应的虚拟地址空间。
17 虚函数:
17.1虚函数的作用是多态:调用同一个函数名,可以根据需要但实现不同的功能。主要是运行时多态。
- 若要访问派生类中相同名字的函数,必须将基类中同名函数定义为虚函数,这样,将不同的派生类对象的地址赋值给基类指针变量后,就可以动态的调用不同类中的函数。
- 在派生类中重新定义基类中的虚函数时,可以不用关键字virtual来修饰这个成员函数。
- 构造函数中虚函数不起多态作用
- 在程序执行过程中,依据指针具体指向哪个对象,或依据引用哪个类对象,才能确定激活哪个版本,实现动态聚束。
17.2 设置虚函数须注意:
1) 只有类的成员函数才能说明为虚函数;普通函数不能被继承
2) 静态成员函数不能是虚函数;
3) 内联函数不能为虚函数;
4) 构造函数不能是虚函数,构造函数中虚函数不起作用。
5) 析构函数可以是虚函数,而且通常声明为虚函数。
6) 虚析构的作用是什么:防止内存泄露,防止在用父类的指针 *** 作派生类对象后,在析构的时候只回收了基类的资源,没有析构派生类函数。
18 浅拷贝和深拷贝
浅拷贝就是只拷贝一层,就相当于把一个对象中的所有的内容,复制一份给另一个对象,直接复制,或者说,就是把一个对象的地址给了另一个对象,他们指向相同,两个对象之间有共同的属性或者方法,都可以使用
深拷贝就不会像浅拷贝那样只拷贝一层,而是有多少层我就拷贝多少层,要真正的做到全部内容都放在自己新开辟的内存里。可以利用递归思想实现深拷贝,把一个对象中所有的属性或者方法,一个一个的找到,并且在另一个对象中开辟相应的空间,一个一个的存储到另一个对象中.
19 C++11特性
- C++11通过新增一个关键字final:解决了基类不可以被继承问题, 也就是不需要设计基类的构造函数为私有的;final关键还可以修饰基类的虚函数,目的就是为了使得基类的虚函数不被子类重写;
- override 有检查机制,帮你检查你的派生类是否正确的重写了基类的虚函数;
- auto的原理就是根据后面的值,来自己推测前面的类型是什么。
20 智能指针的概念。智能指针的行为类似常规指针,区别是它负责自动释放所指向的对象,避免指针的内存泄漏和非法引用。标准库有多种智能指针:
- shared_ptr采用引用计数的智能指针,允许多个指针指向同一个对象,当所有shared_ptr都全部释放时,该处资源才释放。有某个对象的所有权(访问,控制),是强引用指针。内部实现: 每次复制,多一个共享同处资源的shared_ptr时,计数+1。每次释放shared_ptr时,计数-1。
附:shared_ptr指针和引用计数是线程安全的,但指针所指对象中的 *** 作就需要自己做控制,并不是线程安全的。
- unique_ptr“独占”所指向的对象。只允许基础指针的一个所有者。以移到新所有者,但不会复制或共享。
- weak_ptr不参与引用计数,weakptr 提供对一个或多个 sharedptr 实例拥有的对象的访问,可以解决循环引用的问题。适合观察某个对象但不需要其保持活动状态。
25、如何让局部变量具有全局生命期:
用static修饰就可以了,但是只是生命期延长,范围并没有扩大。
26 C和C++ const区别:
- 在C中,const不是常量,只能说是一个不能改变的变量C编译器不知道他在编译期间的值。所以不能作为数组定义时的下标(C++可以),因下标必须为常量。
- 在C中,const int a;是可以的,因为这只是声明一个变量,告诉编译器,我这里是声明,指明在别的地方有内存分配。但在C++中这样写是不正确的,C++中const默认是内部链接,C中默认是外部链接
27 1) 静态链接的缺点
a 同一个模块被多个模块链接时,那么这个模块在磁盘和内存中都有多个副本,导致很大一部分空间被浪费了。
b 当程序的任意一个模块发生更新时,整个程序都要重新链接、发布给用户。
2) 动态链接: 把链接这个过程推迟到了运行时再进行。因为动态链接器的帮助,可以只是记录动态链接符号,而不需要将动态链接共享文件纳入到最终的可执行文件中, 可以等到程序要运行时才进行链接。
28 strtok函数在使用上要注意什么问题。
【答】: 这个函数的作用是分割字符串,但是要分割的字符串不能是常量,比如先定义一个字符串:char array[]=”part1,part2″;,strtok的原形是char *strtok(char *string, char *delim);,我们将”,”作为分隔符,先用pt=strtok(array,”,”);,得到的结果print出来就是”part1″,那后面的呢,要写成pt=strtok(NULL,”,”);,注意,要用NULL,除第一次使用指向字符串的指针外,之后的都要使用NULL。
29 用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年)
【答】:#define SECONDSPERYEAR (60 * 60 * 24 * 365)UL
这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数,UL表示无符号长整型。
30、什么是预编译,何时需要预编译:
(1) 总是使用不经常改动的大型代码体
(2) 程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个预编译头
31 extern关键字定义外部变量
问: C++里面如何声明const void f(void)函数为C程序中的库函数?
答:在该函数前添加extern“C”声明。由于C++重载,C和C++编译后的名字不同,C++程序不能直接调用C函数。
33、char * const p char const * p const char *p 上述三个有什么区别?
char * const p; //常量指针,p的值不可以修改
char const * p;//指向常量的指针,指向的常量值不可以改
const char *p; //和char const *p
34 程序基础
- 有符号整数和无符号整数运算都化为无符号整数再运算。
- vector
a; sizeof(a) vc答案是16(收尾迭代器 存储空间迭代器 对齐)
35 1) 迭代器失效实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间.
- 数组型结构(vector、deque等)由于分配连续内存,当进行insert和erase *** 作,插入点和删除掉之后的迭代器全部失效。解决方法就是更新迭代器,对于删除,erase()返回的是下一个有效迭代器的值,可以通过iter=vec.erase(iter);来避免迭代器失效。insert同理,insert返回的是插入元素的迭代器的值。
- 针对链表型数据结构(list容器),使用了不连续分配的内存,删除运算使指向删除位置的迭代器失效,但是不会失效其他迭代器。解决办法有两种,一种是erase(iter)会返回下一个有效迭代器的值,可以通过iter=vec.erase(iter);来避免迭代器失效,另一种方法是通过erase(iter++);来避免迭代器失效,
38 COM是组件对象模型,它定义了一种二进制标准,使得任何编程语言存取它所编写的模块。组件与编程语言无关,编译后组件以二进制形式发布。通过接口有效保证组件的复用性,组件运行高效,便于使用和管理。
39 #include与#include“file.h”的区别:
前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。
二、C++编码
1 Q∶一闪而过
A∶1) system("pause")加头文件stdlib.h或cstdlib //oj可能有影响
2 ) C中,使用 getchar(); C++中,使用cin.get()
2 字符串∶http://c.biancheng.net/view/400.html
2.1 #include
strcpy(s1,s2); 复制字符串s2 到字符串s1的末尾
Strcat(s1,s2); 连接字符串s2 到字符串 s1的末尾。
strlen(s1); 返回字符串s1的长度。
strcmp(s1, s2); 如果 s1和 s2是相同的,则返回 0;如果 s1 strchr(s1, ch); 返回一个指针,指向字符串s1中字符ch第一次出现的位置,没有就返回NULL strstr(s1, s2); 返回一个指针,指向字符串s1中字符串s2第一次出现的位置,没有就返回加NULL strtok_s 分割字符串(strtok线程不安全) eg: string str = "now # is the time for all # good ,men to come"; //缓冲块首地址 char arr[200]; strcpy_s(arr, str.size() + 1, str.c_str());//string类str1转字符数组arr char delims[] = "#, "; //分隔符数组,可含多个分隔符 char *p = nullptr; //指向将被处理的单词 char *next = nullptr; //保存缓冲块中下一个将被读取的单词的位置 p = strtok_s(arr, delims, &next); while (p != NULL) { cout << p << "@"; p = strtok_s(nullptr, delims, &next); }//nullptr为解决NULL重载时代指空指针存在的二义性问题 char arr[MAX]=""; strcpy_s(arr, MAX, inputStr.c_str());//需查一下 2.2 #include string类:复制用= ; 连接用+ ; 长度用.size(); string str1 ="Hello"; str3 = str1; str3=str1+str2; len = str3.size(); if(str1== str); //字符串是否相等 s1.append(s2); //字符申连接 s.append(c, 3); //把c类型字符串s的前n个字符连接到当前字符串结尾s1.append(s2, 5,5);//把字符串s2中从5开始的5个字符连接到当前字符串的结尾 s1.append(4,'!'); //在当前字符串结尾添加4个字符! 比较 int n=s1.compare(s2); //小于0表示当前的字符串小 子串substr: string sub1=s.substr(5); //只有一个数字5表示从下标为5开始一直到结尾 string sub2=s.substr(5,3); //从下标为5开始截取长度为3位 查找 find∶从前往后查找子串或字符首次出现的位置,rfind查最后出现位置 if (( s1.find(‘u’)) != string::npos) //查找u出现的位置,npos用来表不存在的位置 删除 s1.erase(1,3); //删除子串(1,3), 此后 s1="R Steel” s1.erase(5); //删除下标5及其后面的所有字符,此后 s1="R Ste" 插入 s1.insert(2,"123”); //在下标2处插入字符串”123" s1.insert(3,s2); //在下标3处插入s2 s1.insert(3,5,’×’); //在下标3处插入5个字符x, string类遍历 可用下标:s[i]; 迭代器: string::iterator it = s2.begin(); 范围for :for (auto e : s2) 交换 s1.swap(s2); string 转数组; string str; char arr[MAX]=""; strcpy_s(arr,str.size()+1, str.c_str()); //strcpy不安全,栈溢出 2.3 整形转字符串: 法一:to_string(val) 法二: string str(val) / string str=val /string str; str = val; stringstream str; string b; Int a; str<
str>>b; 3 输入输出: 3.1 cin >> string 只读入空格前的,把空格后的字符串放入缓存区等下次cin读入 3.2 getline(cin,字符串名); //可读入空格 4 排序: #indude int arr[1000000]; sort(arr,(arr+n)); //默认从小到大 5、容器 vector:动态数组的顺序容器,内存空间连续,便于存取 vector 定义赋值:vector vector 二维法二:用 vector for (int i=0;i<5;i++) { obj[i].resize(6); //6列 } //初始为0,后可用obj[i][j] arr.size() //当前使用数据的大小 arr.push_back(1) //在数组的最后添加一个数据i arr.pop_back() //删去数组的最后一个数据 arr.erase(i) 删除i位置的数据项 arr.at(i) 得到编号i位置的数据 arr.begin() 得到数组头的指针 arr.end() 得到数组的最后一个单元+1的指针 arr.front() 得到数组第一个单元的引用 arr.back() 得到数组最后一个单元的引用,不检查是否存在 arr.max_size() 得到vector最大可以是多大 arr.capacity() 当前vector分配的大小 sort(obj.begin(),obj.end());//排序从小到大 #include reverse(arr.begin(), arr.end());//逆序容器和字符串 arr.resize(n) 既修改capacity大小,也修改size大小。填充默认值 reserve 只修改capacity大小,不修改size大小, arr.clear() 清空当前的vector arr.empty() 判断vector是否为空 int maxVal = *max_element(arr.begin(), arr.end()); 返回最大值迭代器 int minVal = *min_element(arr.begin(), arr.end()); 返回最小值迭代器 sort(arr.begin(),arr.end());//从小到大 vector for(it=obj.begin();it!=obj.end();it++) { cout<<*it<<" "; }//遍历/指向vector的元素 rbegin 将vector反转后的开始指针返回(其实就是原来的end-1) rend 将vector反转构的结束指针返回(其实就是原来的begin-1) c1.swap(c2) 与另一个vector交换数据 比较if(arr1==arr2) // vector可直接用==比较是否相等,也可直接> <比较大小 return vector 附:lower_bound() 函数用于在有序指定区域内查找不小于目标值的第一个元素 头文件 auto it = lower_bound(v.begin(), v.end(), num);//v可为vector map 6.map:头文件 声明∶map 定义∶ map 插入∶//用 insert 函败插入 pair mapStudent.insert(pair //用"array"方式插入 mapStudent["r123"]="student_first"; mapStudent["r456"]="student_second"; 查找一∶find,返回的是被查找元素的位置,返回迭代器,没有则返回map.end()。 map iter = mapStudent.find("r123"); if(iter != mapStudent.end()) cout<<"Find, the value is"< 查找二: count,返回的是被查找元素的个数,返回常数。有返回1;没有返回0 遍历∶前向遍历 map for(iter=mapStudent.begin();iter != mapStudent.end(); iter++) { cout< } 大小∶ int nSize = mapstudent.size(); 数据的清空与判空: 清空map中的数据可用clear()函数,判空map可empty()函数,它返回true则说明是空map 删除: 1 用迭代器删∶ map iter-=mapStudent.find("r123”); mapStudent.erase(iter); 2根据键值删:mapStudent.erase[string(“r123”)); // 很据键值删除 附: 哈希unordered_map头文件: 7 set:set中的元素都是排序好的; set中的元素都是唯一的,没有重复的 set set q.insert(x); //将x插入q中 q.erase(x); //删除q中的x元素,返回0或1,0表示set中不存在x begin() 返回:set容器的第一个元素的迭代器 end() 返回:set容器的最后一个元素下一位置的迭代器 q.clear(); //清空q q.empty(); //判断q是否为空,若是返回1,否则返回0 q.size(); //返回q中元素的个数 q.find(x); //在q中查找x,返回x的迭代器,若x不存在,则返回指向q尾部的迭代器即 q.end() max_size() 返回set容器可能包含的元素最大个数 q.lower_bound(x); //返回一个迭代器,指向第一个键值不小于x的元素 q.upper_bound(x); //返回一个迭代器,指向第一个键值大于x的元素 q.rend(); //返回第一个元素的的前一个元素迭代器 q.rbegin(); //返回最后一个元素 8 list: list就是数据结构中的双向链表,内存空间不连续,通过指针访问数据,易插入删除,无法随即存取 list() 声明一个空列表; list(n) 声明有n个元素的列表,每个元素都是由其默认构造函数T()构造 list(n,val) 声明有n个元素的列表,每个元素都是由其复制构造函数T(val)得来 begin() 返回:list容器的第一个元素的迭代器 end() 返回:list容器的最后一个元素的下一位置的迭代器 assign() 给list赋值 back() 返回最后一个元素 empty() 如果list是空的则返回true insert() 插入元素到list中 eg: l1.insert(l1.begin(),100); 在l1的开始位置插入100。 l1.insert(l1.begin(),2,200); 在l1的开始位置插入2个100。 l1.insert(l1.begin(),l2.begin(),l2.end());在l1的开始位置插入l2的从开始到结束的所有位置的元素 erase() 删除元素 eg: l1.erase(l1.begin()); 将l1的第一个元素删除。 l1.erase(l1.begin(),l1.end()); 将l1的从begin()到end()之间的元素删除 front() 返回第一个元素 get_allocator() 返回list的配置器 max_size() 返回list能容纳的最大元素数量 clear() 删除所有元素 merge() 合并两个list pop_back() 删除最后一个元素 pop_front() 删除第一个元素 push_back() 在list的末尾添加一个元素 push_front() 在list的头部添加一个元素 rbegin() 返回指向第一个元素的逆向迭代器 remove() 从list删除元素 remove_if() 按指定条件删除元素 rend() 指向list末尾的逆向迭代器 resize() 改变list的大小 reverse() 把list的元素倒转 size() 返回list中的元素个数 sort() 给list排序 splice() 合并两个list swap() 交换两个list unique() 删除list中重复的元素 9栈 #include stack s.push(item); //将 item压入栈顶 s.pop() //测除栈顶的元素,但不会返回 n = s.top(); //返回栈顶的元素,但不会删除 n = s.size(); //返回栈中元素的个数 s.empty(); //检查栈是否为空,如果为空返回 true,否则返回false 定义栈: stack 输出栈 while(!s.empty()) { cout< s.pop(); } 10队列 #include queue q.push(item) //将item压入队列尾部 q.pop() //删除队首元素,但不返回 q.front() //返回队首元素,但不删除 q.back() //返回队尾元素,但不删除 q.size() //返回队列中元素个数 q.empty() //检查队列是否为空,如果为空返回TRUE,否则FALSE 定义队列:queue 输出队列:while(!q.empty()) { cout< q.pop(); } 11 结构体ListNode 法一:ListNode *head = nullptr; // 定义一个初始为空的链表 head = new ListNode; //分配新结点 head->value = 12.5; //存储值 head->next = nullptr; //表示链表的结尾 ListNode *secondPtr = new ListNode; //创建第二节点 secondPtr->value = 13.5; secondPtr->next = nullptr; //第二个结点是链表的结尾 head->next = secondPtr; //第一个结点指向第二个 法二 结构体含构造函数 ListNode(double valuel, ListNode *nextl = nullptr) { value = value1; next = next1; } 可两种方式创建一个结点: 通过仅指定其 value 部分,而后继指针则默认为 nullptr。 通过指定 value 部分和一个指向链表下一个结点的指针。 Eg: ListNode *head = new ListNode(13.5); head = new ListNode(12.5, head); 欢迎分享,转载请注明来源:内存溢出
评论列表(0条)