- 博客(45)
- 收藏
- 关注
原创 计算机系统【用户级缓冲区】
实际上这是因为当讲输出结构重定向到普通文件是,缓冲策略就会变成全缓冲,也就是当用户层面的缓冲区满之后才会将内容刷新到内核缓冲区,或者在进程结束的时候也会将C缓冲区的内容刷新到内核缓冲区。当子进程对数据要进行修改时就会发生写时拷贝,也就是说当子进行对C缓冲区里的数据进行清空刷新时就会发生写时拷贝,这个过程中,父子进程将会拥有两份内容完全一样的C缓冲区,在进程结束之后分别进行清空并刷新到内核缓冲区,再写入到文件中,这样就出现了上面的运行结果。全缓冲:就是当缓冲区装满了之后在进行刷新到内核缓冲区。
2025-03-26 19:45:06
206
原创 C++【红黑树--debug】
可以发现,当前程序死在了对空指针的引用上。程序问题出在 左旋函数上,一般情况下我们需要对第三次的插入过程进行整体分析,因为程序有可能在左旋之前就已经发生了错误;可以看到,程序崩掉了。上一节,手撕了一个红黑树。本来是要封装一下map,结果出现了一个bug是上节没有发现的。右旋函数的判断条件出现错误;至此debug结束;
2025-03-07 20:18:07
158
原创 C++【STL---set&map底层红黑树(RBTree)】
红黑树是搜索二叉树的一种,它不像AVL树那样使用平衡因子严格的限制树的高度。它是通过节点的颜色来实现:树的最长路径不超过左端路径的二倍,从而接近平衡的;红黑树的特点:1、根节点必须是黑色的;2、每条路径上的黑色节点的数量必须是相等的;3、不能出现连续相同的两个红色节点;4、节点的颜色不是红色就是个黑色;5、每条路径都是以空节点进行结束的,所谓的路径包含叶子节点到空节点的那一段;
2025-03-07 14:54:51
575
原创 数据结构【AVL树(平衡二叉树)】
AVL树的出现主要是解决在一些特定情况下的搜索二叉树出现的效率低的问题,因为在一些极端情况下,搜索二叉树的形况可能会发生一些变异,例如下面的情况。从而影响整个数据结构的效率;AVL树通过在节点中引出平衡因子,再插入过程中自适应调节平衡因子,从而使树达到平衡状态。平衡因子的定义:一个根节点的平衡因子=右子树的高度-左子树的高度;AVL树的要求是每一个节点的平衡因子只能是(-1/0/1);如果平衡因子发生变化,那么就要进行自适应调整。
2025-03-05 17:49:49
1219
原创 C++【STL--- set】
set是一个不包含重复元素的内部自动有序的容器。set和map是经典的关联容器,与之前的vector,list,string,stack,priority_queue,deque等顺序容器不同;关联容器和顺序容器的区别在于:数据的存储方式不同当只是想知道一个值在不在时,就可以使用set,查找的时间复杂度为 O(logN);set内部的key不允许被修改。标准库中提供set的关联容器为:1、按关键字有序保存元素:set(保存关键字的容器)、multiset(允许关键字冗余的容器);
2025-03-05 15:39:34
253
原创 数据结构 【搜索二叉树】
搜索二叉树是STL中map和set的重要铺垫,学好搜索二叉树有助于理解map和set的特性。搜索二叉树也是一种二叉树结构,只是多了一些特定的性质。一棵搜索二叉树可以为空树,如果不为空时,一定满足下面的性质。基于先描述在组织的思想,我们可以尝试搭建一个搜索二叉树结构。
2025-02-26 11:54:00
871
1
原创 进程(上)---更高维度的思考
谈到进程想必计算机从业者并不陌生,但是绝大多数人的理解只浮于表面。没有深度的从操作系统的角度来审视进程是不够的,本文将从更深的层次、更高的维度带领读者重新审视进程。
2025-02-25 14:32:06
303
原创 C++【多态】
假设有一个父类和几个子类,它们都有一个名为 “draw” 的方法,父类的 “draw” 方法可能只是一个通用的框架,而子类会根据自身的特点重写 “draw” 方法来实现不同的绘图功能。也就是这里的函数调用只满足的多态的一个条件(调用使用父类的指针或者引用),那么我们尝试满足形成多态的第二个条件: 构成虚函数的重写,先加上virtual ,这里就会注意到如果编译器不统一进行析构函数名称的处理,那么就无法完成重写的条件(三同)。举个例子:以 “吃” 这个行为为例,不同的动物有不同的 “吃” 的方式和内容。
2025-02-20 21:34:50
351
原创 C++【深入 STL--list 之 迭代器与反向迭代器】
接前面的手撕list(上)文章,由于本人对于list的了解再一次加深。本文再次对list进行深入的分析与实现。旨在再一次梳理思路,修炼代码内功。
2025-02-05 00:32:18
810
原创 C++【深入底层,手撕vector】
在前面的扩容、构造中我们使用的数据拷贝均为memcpy,这就存在一个问题,当存放的数据类型为自定义类型数据时memcpy仅仅进行的是浅拷贝。假设vector中存放的数据类型为string,当容器容量需要扩容时,mencpy仅仅拷贝的是string对象的各个成员变量,并没有开辟新的空间,这就意味着当扩容过程中,开辟了新的空间,而新的空间中存放的依旧是就空间中的string对象,当_str指向新的空间之后,就空间就会调用析构函数,此时delete[] 也就会将就空间中的string对象进行释放。
2025-02-01 20:06:31
811
原创 数据结构 【二叉树(中)】
关于二叉树,在这篇文章已经讲到了一些概念。这篇文章主要讲讲关于二叉树的遍历以及关于递归的一些实际问题。在正式探讨二叉树之前,我们快速构建一个简单的二叉树,方便我们后续的操作。我们按照下图的连接方式构造一棵简单的二叉树。
2025-01-14 19:09:56
518
原创 C++ 【从零手撕,模拟实现list类(上)】
从list源代码中我们可以看到list底层为带哨兵位双向循环链表,从设计者的角度来看,我们并不知道用户在链表中存储的数据类型,所以在这里要使用类模板。再者,每一个节点都包含了前向、后向指针和存储的数据值,所以在这里也可以将每一个节点封装成一个类,结点中的数据必须要在链表中能被访问,所以在设计结点的类时,类中的成员属性应该能被外部访问,即节点类内部应当使用相应的访问限定符进行修饰,也可以直接将class换成struct(struct默认访问限定符为public)
2025-01-13 16:34:30
882
原创 C++【深入底层,从零模拟实现string类】
在学习了类和对象、模板等前期的C++基础知识之后,我们可以尝试根据C++标准库中所提供的接口类型,来搭建我们自己的string类型。这个过程有助于初学者掌握C++的基础语法及底层逻辑。
2025-01-10 14:44:48
1018
原创 一键配置vim编辑器【一分钟手把手教程】
前段时间翻看giitee发现一个已经打包好的vim配置文件,只需要在命令终端下载安装即可。需要说明一下,这个配置文件暂时只支持Centos7.
2024-12-31 16:48:05
322
原创 C++【内存管理】
c/c++中程序的内存划分:1、栈:又称堆栈,存放非静态的局部变量、函数参数、返回值等等,栈是向下增长的。2、内存映射段:是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可以使用系统接口创建共享内存,做进程间的通信。3、堆:用于程序运行时动态内存分配,堆是向上增长的。4、数据段:存储全局数据和静态数据。5、代码段:存放可执行的代码、只读常量。
2024-12-31 14:20:42
456
原创 C++【默认成员函数(下)】
必须是要拷贝的类类型对象的引用。使用传值方式编译器会直接报错,因为会引发无穷递归。为了保证正确传参,在形参位置上一般加上const修饰。C++对于内置类型传参时,实参会直接拷贝给形参。而对于自定义类型进行传参时,实参要先通过自定义类型的拷贝构造函数完成拷贝。所以拷贝构造函数的形参如果写成传值方式的话,就会引发无穷递归,但是使用传引用传参就不会调用拷贝构造函数。
2024-12-18 17:30:51
814
原创 C++ 【默认成员函数(上)】
默认成员函数是指在一个什么成员都没有的空类中,编译器会自动生成的成员函数叫做默认成员函数。类的6个默认成员函数为:1、构造函数(进行初始化)2、析构函数(进行清理)3、拷贝构造函数(同类对象初始化创建对象)4、赋值重载函数(一个现存对象的值拷贝给另一个现存对象)5、普通对象取地址(很少自己实现)6、const 对象取地址(很少自己实现)
2024-12-17 16:54:51
1176
原创 C++ 【类和对象】
C是面向过程的编程语言。关注的是求解问题的过程。而c++是面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的相互交互完成。
2024-12-13 21:33:03
716
原创 C++ 【衔接篇】
定义命名空间需要使用namespace关键字,后面跟命名空间的名字,然后需要接一对大括号{},这里需要与结构体的定义进行区分,命名空间的在定义之后没有分号。大括号中即为命名空间的成员。一般情况下,程序对于变量的访问顺序为:局部优先 其次全局。命名空间就像是一个隔离房,只有将房门打开和指定的方式才能访问到空间内的变量。也就是说,要么直接打开房门,要么指定去这个房间寻找。
2024-12-10 22:03:39
1005
原创 数据结构 【堆排序】
上面两篇文章中,我们可以了解到大堆的堆顶存放的是堆中最大的元素,小堆的堆顶存放的是堆中最小的元素。利用堆的这个属性就可以实现排序的目的。如果排升序,那么使用大堆选取堆中最大的数据放置在堆顶,将堆顶元素与堆中最后一个元素进行交换,将最大的元素排除在外进行向下调整,循环遍历整个堆就可以得到原数据的升序排列。如果排降序,同样的道理,先选取小堆的堆顶,得到堆中最小的元素,将其与堆中最后一个元素进行交换位置,将最后一个元素排除在外,再进行向下调整,遍历整个堆,就会得到原数据的升序排列。
2024-12-01 17:39:20
1155
原创 数据结构 【堆实现】
上文提到堆是一种特殊的二叉树,其中它的父结点均不大于或者不小于其子结点的值。堆总是一棵完全二叉树。其中,堆的父节点全部不小于它的子结点时称为大堆,堆的父结点全部不大于其子结点的堆称为小堆。堆可以由两种结构来实现,分别是顺序结构和链式结构。这里我们先来实现堆的顺序结构。堆中各结点的父节点与子节点在数组中存放的位置有下面的关系:下面,我们就来一起实现一下堆这个数据结构。
2024-11-27 17:26:10
633
原创 数据结构 【双向哨兵位循环链表】
链表的结构分为8中,其实搞懂了单链表和双向哨兵位循环链表,这部分的知识也就掌握的差不多了。双向哨兵位循环链表的结构如下:下面我从0构建一个双向哨兵位循环链表。
2024-11-26 16:45:50
1121
原创 数据结构 【带环链表2】
分析:这道题目可以拆分成两个部分,第一:检查链表是否带环。第二:返回带环链表的第一个进环节点。说到带环链表,有一道题目是这样说的,如果一个链表存在环,那么就返回进入环的第一个节点,如果链表没有环,那么就返回空。随即问题得到转化,可以先计算headA和headB的长度,计算出长度之前的差值,让长的链表先走差值步,然后两个链表同时往后走,在第一次。所以算法的设计思路为:当meet和start从相应的条件开始移动时,它们相遇的节点就是链表环的入口节点。第二种解法:转换法(将环断开,转换成求链表的第一个交点问题)
2024-11-21 21:56:53
665
原创 数据结构 【带环单链表】
在单链表中可能会存在一种情况,某一结点在经过几次转移之后回到了自己本身,这种情况就称之为带环链表。对于带环链表,我们不能轻易对其进行遍历,遍历可能会导致产生死循环。如何判断一个链表带环是在面试过程中常见的问题,这里介绍一个利用快慢指针检测链表是否带环的方法。带环链表的逻辑图如下所示:(这里只展示一种简单情况)
2024-11-20 16:02:33
464
原创 数据结构 【单链表】
数据域用于存储实际的数据,而指针域则存储指向下一个节点的地址。单链表的特点包括动态存储、非连续存储、易于插入和删除。节点可以定义成一个结构体,每个节点中包含一个数据和下一个节点的地址。上面的结构体定义了一个节点,节点中存放的数据类型被定义成了SLDataType类型,节点的名称叫做SLNode。
2024-11-16 13:56:07
1746
1
原创 C 语言 【模拟实现内存库函数】
memcpy函数是C/C++语言中的一个用于内存复制的函数,声明在 string.h 中(C++是 cstring)。其中,destination表示的是要拷贝到的目标起始地址,source表示要拷贝内容的起始地址,num表示要拷贝的字节数。函数的作用为:将 num个bytes 的值从 source 指向的位置直接复制到destination 指向的内存块。模拟实现:我们可以看到,destination和source指针的类型均为void*类型,也就是说传入的指针变量不知道它的具体类型。
2024-11-13 11:50:02
1060
原创 C语言 【大白话讲指针(中)】
在之前的文章中我们已经知道了指针的概念,指针就是一个变量,用来存放地址,地址指向唯一一块内存空间。指针的大小是固定的4/8个字节(32为机器/64位机器)。指针是有类型的,指针的类型决定了指针加减整数的步长,也指定了该指针在解引用操作时候的权限。
2024-11-08 21:18:43
787
原创 C语言 【通讯录项目】
联系人自定义排序就是可以按照用户的需求进行排序,例如按照名字首字母的顺序、年龄的大小等联系人拥有的信息进行排序。C 语言 【排序算法---qsort()】-优快云博客//按年龄升序排序printf("已完成排序!\n");运行结果:到这里一个简易的通讯录就已经完成了,喜欢的读者请一键三连!
2024-11-07 22:22:10
883
原创 C 语言 【结构体】
结构体是一个自定义数据类型,这里可以做一个类比。让我们回顾一下什么是数组,数组是一种元素类型相同的集合,这个集合统称为数组。那么,结构体可以理解成一组元素类型不同的集合。再清晰地来说,结构是一些不同类型值的集合,这些值被称为成员变量(结构的每个成员变量可以是不同类型的值)。有了结构体类型,那如何定义变量,其实很简单。int x;int y;}p1;//声明类型的同时定义变量p1//定义结构体变量p2p1是在创建结构体类型时就创建的结构体变量,p2是在结构体创建之后创建的变量。
2024-11-07 21:02:26
1239
原创 C 语言 【排序算法---qsort()】
在前面的文章中,我有总结简单的冒泡排序算法。在之前写到的冒泡排序算法的适用范围还是比较狭窄的,它只能适用于整型数据,让我们来简单回顾一下。假设待排序的数据有个,那么就需要趟冒泡,每趟排序需要进行次判断,如果前一个数大于第二个数就进行交换。代码运行结果:现在的代码只能对整型数组进行排序,我们可以对其进行改造。让其可以适用于其他类型的排序,比如浮点型、自定义类型(结构体等)。不过在这之前,我们需要学习库函数qsort()以实现对bubble_sort()的改进。
2024-10-30 17:20:16
577
1
原创 C语言 【句子倒叙】
在学期C语言前期,经常会遇到一个经典的题目:倒序字符串。这个题目利用指针可以很简单地得到解决。句子倒叙需要用到这个思想,在正式句子倒叙之前我们先来倒叙字符串。那么对于句子倒叙这个题目来说,假设输入:hello world!hello 句子中的单词位置发生倒叙,而单词本身不发生倒叙,这里进行输入输出测试:输入hello world!
2024-10-29 15:59:14
563
原创 C 语言 【大白话讲指针 (上)】
在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于指针可以找到内存单元的内容,我们可以把指针理解成内存单元的编号,类似于人的身份证号码,对于每一块内存单元来说,在一个指定的计算机上,该内存单元的指针(地址)是独一无二的。广义上的指针是地址,严格意义上来说,指针其实叫做指针变量。而指针变量中存放的内容就是地址。//在内存中开辟一块空间。
2024-10-29 15:29:56
1018
原创 C 语言 【为什么程序死掉了??】
当i>9时,数组进行了越界访问,越界访问时数组有可能会访问到位于数组存储位置上方的变量i,这就很危险,因为i是循环控制变量。这个案例也在提醒我们在写代码的过程中要注意不能对数据进行越界访问,合理规范的访问数据,可以规避一些程序错误的风险。栈区的使用规则是根据程序的运行,自上而下为函数中的局部变量开辟空间。今天遇到一道有意思的题目,在最初看到的时候没有发现任何问题,可是在运行的时候程序莫名其妙的死循环打印。仔细想了想,原来是变量在定义的时的内存空间分布问题、栈区内存的使用问题结合在了一起。
2024-10-25 21:22:34
397
原创 C 语言 【删除序列中的指定元素】
首先现有一个数组arr[]={1,2,3,4,5,4,6,7,8},假设我要删掉数组中4这个元素。那么我可以将原始数组想象成皇帝的候选妃子,皇帝的癖好是不喜欢太瘦的人,这里假设4就是瘦子。现在就是太监(i)挨个检查候选的妃子,符合标准的让太监(j)放进arr[]。不符合的就淘汰!
2024-10-25 10:17:16
1308
原创 C 语言 【倒序字符串】
这里要注意的是,输入的字符串中可能包含空格,常规的输入函数scanf("%s"),在输入中有空格时就会中断。所以常规的输入函数不能满足该题目的要求,这里有一个比较小众的输入模式的更改即:scanf("%[^\n]"),有了这样的设置,输出函数会在扑捉到回车(\0)之后才会停止。今天来讨论一道经典题目,使用函数倒序字符串的内容,要求:字符串中可能包含空格。C语言的标准库中有一个gets()函数,具体解释可以参考cplusplus网站给出的信息,输入:I am a student。
2024-10-24 09:47:34
499
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人