自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(154)
  • 收藏
  • 关注

原创 算法-----二叉树

开篇:先在开头总结一下,二叉树解题的思维模式分两类:1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。无论使用哪种思维模式,你都需要思考:如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做?其他的节点不用你操心,递归函数会

2022-05-15 15:08:25 339

原创 C++容器源码分析-----Vector

基本数据结构:基本上,STL ⾥⾯所有的容器的源码都包含⾄少三个部分: 迭代器,遍历容器的元素,控制容器空间的边界和元素的移动; 构造函数,满⾜容器的多种初始化; 属性的获取,⽐如 begin(),end()等;迭代器:template <class T, class Alloc = alloc>class vector {public: // 定义 vector ⾃身的嵌套型别 typedef T value_type; typedef value

2022-05-12 11:08:49 1124

原创 C++11新特性-----tuple和pair

简介:在 C++ 中本已有⼀个 pair 模板可以定义⼆元组,C++11 更进⼀步地提供了边⻓参数的 tuple 模板:typedef std::tuple< int , double, string > tuple_1 t1;typedef std::tuple< char, short , const char * > tuple_2 t2 ('X', 2, "Hola!");t1 = t2 ; // 隐式类型转换 tuple是一个固定大小的不同类型值的集..

2022-05-11 10:01:12 499

原创 C++11新特性-----static_assert和assert

assert:原型定义:#include <assert.h>void assert( int expression );作用:计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。例子: int a=1; int b=2; cout<<"next function is assert!"<<endl; assert((a<b ? 0:1));

2022-05-11 09:34:25 688

原创 C++11新特性-----final和override

C++ 借由虚函数实现运⾏时多态,但 C++ 的虚函数⼜很多脆弱的地⽅: ⽆法禁⽌⼦类重写它。可能到某⼀层级时,我们不希望⼦类继续来重写当前虚函数了。 容易不⼩⼼隐藏⽗类的虚函数。⽐如在重写时,不⼩⼼声明了⼀个签名不⼀致但有同样名称的新函数C++11 提供了 final 来禁⽌虚函数被重写/禁⽌类被继承, override 来显示地重写虚函数。 这样编译器给我们不⼩⼼的⾏为提供更多有⽤的错误和警告。final:C++11的关键字final有两个用途。第一,它阻止了从类继承;第二,阻止.

2022-05-10 09:35:04 325

原创 C++11新特性-----构造函数委托

在 C# 和 Java 中,⼀个构造函数可以调⽤另⼀个来实现代码复⽤,但 C++⼀直不允许这样做。 现在可以了,这使得构造函数可以在同⼀个类中⼀个构造函数调⽤另⼀个构造函数,从⽽达到简化代码的⽬的:class myBase { int number; string name; myBase( int i, string& s ) : number(i), name(s){}public: myBase( ) : myBase( 0, "invalid" ){} myBase(

2022-05-10 09:14:48 219

原创 C++11新特性-----类型推导(auto、decltype、强弱类型语言)

C++ 提供了 auto 和 decltype 来静态推导类型,在我们知道类型没有问题但⼜不想完整地写出类型的时候, 便可以使⽤静态类型推导。auto:for(vector<int>::const_iterator it = v.begin(); it != v.end(); ++it);// 可以改写为for(auto it = v.begin(); it != v.end(); ++it);虽然写起来和动态语⾔(如JavaScript的 var )很像,但C++仍然是强

2022-05-10 09:07:54 294

原创 Vector底层代码原理实现

定义初始结构:vector定义了三个指针start(表示目前使用空间的头)、finish(表示目前使用空间的尾)、end_of_storage(表示目前可用空间的尾)。template <class T>class vector{public: ~vector() { delete _start; _start = _finish = _end_of_storage = nullptr; }private: T*

2022-05-09 22:57:25 313

原创 C++-----generate() 和 generate_n()(有例子)

generate:作用 以指定动作运算结果填充特定范围内的元素内容 template <class ForwardIterator, class Generator>void generate (ForwardIterator first, ForwardIterator last, Generator gen);generate_n:作用 以指定动作的运算结果填充n个元素内容 template <class OutputIterator, cl

2022-05-09 12:00:29 205

原创 C++11新特性-----变长的对象初始化列表

C++11 提供了 initializer_list 来接受变⻓的对象初始化列表:class A{public: A(std::initializer_list<int> list);};A a = {1, 2, 3};注意初始化列表特性只是现有语法增强,并不是提供了动态的可变参数。该列表只能静态地构造c++11标准中,initializer_list对于标准库的编写影响非常大,说一个简单的例子,在c++11之前,max函数的源程序是这样的:template <

2022-05-09 11:51:14 225

原创 C++11新特性-----泛化的常量表达式constexpr

int N = 5;int arr[N];编译器会报错: error: variable length array declaration not allowed at file scope int arr[N]; ,但 N 就是5,不过编译器不知道这⼀点,于是我们需要声明为 const int N = 5 才可以。但C++11的泛化常数给出了解决⽅案constexpr int N = 5; // N 变成了⼀个只读的值int arr[N]; // OKconstexpr 告诉编译器这.

2022-05-09 11:44:24 980 1

原创 C++11新特性-----lambada表达式(函数对象、闭包)

作用:Lambda 表达式实际上就是提供了⼀个类似匿名函数的特性,⽽匿名函数则是在需要⼀个函数,但是⼜不想费⼒去命名⼀个函数的情况下去使⽤的。利⽤ lambda 表达式可以编写内嵌的匿名函数,⽤以替换独⽴函数或者函数对象,并且使代码更可读。这里简单介绍一下函数对象:一个函数对象,即一个重载了括号操作符“()”的对象。当用该对象调用此操作符时,其表现形式如同普通函数调用一般,因此取名叫函数对象。举个最简单的例子:class myprint{ public: voi

2022-05-09 11:35:38 375

原创 C++11新特性-----nullptr详解(((void *) 0)的含义和void)

nullptr 出现的⽬的是为了替代 NULL。 在某种意义上来说,传统 C++ 会把 NULL、 0 视为同⼀种东⻄,这取决于编译器如何定义 NULL,有些编译器会将NULL定义为 ((void*)0),有些则会直接将其定义为 0。这里讲一下关于((void*)0):在c语言中,0是一个特殊的值,它可以表示:整型数值0,空字符,逻辑假(false)。表示的东西多了,有时候不好判断。尤其是空字符和数字0之间。为了明确的指出,0是空字符的含义,用用到了: ((void *) 0) 这

2022-05-09 10:12:14 887

原创 从原理上讲解i++和++i的区别

先说结论:++i (前置加加)先⾃增 1再返回,i++ (后置加加)先返回 i 再⾃增1。++i 实现:int& int::operator++ (){ *this +=1; return *this; }i++ 实现:const int int::operator(int){ int oldValue = *this; ++(*this); return oldValue; }...

2022-05-09 09:59:08 82

原创 STL 中迭代器的作用,有指针为何还要迭代器

迭代器 Iterator(迭代器)模式⼜称 Cursor(游标)模式,⽤于提供⼀种⽅法顺序访问⼀个聚合对象中各个元素, ⽽⼜不需暴露该对象的内部表示。或者这样说可能更容易理解:Iterator模式是运⽤于聚合对象的⼀种模式,通过运⽤该模式,使得我们可以在不知道对象内部表示的情况下,按照⼀定顺序(由iterator提供的⽅法)访问聚合对象中的各个元素。由于Iterator模式的以上特性:与聚合对象耦合,在⼀定程度上限制了它的⼴泛运⽤,⼀般仅⽤于底层聚合⽀持类,如STL的list、vector、stack

2022-05-07 14:01:29 542

原创 C++中的set、unordered_set、map、unordered_map详解以及如何选择

set:set就是关键字的简单集合。当只是想知道一个值是否存在时,set是最有用的。一、set的模板参数介绍template < class T, // 表示set里面存放的数据类型 class Compare = less<T>, // 仿函数,可以指定让set按照什么方式进行比较数据 class Alloc = allocator<T> // 空间配

2022-05-07 13:50:49 2575

原创 C++序列容器实现-----vector(扩容及回收、swap方法)

vector 是动态空间,随着元素的加⼊,它的内部机制会⾃⾏扩充空间以容纳新元素。vector 维护的是⼀个连续的线性空间,⽽且普通指针就可以满⾜要求作为 vector 的迭代(RandomAccessIterator)。 vector 的数据结构中其实就是三个迭代器构成的,⼀个指向⽬前使⽤空间头的 iterator,⼀个指向⽬前使⽤空间尾的iterator,⼀个指向⽬前可⽤空间尾的iterator。当有新的元素插⼊时,如果⽬前容量够⽤则直接插⼊,如果容量不够,则容量扩充⾄两倍,如果两倍容量不⾜,

2022-05-07 09:56:02 1527

原创 C++--什么是内存泄漏,和内存溢出的区别,常见引起引起内存泄漏的原因,及解决办法

内存泄露和内存溢出的区别:内存溢出 : out of memory 指程序在申请内存时,没有足够的内存空间供其使用,出现out fo memory 比如申请一个int,但给它存了long才能存下的数那就是内存溢出内存泄露 : memory leak 指程序在申请内存后,无法释放已经申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后的结果很严重,无论多少内存,迟早会被占光即为:不再会被使用的对象的内存不能被回收,就是内存泄露C++没有垃圾回收机制,我们需要关注那些类型的内存泄漏?堆

2022-05-06 22:46:11 1121

原创 哪些函数不能是虚函数?

构造函数,构造函数初始化对象,派⽣类必须知道基类函数⼲了什么,才能进⾏构造;当有虚函数时,每⼀个类有⼀个虚表,每⼀个对象有⼀个虚表指针,虚表指针在构造函数中初始化; 内联函数,内联函数表示在编译阶段进⾏函数体的替换操作,⽽虚函数意味着在运⾏期间进⾏类型确定,所以内联函数不能是虚函数; 静态函数,静态函数不属于对象属于类,静态成员函数没有this指针,因此静态函数设置为虚函数没有任何意义。 友元函数,友元函数不属于类的成员函数,不能被继承。对于没有继承特性的函数没有虚函数的说法。 普通函数,普

2022-05-06 10:55:49 206

原创 C++构造函数和析构函数的具体执行算法

构造函数:在派⽣类构造函数中,所有的虚基类及上⼀层基类的构造函数调⽤; 对象的 vptr 被初始化; 如果有成员初始化列表,将在构造函数体内扩展开来,这必须在 vptr 被设定之后才做; 执⾏程序员所提供的代码;而当被扩展的类的构造函数:记录在成员初始化列表中的数据成员初始化操作会被放在构造函数的函数体内,并与成员的声明顺序为顺序; 如果⼀个成员并没有出现在成员初始化列表中,但它有⼀个默认构造函数,那么默认构造函数必须被调⽤; 如果 class 有虚表,那么它必须被设定初值;

2022-05-06 10:52:57 667

原创 C++默认构造函数

定义:默认构造函数(default constructor)就是在没有显式提供初始化式时调用的构造函数。它由不带参数的构造函数,或者为所有的形参提供默认实参的构造函数定义。如果定义某个类的变量(对象)时没有提供初始化式就会使用默认构造函数。合成的默认构造函数如果我们的类没有显示地定义构造函数,那么编译器就会为我们隐式地定义一个默认构造函数。这个由编译器创建的构造函数又称为合成的默认构造函数(synthesized default constructor)合成的默认构造函数只适合非常简单的类,

2022-05-06 10:31:27 4496

原创 C++中初始化列表,何时需要成员初始化列表?

初始化列表定义:与其他函数不同,构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。class foo{public: foo(string s, int i) :name(s), id(i) {}; // 初始化列表private: string name; int id;};示例:class Test1{public: Test1() // 无参构造函数 { cout << "Con

2022-05-06 09:58:32 364

原创 动态链接和静态链接区别

你是否知道引用的那些头文件中的函数是怎么被执行的呢?这就要牵扯到链接库了!!!  库有两种,一种是静态链接库,一种是动态链接库,不管是哪一种库,要使用它们,都要在程序中包含相应的include头文件。我们先来回顾一下程序编译的过程。如下图:静态链接:静态连接库就是把 (lib) ⽂件中⽤到的函数代码直接链接进⽬标程序,程序运⾏的时候不再需要其它的库⽂件;静态链接的优缺点: 静态链接的缺点很明显,一是浪费空间,因为每个可执行程序中对所有需要的目...

2022-05-05 11:15:08 1845

原创 define、const、typedef、inline 使⽤⽅法?

1、const 与 #define 的区别 const 定义的常量是变量带类型,⽽ #define 定义的只是个常数不带类型; define 只在预处理阶段起作⽤,简单的⽂本替换,⽽ const 在编译、链接过程中起作⽤; define 只是简单的字符串替换没有类型检查。⽽const是有数据类型的,是要进⾏判断的,可以避免⼀些低级错误; define 预处理后,占⽤代码段空间,const 占⽤数据段空间; const 不能重定义,⽽ define 可以通过 #undef 取消某个符号的定

2022-05-05 10:49:20 155

原创 深拷贝和浅拷贝的区别

当出现类的等号赋值时,会调⽤拷⻉函数,在未定义显示拷⻉构造函数的情况下, 系统会调⽤默认的拷⻉函数-即浅拷⻉,它能够完成成员的⼀⼀复制。当数据成员中没有指针时,浅拷⻉是可⾏的。 但当数据成员中有指针时,如果采⽤简单的浅拷⻉,则两类中的两个指针指向同⼀个地址,当对象快要结束时,会调⽤两次析构函数,⽽导致指野指针的问题。所以,这时必需采⽤深拷⻉。深拷⻉与浅拷⻉之间的区别就在于深拷⻉会在堆内存中另外申请空间来存储数据,从⽽也就解决来野指针的问题。简⽽⾔之,当数据成员中有指针时,必需要⽤深拷⻉更加安全。...

2022-05-05 10:42:16 176

原创 函数传递参数的几种方法(值传递、指针传递、引用传递)

·值传递:形参是实参的拷⻉,函数内部对形参的操作并不会影响到外部的实参。 指针传递:也是值传递的⼀种⽅式,形参是指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进⾏操作。 引⽤传递:实际上就是把引⽤对象的地址放在了开辟的栈空间中,函数内部对形参的任何操作可以直接映射到外部的实参上⾯...

2022-05-04 15:13:25 413

原创 C++中指针函数和函数指针以及回调函数

指针函数:定义:它的本质是一个函数,不过它的返回值是一个指针。其声明的形式如下所示:ret *func(args, ...);示例:# include <stdio.h># include <stdlib.h>int * func_sum(int n){ if (n < 0) { printf("error:n must be > 0\n"); exit(-1); } stati

2022-05-04 15:08:13 601

原创 C++ 中重载和重写,重定义的区别

重载 翻译⾃ overload,是指同⼀可访问区内被声明的⼏个具有不同参数列表的同名函数,依赖于 C++函数名字的修饰 会将参数加在后⾯,可以是参数类型,个数,顺序的不同。根据参数列表决定调⽤哪个函数,重载不关⼼函数的返 回类型。 重写 翻译⾃ override,派⽣类中重新定义⽗类中除了函数体外完全相同的虚函数,注意被重写的函数不能是 static 的, ⼀定要是虚函数,且其他⼀定要完全相同。要注意,重写和被重写的函数是在不同的类当中的,重写函数的访问修 饰符是可以不同的,尽管 vir

2022-05-03 11:46:20 434

原创 C 和 C++ 区别 (函数/类/struct/class)

⾸先,C 和 C++ 在基本语句上没有过⼤的区别。 C++ 有新增的语法和关键字,语法的区别有头⽂件的不同和命名空间的不同,C++ 允许我们⾃⼰定义⾃⼰的空间, C 中不可以。关键字⽅⾯⽐如 C++ 与 C 动态管理内存的⽅式不同,C++ 中在 malloc 和 free 的基础上增加了 new 和 delete,⽽且 C++ 中在指针的基础上增加了引⽤的概念,关键字例如 C++中还增加了 auto,explicit 体现显示 和隐式转换上的概念要求,还有 dynamic_cast 增加类型安全⽅⾯

2022-05-03 11:41:50 718

原创 C++ 中 const 和 static 关键字(定义,⽤途)

static 作⽤:控制变量的存储⽅式和可⻅性。 作⽤⼀:修饰局部变量:⼀般情况下,对于局部变量在程序中是存放在栈区的,并且局部的⽣命周期在包含语句块 执⾏结束时便结束了。但是如果⽤ static 关键字修饰的话,该变量便会存放在静态数据区,其⽣命周期会⼀直延续 到整个程序执⾏结束。但是要注意的是,虽然⽤ static 对局部变量进⾏修饰之后,其⽣命周期以及存储空间发⽣了 变化,但其作⽤域并没有改变,作⽤域还是限制在其语句块。 作⽤⼆:修饰全部变量:对于⼀个全局变量,它既可以在本⽂件中被访问到,也可

2022-05-03 11:37:45 804

原创 C++ 中的指针参数传递和引⽤参数传递

指针参数传递:指针参数传递本质上是值传递,它所传递的是⼀个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从⽽形成了实参的⼀个副本(替身)。 值传递的特点是:被调函数对形式参数的任何操作都是作为局部变量进⾏的,不会影响主调函数的实参变ᰁ的值 (形参指针变了,实参指针不会变)。void Swap(int *x, int *y){ int *tmp; tmp = x; x = y; y = tmp;}int m

2022-05-03 11:06:01 2747 2

原创 C++中返回最大最小值的方法--min_element、max_element、max、min(很全)

1. max()使用C++11,需要algorithm标准库两个值的取最大值:max(a,b);多个数取最大值:#include <iostream>#include <algorithm>using namespace std;int main() { int a = 1; int b = 2; int c = 3; cout << max({a, b, c}) << endl; return 0;}2.

2022-05-02 16:04:36 1632

原创 TIME_WAIT状态过多有什么危害,如何解决

TIME_WAIT过多危害:网络情况不好时,如果主动方无TIME_WAIT等待,关闭前个连接后,主动方与被动方又建立起新的TCP连接,这时被动方重传或延时过来的FIN包过来后会直接影响新的TCP连接; 同样网络情况不好并且无TIME_WAIT等待,关闭连接后无新连接,当接收到被动方重传或延迟的FIN包后,会给被动方回一个RST包,可能会影响被动方其它的服务连接。 过多的话会占用内存,一个TIME_WAIT占用4k大小在高并发短连接的 TCP 服务器上,当服务器处理完请求后主动请求关闭连接,这样服务

2022-05-02 11:23:23 3092

原创 UDP如何实现可靠传输

UDP不属于连接协议,具有资源消耗少,处理速度快的优点,所以通常音频,视频和普通数据在传送时,使用UDP较多,因为即使丢失少量的包,也不会对接受结果产生较大的影响。传输层无法保证数据的可靠传输,只能通过应用层来实现了。实现的方式可以参照tcp可靠性传输的方式,只是实现不在传输层,实现转移到了应用层。最简单的方式是在应用层模仿传输层TCP的可靠性传输。下面不考虑拥塞处理,可靠UDP的简单设计。1、添加seq/ack机制,确保数据发送到对端 2、添加发送和接收缓冲区,主要是用户超时重传。

2022-05-02 10:46:42 9650

原创 C++中emplace_back和push_back区别

emplace_back()是c++11的新特性。区别在于:push_back()方法要调用构造函数和复制构造函数,这也就代表着要先构造一个临时对象,然后把临时的copy构造函数拷贝或者移动到容器最后面。而emplace_back()在实现时,则是直接在容器的尾部创建这个元素,省去了拷贝或移动元素的过程。结论:在C++11情况下,果断用emplace_back代替push_back...

2022-04-29 15:35:35 861

原创 C++二维vector初始化

初始化一个 二维vector,行M,列N(行列数确定且含有初始值):// 初始化一个 二维的matrix, 行M,列N,且值为0vector<vector<int>> matrix(M,vector<int>(N));//等价于下面的vector<vector<int> > matrix(M); for(int i=0;i<M;i++) { matrix[i].resize(N);}//等价于下面的vector&l

2022-04-29 15:31:26 8491

原创 HTTPS实现原理

版本一:以TLS1.2为例,以下为TLS1.2四次握手的详细流程(括号内为可选内容):第一次握手:第一次握手是客户端向服务器发送Client Hello消息,消息以明文的形式传输,里面包括客户端支持的协议版本、加密套件、压缩算法、客户端生成的一个随机数R1、扩展字段等。其中加密套件是四个功能的组合,即:认证算法(Au)、密钥交换算法(KeyExchange)、对称加密算法(Enc)和信息摘要算法,随机数R1则会在后面的密钥生成中使用到。第二次握手:① 应对客户端发来的Clien.

2022-04-29 08:52:57 417

原创 子网掩码的作用

1.划分出网络号和主机号:子网掩码,掩码的意思就是掩盖掉主机号,剩余的就是网络号。将子网掩码和 IP 地址按位计算 AND,就可得到网络号。为什么要分离网络号和主机号?因为两台计算机要通讯,首先要判断是否处于同一个广播域内,即网络地址是否相同。如果网络地址相同,表明接受方在本网络上,那么可以把数据包直接发送到目标主机。路由器寻址工作中,也就是通过这样的方式来找到对应的网络号的,进而把数据包转发给对应的网络内。2.划分子网:子网划分实际上是将主机地址分为两个部.

2022-04-28 11:04:57 2234

原创 IP地址分类

IP 地址分类成了 5 种类型,分别是 A 类、B 类、C 类、D 类、E 类。上图中黄色部分为分类号,用以区分 IP 地址类别。什么是 A、B、C 类地址?其中对于 A、B、C 类主要分为两个部分,分别是网络号和主机号。什么是 D、E 类地址?而 D 类和 E 类地址是没有主机号的,所以不可用于主机 IP,D 类常被用于多播,E 类是预留的分类,暂时未使用。多播地址用于什么?多播用于将包发送给特定组内的所有主机。由于广播无法穿透路由,若想给.

2022-04-28 10:53:31 632

原创 两张图解决每一层所对应的网络协议

2022-04-27 11:25:57 3200

空空如也

空空如也

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

TA关注的人

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