- 博客(43)
- 收藏
- 关注
原创 Linux--高级I/O(select、poll、epoll)
一、五种I/O模型1.1、阻塞I/O阻塞I/O:在内核将数据准备好之前,系统调用会一直等待,所有的套接字,默认都是阻塞方式。举例:张三拿了一根鱼竿在荷塘旁边钓鱼,张三钓鱼的方式是一直看着鱼竿直到有鱼上钩。1.2、非阻塞I/O非阻塞I/O:如果内核还未将数据准备好,系统调用仍然会直接返回,并且返回EWOULDBLOCK错误码。非阻塞I/O往往需要程序员循环的方式反复尝试读写文件描述符,这个过程称为轮询。这对CPU来说是较大的浪费,一般在特定场景下使用。举例:李四拿了一根鱼竿在荷塘旁边钓鱼
2021-07-23 21:17:16
329
1
原创 高并发内存池
一、什么是内存池内存池(Memroy Pool):是一种动态内存分配与管理技术。在真正使用内存之前,先申请分配一大块内存(内存池)留作备用,当程序员申请内存时,从池中取出一块动态分配给程序,当程序员释放时,则直接将这块内存释放进入内存池中,再次申请时,再取出来使用,并且和周围的空闲内存块合并出大的内存,当程序员需要申请大块内存时可以将合出来的大块内存分配出去。当内存池中的内存不足时再进行扩容。二、内存池的演进2.1、简单内存池做一个链表指向空闲内存,分配就是查找链表中空闲内存大于等于所需要的内存分配
2021-07-17 11:56:03
401
原创 实现一个简单的定长内存池
一、内存池内存池是一种动态内存分配与管理技术,程序员习惯直接使用new、delete、free、malloc等这些API申请和释放内存,这样导致的后果:由于申请的大小不固定,频繁的使用会造成内存碎片从而降低程序和操作系统的性能。内存池则是在使用时,先申请一大块内存留做备用,当程序需要使用时,就直接使用内存池中的内存,当程序要将内存释放时,就先释放到内存池中。当再次申请时,就再次从内存池中取出使用。这样可以避免频繁的找系统申请,大大加快了系统的性能。1.1、好处1、我们一次性向系统申请一大块内存,这样
2021-06-30 22:02:00
333
3
原创 STL--AVLTree、RBTree介绍和插入的模拟实现
一、平衡二叉搜索树对于map/multimap/set/multiset 这几个容器的共同点是:其底层都是按照二叉搜索树来实现的。但是二叉搜索树有其自身的缺陷,假如往树中插入的元素有序或者接近有序,二叉树搜索树就会退化成单支树,时间复杂度会退化成O(N),因此map/set等关联式容器的底层结构是对二叉树进行了平衡,即采用二叉平衡搜索树来实现的。二、AVLTree二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗
2021-06-07 10:17:40
348
3
原创 Linux--网络编程套接字
一、预备知识1.1、简单理解源IP和目的IP在IP数据包中头部中,有两个IP地址:分别叫做源IP地址和目的IP地址。就好比唐僧西天取经,唐僧从东土大唐来要前往西天取经。源IP地址:东土大唐;目的IP地址:西天。1.2、认识端口端口号的性质:1、端口号是一个2字节16位的整数。2、端口号用来标识一个进程,告诉操作系统,当前的这个数据要交给哪一个进程来处理。3、IP地址+端口号能够标识网络上的某一台主机的某一个进程。4、一个端口号只能被一个进程占用。端口号就好比唐僧到了西天要找到具体的某个
2021-05-17 22:27:58
231
11
原创 Linux--生产者消费者模型(BlockingQueue、RingQueue案例)、线程池
一、生产者消费者模型为何要使用生产者消费者模型生产者消费者模式就是通过一个容器来解决生产者消费者的强耦合问题。生产者消费者彼此之间不再直接通讯,而是通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接仍给阻塞队列,消费者不找生产者要数据,而是直接通过阻塞队列拿数据,阻塞队列相当于一个缓存区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。模型满足的关系在计算机中生产者消费者具体指的是:生产者:线程消费者:线程空间、交易场所:一块"内存块"
2021-05-04 15:22:54
572
5
原创 STL--priority_queue(介绍以及使用和模拟实现)
一、priority_queue的使用template <class T, class Container = vector<T>,class Compare = less<typename Container::value_type> > class priority_queue;优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆的算法将vector的元素构成了堆的结构,所有需要用到堆的位置,都可以考虑使用priority_qu
2021-05-03 15:46:29
204
1
原创 C++--继承(继承的概念与定义、派生类默认成员函数、菱形继承及菱形虚拟继承)
一、继承的概念及定义1、继承的概念继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新的功能,这样产生新的类,新类称为派生类或基类。继承是类设计层次的复用,呈现了面向对象程序设计的层次结构。class Person {public: void Print() { cout << "name:" << _name << endl; cout << "age:" << _ag
2021-05-02 19:38:45
835
1
原创 STL--deque、stack、queue
一、deque介绍deque(双端队列):是一种双开口的“连续”空间的数据结构。双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不必搬动数据;与list相比,空间利用比较高。deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图:deque采用一块所谓的map(注意:不是STL的map容器)作为主控,这里的map是一小块连续空间,其中每个元素都是一个指针,指向另一段(
2021-05-01 16:39:01
2240
4
原创 STL--vector容器介绍和使用以及迭代器失效问题
一、vector的介绍1、vector是表示可变大小的序列容器。2、就像数组一样,vector也采用的连续存储空间来存储元素。也就意味着可以采用下标对vector的元素进行访问和数组一样高效。但是又不像数组,它的大小可以动态改变的,而且它的大小会被容器自动处理。3、本质讲,vector使用动态分配数组来存储它的元素。当新元素插入的时候,为了增加存储空间这个数组需要被重新分配。其做法是分配新的数组,然后将全部元素移到新的数组中。就时间而言,这是一个相对代价较高的任务,但是vector并不会每次都重新分配
2021-04-28 17:20:11
304
1
原创 STL--vector模拟实现
一、前言在另一篇博客中我已经写了:vector容器介绍和使用以及迭代器失效问题,那么在这篇博客中我将要模拟实现一个简单的vector,对vector实现基本的增、删、改。下图是vector的基本结构:二、vector的成员、构造、析构、迭代器的基本实现#pragma once#include<iostream>#include<assert.h>namespace Myvector{ template<class T> class vector {
2021-04-28 17:19:37
524
3
原创 C++string类(现代写法、传统写法以及模拟实现)
为什么学习stringC语言中的字符串C语言中,字符串是以‘\0’结尾的一些字符的集合,为了操作方便,C标准库提供了一些str系列的函数,但是这些库函数是与字符串分开的,不符合OOP思想,而且底层空间需要用户自己管理,稍不留神就会发生越界访问。stringstring是一个类,对于底层空间自己管理,不会发生越界访问。string使用起来方便、快捷、简单。string的常用接口string类对象的构造函数名称功能说明string() (重点)构造空的string类对
2021-04-17 15:04:00
710
1
原创 Linux--信号
信号的入门1、生活中的例子1、 你在网上买了很多件商品(多种信号),再等待不同商品快递的到来。但即便快递没有到来,也就是你能“识别快递”(识别多种信号)。(信号达到之前)2、当快递员到了你楼下,你收到了通知,但是你正在打游戏,需5min之后才能去取快递。那么在这5min之内,你并没有去取快递,但是你是知道有快递到来了。也就是取快递的行为并不是一定要立即执行,可以理解成“在合适的时候去取”。(操作系统收到了信号并不立即处理,这是可能还有比处理信号更重要的事要做。)3、当你觉得时间合适了,拿到快递之后
2021-04-13 11:54:55
1980
8
原创 Linux--进程间通信(管道、共享内存)
进程间通信目的1、数据传输:一个进程需要将它的数据发送给另一个进程。2、资源共享:多个进程之间共享同样的资源。3、通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。4、进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。管道什么是管道管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
2021-04-07 18:10:29
2510
5
原创 Linux--基础IO
C文件接口写文件#include<stdio.h>#include<string.h>int main(){ FILE *fp=fopen("myfile.txt","w"); if(!fp){ printf("open error!\n"); return 1; } const char *msg="Hello World!\n"; //这里不用 +1,具体查看man手册对该函数得说明 fwrite(msg,strlen(msg),1,fp);
2021-04-03 11:17:10
1686
4
原创 Linux--进程控制
进程创建fork函数初始fork函数从已存在的进程中创建一个进程。新进程为子进程,原来的进程为父进程。#include<sys/types.h>#include<unistd.h>pid_t fork(void);//子进程返回,父进程返回子进程的PID,如果出错,则为-1进程调用fork函数,当控制转移到内核中的fork代码后,内核完成了以下工作:1、分配新的内存块和内核数据结构(task_struct等)给子进程。2、将父进程部分数据结构内容(mm_str
2021-03-17 16:07:49
277
4
原创 Linux--进程地址空间
进程地址空间图验证进程地址空间#include<stdio.h> #include<stdlib.h> int g_val=100; int g_unval; int main(int argc,char *argv[],char *env[]){ printf("code addr : %p\n",main); printf("g addr : %p\n",&g_val);
2021-03-15 10:49:37
106
原创 Linux--进程优先级、环境变量
进程优先级基本概念1、cpu资源分配的先后顺序,就是指进程的优先级。2、优先级高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。3、还可以把进程运行到指定的cpu上,这样一来,把不重要的进程安排到某个cpu上,可以大大改善系统整体性能。查看系统进程ps -l //查看系统进程UID:代表执行者的身份PID:代表这个进程的代号PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号PRI :代表这个进程可被执行的优先级,其值越
2021-03-11 17:37:43
351
原创 Linux--进程初识、fork函数、进程状态转换
冯诺依曼体系结构到目前为止,我们所知道的计算机,如笔记本、服务器、台式机等。。都遵守冯诺依曼体系。这些都是由一个个硬件组成。输入单元:磁盘、网卡、键盘, 鼠标,扫描仪, 写板等输出单元:磁盘、网卡、显示器,打印机等中央处理器(CPU):包含运算器和控制器等我们需要强调几点:存储器就是指内存。不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备)。外设要输入或输出数据,也只能写入内存或从内存中读取。总之就是所有外设都只能与内存打交道,不能直接与CPU打交
2021-03-10 18:33:25
2916
8
原创 LeetCode大数运算
415. 字符串相加题意:给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。返回值:返回相加后的结果字符串。说明:1、num1 和num2 的长度都小于 51002、num1 和num2 都只包含数字 0-93、num1 和num2 都不包含任何前导零4、你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式思路:这道题主要考察对字符串的模拟,模拟两个整数相加的情况。来看看我们做加法的情况。步骤:■ 1、从每个数从低位到高
2021-03-08 19:30:49
2063
3
原创 Linux--yum、vim、gdb、make\Makefile的使用
Linux 软件包管理器 yum什么是软件包在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序。但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安装程序)放在一个服务器上, 通过包管理器可以很方便的获取到这个编译好的软件包, 直接进行安装。软件包和软件包管理器, 就好比 “App” 和 “应用商店” 这样的关系。yum(Yellow dog Updater, Modified)是Linux下非常常用的一
2021-03-05 08:57:37
318
原创 Linux--权限、目录的权限、粘滞位
Linux权限的概念Linux下有两种用户:超级用户和普通用户。超级用户:可以在Linux系统下做任何事情,不受限制。普通用户:可以在Linux系统下做有限的事情。超级用户的提示符是“#”,普通用户的提示符是“$”。命令: su [用户名]。功能: 切换用户。要从root用户切换到普通用户user,使用su user。要从普通用户切换到root用户则使用su root(root可以省略),此时系统会提示输入root用户的口令。Linux权限管理...
2021-02-17 17:21:01
355
原创 C++入门--友元、静态成员、单例设计模式、成员变量和函数的存储
友元类的主要特点之一是数据隐藏,即类的私有成员无法在类的外部访问,但是我们有时候需要在类的外部访问类的私有成员。那么我们可以使用友元来解决,友元是一种特权,允许访问类的私有成员。友元分为:友元函数和友元类。友元函数友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但是需要在类的内部声明,声明时需要加friend关键字。实例代码:class Date{ friend ostream&(ostream& cout,const Date& da
2021-02-15 16:00:28
265
1
原创 C++入门--运算符重载
运算符重载C++为了增强代码的可读性引入了运算符重载,对已有的运算符重新进行定义,赋予其另一种功能,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。运算符重载的定义函数名字:operator后面接需要重载的运算符符号。函数原型:Type operator操作符 (参数列表)。注意■ 1、不能通过连接其他符号来创建新的操作符:比如operator@。■ 2、重载操作符必须有一个类类型,没有类型那么根本没有意义。■ 3、用于
2021-02-14 10:13:45
271
1
原创 C++入门--构造函数、拷贝构造函数、析构函数
构造函数构造函数:主要作用在于创建对象时为对象的成员属性赋值,由编译器自动调用,无须手动调用。在对象的生命周期中只调用一次。特性特性如下:■ 1、函数名和类名相同。■ 2、没有返回值,而且不能有void。■ 3、有参数,支持重载。■ 4、对象实例化时编译器自动调用对应的构造函数。class Date{public: //无参构造函数 Date(){ } //有参构造函数 Date(int year,int month,int day){ _year=year; _mo
2021-02-08 15:50:21
483
原创 C++入门--引用的本质、const限定符、this指针、nullpter
引用引用的概念引用不是新定义一个变量,而是给已存在变量去一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。引用定义:类型& 引用变量名(对象名) = 引用实体;int main(){ int a=10; int &b=a; cout<<"a的地址:"<<&a<<endl; cout<<"b的地址:"<<&&b<<endl; return 0;
2021-02-06 21:24:04
319
原创 C++入门--命名空间、函数默认参数、函数重载、内联函数
命名空间C/C++中,变量、函数和类都是大量存在的。这些变量、函数和类都将存在于全局作用域中,可能会有很多冲突。使用命名空间的目的就是对标识符的名字进行本地化,以避免命名冲突和名字污染,于是namespace关键字出现了。命名空间定义定义命名空间:用namespace关键字,后面跟命名空间的名字,然后是一对 {},{}中即为命名空间中的成员。//1.命名空间下可以放函数,变量和类,结构体以及命名空间//2.命名空间必须定义在全局作用域下//3.命名空间可以嵌套命名空间namespace
2021-02-03 17:54:05
259
原创 C/C++源文件到可执行文件、C++能重载C语言不能重载本质
C/C++源文件到可执行文件翻译环境过程总结:■ 1、组成一个程序的每个源文件通过编译过程分别转换为对应的每个目标文件。■ 2、每个目标文件通过链接器捆绑在一起,形成单一而完整的可执行程序。■ 3、链接器同时也会引入标准C/C++库函数中任何被该程序所用到的函数,而且还会搜索程序员个人的程序库,将其需要的函数也链接到程序中来。翻译环境中的每一步具体干了什么每个过程总结:■ 1. 预处理:为正式编译做准备。1.头文件展开。2.宏替换。3.去掉注释。在Linux环境下用命令gcc -E
2021-02-01 22:03:14
293
6
原创 常见排序算法总结
排序的概念1、排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。2、稳定性:假定在待排序的记录序列中,存在多个具有相同关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。3、内部排序:数据元素全部放在内存中的排序。4、外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序
2021-01-31 17:13:44
5256
7
原创 归并排序(递归实现、非递归实现)、磁盘中的外排序
前言归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。其中二路归并类似二叉树的后序遍历。归并排序的思考更多的是解决在磁盘中的外排序问题。主要思路:■ 先将待排序的序列分割为小的序列,使每个子序列有序。■ 将小的子序列合并为更大的子序列,即使子序列段间有序。合并到最后整个序列有序。过程演示递归实现归并排序C语言代码实现//将已有序的小区间合并为更大的有序区间,其中合并取得是闭区间。v
2021-01-30 18:05:35
1552
6
原创 快速排序(双指针法、挖坑法、前后指针法)递归、非递归实现
前言快速排序是交换排序中的一种,是Hoare于1962年提出的一种二叉树结构的交换排序方法,类似于二叉树的前序遍历。主要思想:■ 任取待排序元素序列中的某元素作为关键字,按照该关键字将待排序集合分割。■ 按照该关键字将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值。■ 然后将左右子序列重复该过程,直到所有元素都排列在相应位置上为止。区间划分左右部分常见方式双指针法实现过程:如下图 !C语言代码实现int PartSort1(int*
2021-01-30 13:04:27
2725
3
原创 图解二叉堆:堆排序
前言二叉堆和二叉树有什么关系呢?二叉堆的存储方式是数组,为什么我们总是把二叉堆画成二叉树呢?其实二叉堆是一种特殊的二叉树:完全二叉树。由于完全二叉树的性质所以我们更适合使用数组来存储,用数组的索引来操作子节点。而对于一般二叉树我们使用指针来操作子节点。其实二叉堆的主要核心操作就是down(下沉)和up(上浮)。二叉堆的概念下图是一个二叉堆实例。从图上我们可以看出父亲和儿子节点索引的关系int parent(int root){ return (root-1)/2;//记住一定是先减1再除2
2021-01-20 17:04:16
1005
1
原创 链表:判断链表是否有环以及找入口
141环形链表题意: 给定一个链表,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。返回值:如果链表中存在环,则返回 true 。 否则,返回 false 。说明:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。思路:这道题目,主要考察对链表的操作。主要方法:■ 双指针:快慢指针
2021-01-16 10:36:51
952
3
原创 数组模拟单链表
数组模拟单链表链表的概念以及结构概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 ,这种链表也叫动态链表。定义:在C语言中我们通过结构体实现一个节点的定义。typedef struct ListNode{ int val, struct ListNode *next;}ListNode;缺点:■ 在我们创建一个链表时这个过程是十分慢的,需要重新开辟一个空间,我们在做算法题的时候常常会时间超时。数组模拟链表我们用数组
2020-12-12 20:04:49
517
2
原创 C语言动态内存管理、柔性数组
C语言动态内存管理为什么有动态内存管理//没有动态内存分配之前我们掌握开辟的内存的方式有:double a=10; //在栈上分配8个字节大小的空间char ch[10]; //在栈上分配一段连续的空间以上述方式开辟的内存有一下特点:■ 空间开辟的大小是固定的■ 数组在申明的时候,必须用一个常量来指定数组的长度,所需要的内存在编译时就已经在栈上分配好了总结:在实际情况中我们对内存的需求,不止上述情况,有时我们需要的空间大小在程序运行的时候才能知道,那对于数组的定义上述方式就不能满足需求
2020-12-09 17:36:55
327
1
原创 C/C++ 内存模型
C/C++ 内存模型内存模型图程序运行前在程序编译后,生成了可执行的exe文件,未执行该程序前分为两个区域。■ 代码区:存放函数体(类成员函数和全局函数)的二进制代码 共享:对于频繁执行的程序,内存中只需要一份就可以只读:防止程序意外修改其指令■ 全局区:全局变量、静态变量 全局区中还包括常量区(字符串常量、其他常量(const修饰))也放在全局区特点:该区域的数据在操作系统运行结束之后由操作系统释放【测试全局区】//测试全局区int g_a = 10;int
2020-12-07 17:24:39
1122
原创 C语言浮点数、整数在内存中的存储
数据的基本介绍在 C 语言中,变量的类型决定了变量开辟内存空间的大小,如何看待内存空间的视角。整数类型类型存储大小值范围char1 字节-128 到 127 或 0 到 255unsigned char1 字节0 到 255signed char1 字节-128 到 127int2 或 4 字节-32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647unsigned int2 或 4 字节
2020-12-02 22:34:20
789
2
原创 C语言字节对齐、位域、枚举、联合体
C语言字节对齐什么是字节对齐现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。为什么要字节对齐■ 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址 处取某些特定类型的数据,否则抛出硬件异常。 ■ 性能原因: 数据结构(尤其是栈)应该尽可能地在
2020-12-01 16:55:50
3711
9
原创 C常用字符串模拟、内存重叠问题
C常用字符串函数模拟当我们在模拟字符串函数的时候需要注意两点:■ 检查参数合法性■ 对指针进行参数保护字符串长度strlen注意点:字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。参数指向的字符串必须要以 ‘\0’ 结束。注意函数的返回值为size_t,是无符号的(易错)。//注意返回值是size_tsize_t my_strlen(const char *string) { assert(strin
2020-11-28 22:32:00
3466
8
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人