继续来复习C++,比较枯燥,但是这是扎实掌握NDK开发的必经之路,不容小觑。

容器:

容器,就是用来存放东西的盒子。

常用的数据结构包括:数组array, 链表list, 树tree, 栈stack, 队列queue, 散列表hash table, 集合set、映射表map 等等。容器便是容纳这些数据结构的。这些数据结构分为序列式与关联式两种,容器也分为序列式容器和关联式容器。

STL 标准模板库,核心包括容器、算法、迭代器。


序列式容器/顺序容器:

元素排列次序与元素无关,由元素添加到容器的顺序决定,其相关的容器有以下几种:

容器 说明
vector 支持快速随机访问
list 支持快速插入、删除
deque 双端队列 允许两端都可以进行入队和出队操作的队列
stack 后进先出LIFO(Last In First Out)堆栈
queue 先进先出FIFO(First Input First Output)队列
priority_queue 有优先级管理的queue
  • 向量(vector):连续存储的元素,后进先出。
    下面声明一下:

    另外还有一些重载的形式,如下:

    有了容器之后就可以往里面添加、删除数据了,下面来用一下:

    接下来删除一个元素:

    那最终容器里还剩哪个元素呢?下面就可以将元素输出出来,如下:

    另外有个细节想一下,vector是一个模板类,为啥我们可以用下标的形式来访问它里面的元素,很显然是因为该类重写的下标运算符嘛,源码定义如下:

    另外通过下标获取元素还有另外一种方式,如下:

    另外还可以通过函数直接获得队首和队尾的两个元素,如下:

    如果想清空元素可以用:

    还有另外一种清除函数,可以删除某个元素,如下:

    那vector目前的容量是多大呢?也有现成的函数,被清掉之后很明显大小为0嘛,试试看:

    这里可以说明vector容器其内存占用的空间是只增不减的,clear()释放元素之后,去不能减小vector所占的内存空间。那这不会造成内存的浪费么?尤其对于全局的vector变量,然后方法使用到了该全局变量,如下:

    此时全局的容量大小虽说在方法内部被clear()掉了,但大小还是2,那实际如果被调多次那容量不会很可怕,那怎么能达到缩小容量大小的效果呢?这里可以采用swap替换操作,用一个新的临时vector来替换目前的vector,具体做法如下:

    其中还可以简写:

    注意:建立临时vector temp对象,swap调用之后对象vec占用的空间就等于默认构造的对象的大小,temp就具有vec的大小,而temp随即就会被析构,从而其占用的空间也被释放,所以不会有内存泄漏问题。
    那如果要遍历里面的所有元素可以使用迭待器,具体使用如下:

    其中在迭待过程中是不能删除元素的,跟java一样的,另外还需要了解到:

  • 列表 (list):由节点组成的双向链表,每个结点包含着一个元素。
    其操作跟vector基本类似,略过。
  • 双端队列(deque):连续存储的指向不同元素的指针所组成的数组。
    其操作跟vector基本类似,略过。
  • 队列(queue):先进先出的值的排列。
    比较简单,下面稍过一下:
  • 栈(stack):后进先出的值的排列。
    也直接一笔带过:
  • 优先队列(priority_queue ):元素的次序是由所存储的数据的某个值排列的一种队列。

    也就是说明默认情况下最大的元素在队首,那如果想改变默认的元素排序将最小的放到队首呢,具体就得这么办:

    其中:

    当然这个less和greater都是一个模板结构体 也可以自定义,就类似于Java中的比较器一样,这样less和greater的含义就发生变化了,如下:
    less  让优先队列总是把最大的元素放在队首;
    greater    让优先队列总是把最小的元素放在队首;
    下面用自定义的类型来自定义一下比较器,如下:

    编译运行:

    报错了,为啥?因为对于Student类来说不知道如何进行排序,所以此时就得自定义排序规则,这里校仿一下它:

    打开看一下它的源码实现:

    咱们对Student的自定义排序直接用这个源码,当然由于我们只对Student类型进行排序,所以就用不着泛型了,具体定义如下:

关联式容器:

关联容器和大部分顺序容器操作一致

关联容器中的元素是按关键字来保存和访问的 支持高效的关键字查找与访问

  • 集合(set):由节点组成的红黑树,每个节点都包含着一个元素,元素不可重复。
    下面来使用一下:

    如果要删除元素可以用:

    那如何遍历set呢?这里需要特别注意,有别于vector的,我们知道vector的遍历是如下:

    那校仿一下来遍历set:

    证明set中并没有重写<号运算符,那只能将其换成不等于了,如下:

  • 键值对(map):由{键,值}对组成的集合。
    基本跟java一样,这里过一遍用法:

    其插入元素还可以生成一个键值对对象,如下:

    如何通过key来查询元素呢,如下:

    删除元素则如下:

    最后来遍历一下元素,如下:

  • 红黑树
    对于二叉树我们都了解的比较多,而红黑树接触稍微少,所以这里来对其进行一个全面的认识,首先先来看一下二叉树:

    对于二叉树有一个二分查找法,比如说要从二叉树中找到“2”这个数,其整个查找过程如下:

    1、查看根节点为10

    2、由于2小于10,因此查找左孩子,节点为5

    3、同时2小与5,继续查看左边,找到2节点。

    也就是说查找最大次数为树的高度,那如果有下面的二叉查找树,插入7、6、5......,如下:

    这样几乎成为线性,查找性能大幅下降,那为了解决这种不平衡,红黑树就诞生了。在wikipedia的定义如下:

    红黑树(Red Black Tree)又称为 RB树,是一种相对平衡二叉树 ,它有如下特点:

    1.节点是红色或黑色。

    2.根节点是黑色。

    3.每个叶子节点(空节点)都是黑色的。

    4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

    5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

    其插入有如下原则:
           1. 插入新节点总是红色节点。
           2. 如果插入节点的父节点是黑色, 能维持性质。
           3. 如果插入节点的父节点是红色, 破坏了性质。插入算法就是通过重新着色或旋转, 来维持性质。
    下面画图来理解:首先画一个根结点,它是黑色的:

    然后再再插入两个子接点,新节点都是用红色表示,如下:

    接下来插入一个“7”,由于比“8”小需要插到它的左边,如下:

    因为规则四是这样描述的:“4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)”,也就是目前“7”、“8”两个都是红色破坏了规则,那么需要根据不同的状况进行不同的策略使其平衡并符合规则,7的父节点8 与叔父节点 12 都是红色,则我们可以将8、12两个重绘为黑色并重绘祖父节点9为红色,所以此时先将“8”涂成黑色:

    此时又破坏了第5条规则:“5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。”,因为“9”->"8"都是黑色,而"9"->"12"不全是黑色,也就是两边不统一了,为了解决此破坏,就得将“12”也涂成黑色:

    现在满足5个规则了,因此7插入完成。
    接下来插入 6:

    现在新节点 6 是 父节点 7的左节点,而6的叔父节点 缺少,父节点 7 又是祖父节点8的左子节点 ,这种情形下,我们进行针对6节点的祖父节点8的一次右旋转,其右旋转是指:顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子。如下:

    此时还是破坏规则4,因为“6”和"7"都是红色,此时再切换 7 和 8 的颜色,如下:

    现在满足5个规则了,因此6插入完成。
    再插入5:

    5和6都是红色,将 父节点 6 和叔父节点 8 绘为黑色:

    然后再将祖父7设为红色,最终如下:

    【提示】:关于红黑树什么时候要右旋,什么时候要左旋等一些处理,可以参考维基百科,里面列出了详细的各种情形处理,对着进行处理就成了,如下:

类型转换:

除了能使用c语言的强制类型转换外,还有:转换操作符 (新式转换)

const_cast:

修改类型的const或volatile属性。

static_cast:

  1. 基础类型之间互转。如:float转成int、int转成unsigned int等
  2. 指针与void之间互转。如:float*转成void*、Bean*转成void*、函数指针转成void*等
  3. 子类指针/引用与 父类指针/引用 转换。

举个例子:

但是如果将父类的方法声明为虚方法,结果就不一样了,如下:

dynamic_cast:

主要将基类指针、引用 安全地转为派生类,在运行期对可疑的转型操作进行安全检查,仅对多态有效。
还是拿static_cast的程序进行举例,咱们先将父类的虚函数去掉再做实现:

然后编写动态转换代码:

错误提示为:

Parent不是多态,也就是需要将它声明为虚函数才行,所以增加virtual关键字:

因为转换失败了,这时指针会为null,所以完善的代码应该加上判断:

接下来修改一下程序:


那如果是子类动态转换成父类呢?

reinterpret_cast:

对指针、引用进行原始转换,什么意思,下面来看代码:

char*与int转换:

异常:

基本上跟java类似,贴一个范例:

另外,相比java,c++中抛异常时可以随便抛一个对象,不一定是非要继承至exception类的,如下:

文件与流操作【基本C方式使用得多一些】:

C 语言的文件读写操作

头文件:stdio.h

函数原型:FILE * fopen(const char * path, const char * mode);

path: 操作的文件路径

mode:模式

其中的mode有如下这些:

模式 描述
r 打开一个已有的文本文件,允许读取文件。
w 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。
a 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。
r+ 打开一个文本文件,允许读写文件。
w+ 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。
a+ 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。

下面先来写一个文件:

打开文件看一下内容:

另外还可以以格式化的文本方式来写入,如下:

接下来读取文件:

这是因为当读取遇到空格字符就会终止,所以需要遍历读取,如下:

另外还有一个直接读最大字节的API,对于上面的程序可以改为它:

还有其它的一个比较方便的API,这里就不一一去实验了,到时用到再回来查,下面把范例贴一下:

C++ 文件读写操作

<iostream> 和 <fstream>

其涉及到的方法有:

数据类型 描述
ofstream 输出文件流,创建文件并向文件写入信息。
ifstream 输入文件流,从文件读取信息。
fstream 文件流,且同时具有 ofstream 和 ifstream 两种功能。

下面举个例子来简单的使用一下:

编译运行:

ndk学习之c++语言基础复习----C++容器、类型转换、异常与文件流操作的更多相关文章

  1. ndk学习之C语言基础复习----虚拟内存布局与malloc申请

    在这一次中来学习一下C语言的内存布局,了解它之后就可以解释为啥在用malloc()申请的内存之后需要用memset()来对内存进行一下初始化了,首先来了解一下物理内存与虚拟内存: 物理内存:通过物理内 ...

  2. ndk学习之c++语言基础复习----面向对象编程

    关于面向对象编程对于一个java程序员那是再熟悉不过了,不过对于C++而言相对java还是有很多不同点的,所以全面复习一下. 类 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程 ...

  3. ndk学习之C语言基础复习----基本数据类型、数组

    关于NDK这个分类在N年前就已经创建了,但是一直木有系统的记录其学习过程,当然也没真正学会NDK的技术真谛,所以一直也是自己的一个遗憾,而如今对于Android程序员的要求也是越来越高,对于NDK也是 ...

  4. ndk学习之c++语言基础复习----C++线程与智能指针

    线程 线程,有时被称为轻量进程,是程序执行的最小单元. C++11线程: 我们知道平常谈C++线程相关的东东基本都是基于之后要学习的posix相关的,其实在C++11有自己新式创建线程的方法,所以先来 ...

  5. ndk学习之C语言基础复习----结构体、共用体与C++开端

    自己实现sprintf功能: 关于C中的系统函数sprintf在上次[https://www.cnblogs.com/webor2006/p/7545627.html]学习中已经用到过了,这里再来回顾 ...

  6. ndk学习之C语言基础复习----指针、函数、预处理器

    指针: 指针乃C.C++的灵魂之所在,所以有必要好好的复习复习.什么是指针?一句话来概括:“指针是一个变量,它的值是一个地址.”,其中指针变量的声明有如下三种形式: 其中第一种是被推荐的写法. 其中还 ...

  7. MySQL学习笔记_8_SQL语言基础复习

    SQL语言基础复习 一.概述 SQL语句注释方式 1)以"#"开头直到行尾的所有内容都是注释 2)以"--"(--后还有一个空格)开头直到行尾的所有内容都是注释 ...

  8. Java学习笔记:语言基础

    Java学习笔记:语言基础 2014-1-31   最近开始学习Java,目的倒不在于想深入的掌握Java开发,而是想了解Java的基本语法,可以阅读Java源代码,从而拓展一些知识面.同时为学习An ...

  9. C语言基础复习总结

    C语言基础复习总结 大一学的C++,不过后来一直没用,大多还给老师了,最近看传智李明杰老师的ios课程的C语言入门部分,用了一周,每晚上看大概两小时左右,效果真是顶一学期的课,也许是因为有开发经验吧, ...

随机推荐

  1. git 命令使用

    //快速删除node_modules: 1.npm install -g rimraf  2. rimraf node_modules 1.本地新建分支并且连接远端 克隆:git clone 远端地址 ...

  2. Andrew Ng机器学习课程14(补)

    Andrew Ng机器学习课程14(补) 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 利用EM对factor analysis进行的推导还是要参看我的上一 ...

  3. Asp.net SignalR 实现服务端消息实时推送到所有Web端

    ASP .NET SignalR是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信.实际上 Asp.net SignalR 2 实现 服务端消息推送到Web端, 更加 ...

  4. nssm使用,安装服务、删除服务

    安装服务参考 nssm设置solr开机启动服务 删除服务 Windows删除服务 sc delete 服务名 nssm删除服务 nssm remove 服务名 nssm常用命令: nssm insta ...

  5. 2019春《C语言程序设计》课程设计的安排

    课程设计的安排 课前准备: 要求同学们注册码云,并登陆: 要求组长加入由老师创建的一级组织:"2019春C语言": 要求组长建立二级组织,给自己的小组取个好听的名字,并邀请本组成员 ...

  6. Linux 时间以及时间间隔的简单处理.

    最近想知道自己的一个部署脚本的耗时, 中午时间看了一下最简单的Linux 时间函数的处理 我这里的处理非常简单, 仅仅是够用而已. 处理过程. 1. 获取当前时间: time1=`date` 或者是 ...

  7. [转帖]nginx location配置详细解释

    nginx location配置详细解释 http://outofmemory.cn/code-snippet/742/nginx-location-configuration-xiangxi-exp ...

  8. java学习基础知识入门

    基础入门知识(一) 一.java技术的分类 java按照技术标准和应用场景的不同分为三类,分别是JAVASE.JAVAEE.JAVAME JAVASE : 平台标准版,用于开发部署桌面,服务器以及嵌入 ...

  9. MongoDB部分

  10. 浅谈C++继承

    C++中的继承 1.继承概念及定义:     概念:是面向对象程序设计使代码可以复用的最重要的手段-----继承是类设计层次的复用     定义:            父类->基类:子类-&g ...