自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(85)
  • 问答 (1)
  • 收藏
  • 关注

原创 数据结构之线段树

#include<iostream>#include<vector>const int MAXSIZE = 20;void build_tree(std::vector<int>& arr, std::vector<int> &tree, int root_node, int start, int end) { if (st...

2020-03-19 13:26:06 187

原创 数据结构之跳跃表

在以往的动态平衡数据结构中,我们学习过AVL tree, RB tree等等。二者的对元素的插入,删除,访问的时间复杂度都为对数时间。但是二者相对比较复杂,构建也比较麻烦(尤其是RB树,太难了~~)。有没有也存在一种动态平衡的数据结构,对元素的插入,删除和访问操作为对数时间尼?当然有! 那就是跳跃表。我们都知道链表的插入或者删除操作的时间复杂度为常数时间,但是其索引元素的时间复杂度便为线性时间...

2020-03-05 22:34:08 426

原创 设计模式之命令模式

#include<iostream>#include<memory>class IceCream {public: virtual void eat() = 0; virtual void noeat() = 0;};class HDIceCream :public IceCream {public: void eat()override { s...

2020-02-19 17:10:26 278

原创 程序员的自我修养——链接,装载与库(八)运行库

运行库是程序运行时所需要的库文件。 操作系统装载程序以后,首先运行的不是main函数,而是入口函数(往往是运行库的一部分)。 Linux下程序的运行步骤由4部分构成:操作系统在创建进程后,把控制权交到了程序的入口,这个入口往往是运行库的某个函数。 入口函数对运行库和程序运行环境进行初始化,包括堆栈,堆,I/O,线程,全局变量构造。 入口函数在完成初始化之后,调用main函数,正式开始执...

2020-02-15 17:02:26 316

原创 程序员的自我修养——链接,装载与库(七)内存

内存是承载程序的运行介质,也是程序进行各种运算和表达的场所。 栈(高地址->低地址)用于维护函数调用的上下文,离开了栈,函数调用无法实现。 堆(低地址->高地址)用于储存应用程序动态分配内存的内存区域。 可执行文件映像用于存储可执行文件在内存中的映像。 保留区存储内存中收到保护而非禁止访问的对象。 动态链接库映射区用于存储装载的动态链接库。 程序中出现的段错误或非法访问有两...

2020-02-14 16:48:55 299

原创 程序员的自我修养——链接,装载与库(六)Linux共享库的组织

Linux下共享库就是共享对象,因为共享对象可以被多个进程共享。 共享库的更新被分为两类:兼容更新(共享库更新后原有的接口不发生改变)和不兼容更新(共享库更新后原有的接口发生改变)。 ABI(二进制接口),主要包括一些函数调用的堆栈结构,符号命名,参数规则和数据结构的内存布局等方面。 使用共享库版本的方法可以解决共享库兼容性的问题。 共享库的文件libname.so.x.y.z x表示主...

2020-02-14 15:19:24 166

原创 Effective Modern C++ 之 lambda表达式

lambda表达式是C++11中增添的特性。lambda表达式(可调用表达式:函数,函数指针,lambda表达式,std::bind,函数对象类)是可调用表达式的一种。lambda表达式一般可以用在为智能指针创建删除器和作为算法族的实参进行传递等等。lambda表达式可以创建闭包(lambda表达式创建的运行期的对象),闭包也是可以复制的。 auto lambda_1 = [](i...

2020-02-14 14:55:34 227

原创 程序员的自我修养——链接,装载与库(六)动态链接

静态链接使得不同的程序开发者和部门能够相对地开发和测试自己的程序模块,从某种意义上来讲大大促进了程序的开发效率,原来限制程序的规模也随之扩大,但是静态链接也存在浪费内存和磁盘空间,模块更新困难的问题。而且一旦程序中有任何模块的更新,整个程序就要重新链。 动态链接的基本思想:把程序按照块分成各个相对独立的部分,在程序运行时才将它们链接在一其形成一个完整的程序,而不是像静态链接一样把所有的程序模块都...

2020-02-12 18:53:33 366

原创 Effective Modern C++ 之 引用折叠

前面我们介绍到,当函数模板的形参的型别为万能引用时,当传递给该函数模板的实参是个左值时,则推导出的形参的类型型别为左值引用,当传递给该函数模板的实参是个右值时,则推导出的形参的类型型别为右值引用。还有在实现完美转发时,当传递给调用者的实参是左值时,使用std::forward()被调者的形参的型别为左值引用,当传递给调用者的实参是右值时,使用std::forward()被调者的形参的型别为右值引用...

2020-02-12 14:52:47 145

原创 程序员的自我修养——链接,装载与库(五)

可执行文件只有装载到内存中才能被CPU执行。 程序是个静态的概念,它就是一些预先编译好的指令和数据集合的一个文件。进程是个动态的概念,它是程序运行时的一个过程,很多时候把动态库叫做运行时也有一定的含义。 程序运行时都会拥有自己的虚拟地址空,虚拟空间的大小由CPU的位数来决定(32位虚拟地址空间大小为4GB,64位虚拟地址空间的大小为无穷(目前阶段))。 C语言指针的大小的位数与虚拟地址空间的...

2020-02-11 21:36:45 236

原创 程序员的自我修养——链接,装载与库(四)静态链接

链接器在链接过程中将多个目标文件加工合并为一个文件。 层序链接:将多个目标文件安装次序叠加起来。但是这样会导致空间的浪费,产生大量的内部碎片。 相似段拟合:将相同性质段合并在一起。这个也是最实际的方法。 链接器合并各个段,也将.bss段进行合并,为目标文件分配地址空间(虚拟地址空间) 链接器进行链接时才用相似段拟合的方法,整个链接过程分为两步:第一 空间与地址的分配(链接器获得所有目标文件...

2020-02-10 20:33:23 243

原创 Effective Modern C++ 之 std::forward

std::forward与std::move的行为机制很类似。前面我们讲过std::move的实质是对传入的实参进行强制类型转换,最终转换为右值。从这里我们可以看出std::move实施的强制类型转换是无条件的。std::forward最长使用的场景是:函数模板以万能引用为新参,任何调用另一个函数。现在先让我们看一个简单的测试案例:void fun1(std::string& str...

2020-02-10 15:15:16 184

原创 Effective Modern C++ 之 std::move

移动语义可以使编译器使用移动操作来替换复制操作。移动构造函数和移动复制运算符具有控制对象移动的能力。std::move()可以实现移动语义,但是std::move()到底是怎么实现的呢?其底层原理是什么呢?首先我们先观察一下std::move()的源码:template<typename T>decltype(auto) move(T&& t)noexcep...

2020-02-10 11:26:57 206

原创 Effective Modern C++ 之 优先选用make_unique和make_shared

我们知道make_unique和make_shared可以创建unique_ptr和shared_ptr。make_unique和make_shared底层实现是将其形参向待创建对象的构造函数作了一次完美转发,从一个new运算符产生的裸指针出发,构造了一个unique_ptr或shared_ptr,然后返回创建的这个unique_ptr或者shared_ptr。new运算符也可以创建对象,那么ne...

2020-02-10 10:02:29 369

原创 程序员的自我修养——链接,装载与库(三)

目标文件从结构上讲,它是编译后的可执行文件格式,只是还没有经过链接的过程。其中可能有些符号或有些地址还没有被调整。其实它本身就是按照可执行文件格式存储的,只是与真正的可执行文件在结构上稍有不同。 可执行文件的格式分为windows下的PE和linux下的ELF。 目标文件是源代码编译后未进行链接的中间文件(windows下的.obj,linux下的.o),与可执行文件的内容和结构很...

2020-02-09 16:45:20 225

原创 Effective Modern C++ 之 shared_ptr

我们前面介绍了unique_ptr智能指针,它对它所指向的对象资源具有专属所有权。这个就直接导致unique_ptr是无法进行复制操作的。有没有一种智能指针对象资源不具有专属所有权,也就是它可以进行复制操作。当然有的。那就是shared_ptr智能指针。shared_ptr也是对裸指针进行包装的类。shared_ptr智能指针对它所指涉的对象资源具有共享所有权,也就是说指涉到该对象资源的所有的...

2020-02-09 11:10:43 133

原创 Effective Modern C++ 之 unique_ptr

首先我们应该知道为什么要使用智能指针。智能指针是对野指针的包装,它们的行为类似于被封装起来的裸指针。因此,避免了很多裸指针所带来的许多陷阱。直接使用裸指针可能会造成未定义行为,可能会产生悬垂指针等待。C++11中共有三种智能指针:unique_ptr,shared_ptr和weak_ptr。今天我们就先深层次了解一下unique_ptr吧。unique_ptr具有专属所有权的语义,因此它只能进...

2020-02-08 22:50:06 331

原创 Effective Modern C++ 之 特种成员函数

首先我们应该知道:特种成员函数是由C++编译器自动生成的函数。C++的特种成员函数包括:析构函数,默认构造函数,析构函数,复制构造函数,复制赋值运算符,移动构造函数,移动赋值运算符。 当我们使用移动构造函数和移动复制运算符时,其实质是:支持移动操作的成员上执行移动操作,不支持移动操作的成员上执行复制操作。 生成移动操作的精确条件和复制操作的精确条件是不同的。两种复制操作时批次独立的,声明了其...

2020-02-08 11:42:46 150

原创 Effective Modern C++ 之 constexpr

程序的执行分为编译阶段和运行阶段。为了让程序的执行时间最短,我们应该在编译阶段和运行阶段进行权衡。constexpr应用于对象时,对象具有const属性(加强版的const),其对象在编译阶段就已知。这些对象可能被存放在ROM里面(只读内存)。constexpr一般被使用在数组的尺寸规格,整型模板实参,枚举量的值和对齐规格中。 我们应该有效的区别const和constexpr。constexpr...

2020-02-08 10:11:52 112

原创 程序员的自我修养——链接,装载与库(二)

一个程序的运行,标准情况下,需要四个步骤:预处理,编译,汇编和链接。预处理阶段:源代码文件和相关的头文件被预编译成扩展名为.i的文件。预编译过程主要处理那些源代码文件中的以“#”开头的预编译指令。 编译阶段:编译过程就是把预处理完的文件进行一系列的词法分析,语法分析,语义分析及优化后生成相应的汇编代码文件。细分的化,编译过程一般可以分为6步:扫描,语法分析,语义分析,源代码优化,代码生成和目标...

2020-02-07 20:12:21 207

原创 程序员的自我修养——链接,装载与库(一)

程序员的自我修养——链接,装载与库这本书看了差不多有一个多月了,这本书讲了很多计算机底层的知识,也补充了我的知识盲区。但是感觉看完以后前面有的知识有遗忘,因此就想好好的总结一下,也可以更好的理解这本书。 计算机三个最重要的硬件是:中央处理器CPU,内存和I/O控制芯片。 为了协调I/O设备与总线之间的速度,也为了能够让CUP能够和I/O通信,每个设备都有一个I/O控制器。 ...

2020-02-07 12:06:07 644

原创 Effective Modern C++ noexcept

我们知道关于函数发射异常这件事,真正重要的信息是他会不会发射异常。在C++11中,无条件的为函数声明noexcept就是为了不会发射异常的函数而准备的。函数是否要加上如此声明,事关接口的设计。当我们知道函数不会发射异常但却没有为函数加上noexcept,这就是接口规格设计存在缺陷。为不会发射异常的函数加上noexcept,可以让编译器生成更好的代码(也就是说对代码会进行优化)。在带有noexc...

2020-02-07 11:04:30 146

原创 STL源码剖析之slist

我们都知道list的底层实现是双向链表,今天我们就讲一讲底层为单向链表的slist,其实现比较简单。listnode.htemplate<typename T>struct ListNode { T value; ListNode<T>* next;public: ListNode(const T _value) :valu...

2020-02-07 09:37:23 226

原创 Effective Modern C++ 之 override

我们都知道C++是面向对象的语言,而在C++中OOP的三大特性是:数据抽象,继承和多态。在实现多态中是通过虚函数来实现的,派生类中的虚函数的实现会改写基类中对应的虚函数的实现。而要改写的这个动作的完全实现必须满足一些要求: 基类中的函数必须是虚函数。 基类和派生类中的函数的签名必须完全相等。 基类和派生类中的函数的引用饰词(可以让左值和右值的对象的处理区分开来)必须完全相...

2020-02-06 15:53:52 149

原创 Effective Modern C++ 之 删除函数与private未定义的函数

如果我们想阻止对象去调用函数,我们便可以把该函数声明成private,并且不去定义它。但是这样真的可以阻止客户对象区调用它吗?其实是不行的,虽然我们把函数声明为private,客户对象只是不能直接的去进行调用,但是却可以间接的进行调用(通过使用接口函数对其进行调用便可)。有什么方法可以让一个函数永远不会使用呢? 当然有啊~~ C++11中,有更好的途径来达成效果上相同的结果:使用“=del...

2020-02-06 11:58:59 142

原创 Effective Modern C++ 之 枚举型别

枚举型别也是类,是一种特殊的类(里面只允许存在整型常量的类)。枚举量都是整型常量。枚举型别分为限定作用的和不限定作用域的。顾名思义,不限定作用域的表示枚举量在任何地方都可以使用,而限定作用域的只能在其作用域里使用。因此,不限定作用域的枚举类会泄漏名字,造成名字的空间污染。 限定作用域的枚举类的枚举量是更强型别的,也就是说其枚举量不发生隐式的类型转换。而不限定作用域的枚举类的枚举量却可...

2020-02-05 22:11:44 143

原创 Effective Modern C++ 之 优先选用nullptr,而非或NULL

我们知道C++的基本观点是0的型别是int,而非指针。0和NULL(C里面的空指针)在C++都不具备指针型别。C++中我们使用nullptr一般表示空指针(其实nullptr不具备任何的型别,它是一种任意类型的指针)。nullptr还可以提高代码的清晰性,nullptr不会造成0和NULL造成的代码的二义性问题,因此C++中表示空指针时,相对于0和NULL,我们应该优先选用nullptr。...

2020-02-05 10:56:29 133

原创 STL源码剖析之stack

大家知道在程序设计里面,哪种数据结构使用率最高呢?答案是:栈。为什么呢?因为程序设计里面会存在的大量的函数调用,而函数的调用实质是使用了栈。今天就让我们来了解一下栈的底层实现吧~栈是一种先进后出的数据结构,它只有一个出口,因此它允许在最顶端增加元素和删除元素。所以栈是不存在迭代器的,也就是说栈不存在遍历行为啦。由于栈以底部的某个容器完成其所有的工作,所以我们可以把栈理解为“修改某数据结构的...

2020-02-02 20:04:30 243

原创 Effective Modern C++ 之 () 和{}的区别

小括号和大括号都可以给对象进行初始化。但是大括号的范围更广,效率更高。大括号禁止内建型别之间隐式窄化型别转化,也就是对对象初始化时,不会发生隐式的型别转化。大括号还可以对最令人苦恼之解析语法免疫。当我们对对象进行默认构造时,有时也不注意,我们会写成声明一个函数,这个是很危险的。但是,使用大括号进行初始化,就不会出现此类的问题。前面我们讲过使用大括号的auto型别推导,会推导成std::in...

2020-02-02 11:20:07 252

原创 STL源码剖析之deque

前面我们讲过,vector的底层是连续线性存储的,其是动态的分配内存空间的,而vector只支持尾端的插入和删除操作。有没有一种数据结构首尾都支持插入和删除的的操作呢?当然有啊~ 就是deque(双端队列)。deque是一种双向开口的连续线性空间,所谓双向开口,意思是可以在头尾两端进行插入和删除的操作。deque和vector的最大差异在于deque允许于常数时间内对首尾两端进行插入和删除,还...

2020-02-02 09:46:41 193

原创 STL源码剖析之list

先前我们讲过vector是连续线性存储的,其访问元素的时间复杂度是,但是插入或者删除元素的时间复杂度是,所以其插入或者删除的效率比价低。有什么容器的插入或者删除的效率是常数时间呢? 有啊~~ 就是list。list的每次插入或者删除元素时,配置或者释放一个内存空间,其时间复杂度永远是。现在就让我们来了解一下list的底层实现吧。首先让我们来看一下list的节点。template<t...

2020-02-01 18:34:00 169

原创 Effective Modern C++ 之 auto的使用

前面的总结中,我们对auto进行了总结。我们了解到auto的类型推导实质是模板类型推导。现在我们来讲解一下auto的使用,有人会觉得auto的使用很简单的,其实不然,auto的使用中存在很多的陷阱的。 我们都知道在栈上分配的内存空间,必须进行初始化,不然会导致未定义的行为。有时候我们显示的声明对象的型别,可能会忘记初始化,因此便会出现未定义的行为。有什么办法呢? 有啊~~ 使用auto啊,通...

2020-01-30 23:03:46 195

原创 STL源码剖析之vector

容器vector的底层实现是由数组(连续的线性空间)实现的,veector是动态分配内存空间的,也就是说,随着元素的加入,它的内部机制会自行扩充空间以便于容纳新元素。因此vector的底层实现技术的核心是对大小的控制以及重新分配内存空间时对数据的移动效率。因为vector的底层实现是由数组来实现的,所以vector的迭代器就是原生指针。vector的简单实现如下:我把迭代器的内嵌的相应的型别封...

2020-01-30 10:50:38 184

原创 设计模式之单例模式

以下是我摘自维基百科,我觉得总结的特别好:单例模式,也叫单子模式,是一种常用的软件设计模式,属于创建型模式的一种。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配...

2020-01-22 12:41:15 141

原创 Effective Modern C++ 之 auto和decltype的型别推导

首先我们应该知道auto型别推导的实质就是模板类型推导,在型别推导过程中,把auto替换成T就可以(可以看看我之前写的模板类型推导)。是不是所有的auto都可以与模板的类型推导建立一一映射关系呢?当然不是啦!!auto型别推导中有一条特殊的推导规则。接下来就让我们我们讲一讲啦~~当用auto声明变量,并且该变量用大括号进行初始化时,其推导所得的型别是std::initializer_list&...

2020-01-21 10:32:54 145

原创 Effective Modern C++ 之 模板型别推导

模板的型别推到是C++最广泛的特性之一。现在让我们先简单看一个函数模板推导。template<typename T>void fun(PRAMTYPE pram);fun(_parm);这时我们会问T的类型是什么呢?PRAMTYPE的类型又是什么呢?_pram和T的类型,PRAMTYPE的类型存在什么关联呢?这时候就要分三种情况去讨论。PRAMTYPE具有指针或...

2020-01-14 23:08:00 207

原创 设计模式之工厂模式

今天我们来了解一下工厂模式吧~~以下是我摘自维基百科:工厂方法模式(英语:Factory method pattern)是一种实现了“工厂”概念的面向对象设计模式。就像其他创建型模式一样,它也是处理在不指定对象具体类型的情况下创建对象的问题。工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。什么意思呢?其实...

2020-01-03 10:59:03 115

原创 Find—Union(并查集)

有时候我们想要查询两个元素是否在同一个集合中或者想要合并两个集合,怎么办呢?有人会说:“用二叉树,AVL树,链表,布隆过滤器也许啊”等等。但是“杀鸡怎么可以用牛刀呢?更何况,效率可能还不高”那怎么解决呢? 用并查集可以完美的解决这个问题哦~~并查集是一个树状结构(对集合进行抽象的描述),用于处理一些不相交的集合(Disjoint Sets)的合并及查询问题。既然是树状结构,那每个节点肯定有其p...

2019-12-24 17:33:39 477 1

原创 设计模式之装饰者模式

今天就让我们来了解一下装饰者模式吧~~~首先何为装饰呢?装饰的解释:特定的建筑物或室内按照一定的思路和风格进行美化的一种活动。就是对对对象进行包装啦~~比如有一天你带着女朋友逛街,女朋友说“我要喝HouseBlend!!”虽然有点贵但是没办法啊!! 这时女朋友说“啧!! 太难喝了!!,我要加Milk(牛奶)”。喝了一口。“好像还不合胃口哦~~,我要加这个,我还要加个” (哎~~ 幸亏我没有女朋...

2019-12-20 18:33:28 129

原创 C++之最小生成树算法(Prim)

在讲述Prim算法之前让我们先了解一下什么是最小生成树?以下是我摘自维基百科:最小生成树是一副连通加权无向图中一棵权值最小的生成树。在一给定的无向图 G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即 {(u,v)\in E}(u,v)\in E),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集 且 (V, T) 为树,使得{w(T)={(...

2019-12-06 23:24:37 3437

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除