自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 POSIX信号量

虽然生产者在执行生产操作前申请的是空间资源,但生产完数据后,应对数据资源data_sem信号量进行释放操作,而不是释放空间资源,因为此时空间资源的数目还是环形队列容量-1,即生产者生产完数据后,空间资源blank_sem信号量少了一个,而数据资源data_sem信号量多了一个,因此对data_sem资源进行释放才是合理。blank_sem空间信号量的初始值应为环形队列的容量,因为在生产初期,环形队列中没有数据,dota_sem数据信号量的初始值应为0,因为生产者没有执行生产,环形队列中没有数据。

2023-10-21 23:43:37 161

原创 算法专题:双指针

nums[left]为左区间的最小值,而nums[right]为左区间的最大值,若此时nums[left]与nums[right]之和小于10,则此时在数组 nums中nums[left]无法与10组成三角形;输入一个递增的排序数组和一个数字S,在数组中查找两个数使得它们的和正好是S,如果有多对的数字和为S,则输出任意一对即可。散乱数组:nums{0,1,0,3,12 }==》nums{1,3,12,0,0}以{2,2,3,4,5,8,9,10}为例。示例:如nums={2,2,3,4}

2023-10-19 00:56:45 300

原创 传输层TCP协议

前言传输层的历史渊源可以追溯到计算机网络的早期阶段。在20世纪60年代和70年代,计算机网络主要是由一些简单的点对点连接组成的。这些连接通常使用专用的硬件和协议,例如串行线路和电话线路。在这种情况下,传输层的功能是由这些协议本身来提供的。随着计算机网络的发展,各种传输层协议也随之涌现,保证了即使在网络规模大和网络复杂性高、网络通信双方的距离变得越来越远的环境下也能可靠的进行通信。其中最早的传输层协议之一是UDP协议,它最初是在1980年代初期由David P. Reed设计的。

2023-10-08 19:39:42 234

原创 数据结构——红黑树

为什么有了AVL树还需要红黑树?AVL树的出现解决了二叉树会退化为单链表的情况,能把搜索时间控制在O(logN),不过却不是最佳的。因为AVL树的插入和删除,可能会破坏AVL树中的左子树和右子树高度差不超过1的规则,即大量的插入结点和删除结点可能会引发频繁的旋转操作。使得AVL树的性能大打折扣,为了解决AVL树会频繁旋转的问题,又发明了红黑树。

2023-10-07 18:29:20 466

原创 图解AVL树的旋转操作

我们将树的结点定义为三叉链结构,方便实现回溯更新结点的平衡因子,并定义平衡因子为右子树高度-左子树高度。//三叉链结构//左结点//右结点//父结点//存储的键值//平衡因子int _bf;//右子树的高度-左子树的高度,_kv(kv),_bf(0){}

2023-10-06 21:08:05 125

原创 生产者消费者模型

生产者消费者模型是一种用于描述多线程编程中的协作关系的模型。该模型基于生产者和消费者的角色,生产者负责生产数据,消费者负责消费数据,在一个共享的缓冲区中协作完成数据传递。在该模型中,多个生产者和多个消费者可能同时存在,对于生产者而言,如果缓冲区已经满了,就需要等待消费者来消费,直到缓冲区有空闲位置后再进行生产;对于消费者而言,如果缓冲区已经为空,就需要等待生产者来生产,直到缓冲区中有数据后再进行消费。生产者消费者模型可以用于解决多线程编程中的同步和互斥问题,有效提高系统的并发性和效率。

2023-09-30 20:48:43 216

原创 Socket编程基础(1)

因为服务器就是为了给别人提供服务的,因此服务器必须要让别人知道自己的IP地址和端口号,IP地址一般对应的就是域名,而端口号一般没有显示指明过,因此服务端的端口号一定要是一个众所周知的端口号,并且选定后不能轻易改变,否则客户端是无法知道服务端的端口号的,这就是服务端要进行绑定的原因,只有绑定之后这个端口号才真正属于自己,因为一个端口只能被一个进程所绑定,服务器绑定一个端口就是为了独占这个端口。源MAC地址是指发送数据包的主机的网卡的MAC地址,目的MAC地址是指接收数据包的主机的网卡的MAC地址。

2023-09-21 16:27:41 205

原创 进程间通信——共享内存

单独使用IPC_CREAT: 创建一个共享内存,如果共享内存不存在,就创建之,如果已经存在,获取已经存在的共享内存并返回。IPC_CREAT | IPC_EXCL: 创建一个共享内存,如果共享内存不存在,就创建之, 如果已经存在,则立马出错返回 -- 如果创建成功,对应的shm,一定是最新的!关于shmget( )的第一个参数key,是用于标识共享内存的唯一性,通过调用ftok( )使用一定的算法生成的。注意:共享内存的创建只需一个进程进行即可,其余要进行通信的进程,则需要获取共享内存。

2023-09-14 17:22:04 318

原创 Linux线程互斥与同步

例如,现在有两个线程访问一块临界区,一个线程往临界区写入数据,另一个线程从临界区读取数据,但负责数据写入的线程的竞争力特别强,该线程每次都能竞争到锁,那么此时该线程就一直在执行写入操作,直到临界区被写满,此后该线程就一直在进行申请锁和释放锁。多个线程并发的操作共享变量,会带来一些问题。1、首先需要明确的是,单纯的加锁是会存在某些问题的,如果个别线程的竞争力特别强,每次都能够申请到锁,但申请到锁之后什么也不做,所以在我们看来这个线程就一直在申请锁和释放锁,这就可能导致其他线程长时间竞争不到锁,引起饥饿问题。

2023-09-08 13:58:24 134

原创 Linux线程

例如内存空间、文件句柄、网络连接等。而是将错误代码通过返 回值返回。注意: 在Linux中,应用层的线程与内核的LWP是一一对应的,实际上操作系统调度的时候采用的是LWP,而并非PID,只不过我们之前接触到的都是单线程进程,其PID和LWP是相等的,所以对于单线程进程来说,调度时采用PID和LWP是一样的。注意: 用pthread_self函数获得的线程ID与内核的LWP的值是不相等的,pthread_self函数获得的是用户级原生线程库的线程ID,而LWP是内核的轻量级进程ID,它们之间是一对一的关系。

2023-09-07 13:20:38 63

原创 Linux——进程间通信(匿名管道、命名管道、共享内存)

阻塞情况就能够很好的说明,管道是自带同步与互斥机制的,读取的进程和写入的进程是有一个步调协调的过程的,不会说当管道没有数据了读端还在读取,而当管道已经满了写端还在写入。同样的,当读进程从管道中读取数据时,如果写进程没有往管道中写入数据,则读操作也会被阻塞,直到写进程往管道中写入了数据。在管道文件通信中,互斥指的是保证进程对同一管道的访问是有序的,一个进程在写入数据到管道时,其他进程只能等待其写入完成后才能进行读取操作,或者相反,一个进程在读取管道中的数据时,其他进程只能等待其读取完成后才能进行写入操作。

2023-08-25 08:29:15 232

原创 二叉搜索树

树是一种非线性数据结构,它是由n(n>=0)个有限节点组成一个具有层次关系的集合,把它叫做“树”是因为它看起来像一棵倒挂的树,叶子朝下,根朝上。树具有以下特点:1、每个结点有零个或多个子结点;2、没有父结点的结点称为根结点;3、每一个非根结点,有且只有一个父结点;4、除了根结点外,每个子结点,可以分为多个不相交子树;定义:每个结点最多有两个子树的树结构。二叉树性质:性质1:二叉树第i层上的结点数目最多为2^(i-1)个结点。

2023-07-09 09:27:06 69

原创 C++中的继承

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保 持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。public:protected:string _name = "张三";///姓名//年龄protected:int _stuid;//学号protected:int _jobid;//工号继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。

2023-06-18 19:34:28 364

原创 归并排序(C语言)

采用分治的管理方法,校长管理年级主任,年级主任管理各班班主任,班主任再通过在班上将管理问题进行分解,如选取班长等各种班干进行管理。这样就将一个大的问题分解成一个一个小的问题。归并:当一个子数组分成左右两个子数组,且左子数组和右子数组只又一个元素时,只要从这两个有序数组中选取较小的元素放在辅助数组中,同理又从排序好的子数组中选取较小的元素放在辅助数组中,直到把所有的元素取完。归并排序就是利用这种思想实现的,先将待排序的数组分成两半,将这两半子数组排好后,再合并成一个数组。

2023-06-16 22:02:30 54

原创 【数据结构与算法】插入排序和希尔排序(C语言版)

1. 希尔排序是对直接插入排序的优化。2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的 希尔排序的时间复杂度都不固定。希尔排序的其他例子。

2023-06-02 23:28:14 88

原创 Linux环境基础开发工具vim/gcc/gdb使用

实例: gcc hello.o –o hello 在这里涉及到一个重要的概念:函数库 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而 没有定义函数的实现,那么,是在哪里实“printf”函数的呢?「/关键字」: 先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按 「n」会往后寻找到您要的关键字为止。」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直 按「n」会往前寻找到您要的关键字为止。

2023-06-01 13:01:27 225

原创 图解快速排序算法

这种情况是R找到了一个比基准值小的元素等待L去找一个比基准值大的元素,与R所在位置的元素进行交换,如果L与R相遇了,就表示没有找到,一种是L停住了,R在寻找比基准值小的值时遇到L,相遇的位置就是L停住的位置。所谓的三数取中,是指在待排数组中的首元素和最后一个元素以及中间位置,在这三个位置中选取元素数大小排在中间的值,做为基准值这样就可以防止O(N^2)的情况出现。设要排序规模为N的数组所花费的时间T(N),那T(N)等于分割数组时花的时间加左右子序列所花的时间,分割数组时会遍历数万花时间为O(N)

2023-05-31 15:19:48 70

原创 【Linux】文件基础IO(上)

在windows中的文件,它们在linux中也是文件,其次在windows中不是文件的,比如进程,磁盘, 显示器等硬件在Linux中都被抽象成了文件,甚至一些很离谱的东西,比如管道,也是文件。不管是我们常说的文本文件,还是硬件文件操作系统都会用一个struct file类型的结构件去描述相应的文件,这个类型的结构体非常复杂里面包含文件的各种属性,如是否可以被执行、是否可以被写入等各种信息还有对应的读写函数指针,对硬件的操作主要是读写操作,如在我们用户角度看键盘是用来向操作系统写入输入数据的,在操作系统角

2023-05-23 22:45:34 66

原创 STL——vector的使用及模拟实现

vector向量容器不但能像数组一样对元素进行随机访问,还能在尾部插入,是一种简单的、高效的容器,值得注意的是,vector具有内存自动管理功能,对元素的插入和删除,可以动态调整对象所占空间的大小。现在我们来尝试模拟vector容器模拟。为与标准库中的vector区别,我们在my_vector命名空间模拟实现。

2023-05-16 19:59:22 61

原创 剑指Offer经典题目——从尾到头打印链表

看到题目后,我们的第一 反应就是要去遍历链表,然后呢?但题目给我们的链表结构是单链表,只能从一头往一头前进,也就是后遍历的先打印, 先遍历的后打印,是典型的后进先出”,于是我们想到了找。我们可以将遍历到的节点压如栈, 再往下走,直到遍历完链表。基于递归的代码看起来很简洁,但当链表非常长的时候,就会导致函数调用的层级很深,从而有可能导致函数调用栈溢出。其次我们还可以用递归来实现我们要打印一个节点,先递归打印它后面的节点,在输出该节点。题目描述:输入一个链表的头节点,从尾到头打印每个节点的值。

2023-05-13 23:37:23 34

原创 Linux——进程控制

但如果子进程要去执行不同于父进程的任务,子进程就需要独享资源,需要有不同于父进程的代码和数据,这也是进程独立性的体现。而对于父进程来说,子进程是需要被标识的,因为父进程创建子进程的目的是让其执行任务的,父进程只有知道了子进程的PID才能很好的对该子进程指派任务。子进程不一定会执行和父进程一样的功能,所以子进程不会使用父进程的所有数据,并且在子进程不对数据进行写入的情况下,并不会必要对数据进行拷贝,我们应该按需分配,在需要修改数据的时候再分配,写时拷贝是一种按需申请资源的策略,这样可以高效的使用内存空间。

2023-05-10 20:09:11 102

原创 c++模板初阶

函数模板它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供 调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然 后产生一份专门处理double类型的代码,对于字符类型也是如此。

2023-05-08 11:55:44 33

原创 深入理解虚拟内存

回想一下我们网购时填地址时的情况,都是先填写省级行政区,然后系统会将省级行政区下的市级行政区列出来供我们选择。如果系统直接将全国所有市级行政区列出来让我们挑选的话,那用户肯定要被气死。

2023-05-07 20:17:35 64

原创 【数据结构与算法】——二分查找

面试官:你看mid=(Left+Right)/2,这行代码,Left和Right都是整形,当我们要 在一个很大的数据量中查找时,这时的Left和Right就会很大,lLeft+Right就容易产生溢出,结果就应为负数那么mid=(Left+Right)/2也就为负数了,程序就错了。A:你给的数字是有序的,所以没有必要一个一个比较,可以逐渐缩小要查找的范围来查找,我们可以先看中间的元素,如果是15,就直接找到了,如果15比中间的元素大,那就应该去中间元素的右边去找,反之,在左边找。尴尬的笑了笑说看不出!

2023-05-05 16:48:37 164

原创 浅谈Linux进程地址空间

在代码中我们定义一个全局变量,在创建子进程后,子进程对这一变量进行写入修改变量的值,而父进程则不改变变量的值。代码在刚运行时子进程的g_val和交进程的g-val输出的值是一样的它们的地址编号也是一样的,但随着程序的运行,子进程将g_val的值自增了,也就是改了,可是父进程的g_val还是没变,但父进程的g_val和子进程g_val的地址编号从始至终都是一样的,也就是子进程对全局变量数据的修改并不影响父进程,这是因为进程具有独立性,那么操作系统为了让进程具有独立性它做了什么?记录每个进程所申清的内存。

2023-05-03 18:13:36 41

原创 详解C++引用和指针的联系与区别

8、指针和引用的自增运算意义不一样,指针是以指句对象内在空间大小 为单位往,后移一个单位而引用是引用对象+1。4、操作方式:指针可以对指向的对象进行修改,即可以指向其他对象,而引用只是对所引用的对象进行访问或修改。3、内存占用:指针需要一定的内存空间来存指针变量自身的地址,而引用则不需要占用额外的内存空间。7、sizeof(引用)得到的是引的对象的大小、而sizeof(指针)得到的是替色本身的大小。2、空值问题:指针可以为空,即指空地址,而引用必须引用必须引用一个已经存在的对象。

2023-05-01 18:21:07 207

原创 关于进程状态的理解

阻塞:进程因为等待某种条件就绪,而导致的一种不推进的状态——就是进程卡住了。就是在等待某种资源。我们在使用Windows操作系统时会因为启动过多的程序而导致卓面卡住了这也是一种阻塞现象,因为多个进程都在等待使用显示器这一资源,而显示器太慢了,跟不上CPU的速度,调度不及,而产生的阻塞。进程要通过等待的方式,等某一具体的资源被别的进程使用完,才被自己使用,阻塞就是等待某种资源就绪的过程。

2023-05-01 16:47:57 98

原创 Linux——进程概念(上)

1. 首先,操作系统将程序加载到内存中。操作系统会从外存中读取程序的指令,并将其复制到内存中。2. 然后,操作系统会分析程序的指令,并将其转换为机器指令,也就是CPU能识别的指令。3. 接着,操作系统会设置CPU的程序计数器(PC)指向程序的第一条指令,然后CPU就可以开始执行程序了。4. 最后,CPU会依次执行程序中的指令,每条指令执行完毕后,PC就会指向下一条指令,直到程序执行完毕。查看进程首先我们编写以下程序,使用getpid()调出进程的进程描述符也就是pid;

2023-04-28 16:22:39 71

原创 【数据结构】C语言实现双链表的增删查改

双链表(DoublyLinkedList)是一种常见的数据结构,它与单链表类似,但每个节点除了前驱指针指向前一个节点外,还有一个后继指针指向后面一个节点,即每个节点拥有两个指针域。与单链表相比,双链表可以在O(1)的时间内实现在任意位置的插入和删除操作,而不需要像单链表一样需要先遍历找到前一个节点。

2023-04-22 20:02:13 315

原创 【C++】模拟string类的实现

string类是C++标准库中一个重要的组件,它提供了一种方便的字符串操作方式。与C语言中字符数组相比,string类更加灵活和易用,可以方便地处理动态大小的字符串,同时也提供了许多重要字符串操作方式,如拼接,分割,替换,查找等。string类本质上是一个封装了一个字符串的数组,可以在运行时根据需要调整字符串的大小。其设计的重要优点是内存自动管理,即它负责调整内存大小,避免了内存溢出或空间浪费的问题。接下来我们来模拟实现string的常用接口。如有错误,欢迎大家指正。string的成员变量。

2023-04-22 13:09:12 140

原创 C/C++内存管理

c:realloc函数用于重新分配已经分配的内存块的大小,它需要两个参数:指向先前分配的内存块的指针,以及新的内存块的大小。如果新的内存块大小大于先前分配的内存块大小,realloc将在堆上分配新的内存空间,并在新的内存块中存储原来的数据块;如果新的内存块大小小于原先内存块的大小则realloc将原来的数据块截取到新的内存中,并释放剩余空间,如果操作成功,返回指向新分配的内存块起始地址的指针。需要注意的是,使用定位new时需要自行保证分配的内存是合法的,并且需要在适当的时候显式地调用析构函数和释放内存。

2023-04-14 19:02:12 49

原创 C++类和对象

1.面向过程和面向对象初步认识C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。以洗衣服为例,C语言是这样做的:拿盆——放水——放洗衣粉——放衣服——手搓——换水——清洗——拧干——晾衣服。C++把这件事分为四个对象:人、衣服、洗衣粉、洗衣机整个洗衣服的过程:人将衣服放进洗衣机、倒入洗衣粉,启动洗衣机,洗衣机就会完成洗衣过程并且甩干。

2023-04-13 23:02:28 61

原创 C++入门篇

1. 补充C语言语法的不足,以及C++是如何对C语言设计不合理的地方进行优化的,比如:作用域方面、IO方面、函数方面、内联函数方面等。2. 为后续类和对象学习打基础。

2023-02-27 18:26:17 105

原创 二叉树(堆)的理解

树是一种树状结构本文讨论树的定义和逻辑结构表示方法和存储结构及常见问题。

2023-01-04 18:01:59 74

原创 图解单链表的增删查改(C语言版附完代码)

图解!链表真的很简单。

2022-12-21 21:13:57 1206

原创 图解线性表顺序存储结构(附完整代码)

顺序表的增删查改

2022-12-18 16:38:41 2218

原创 C语言——动态内存管理

C语言的数据结构通常是固定大小的,一旦程序完成编译,数组元素的数量就固定了。因为在编写程序时强制选择了大小,为了扩大数据库的容易量,可以增加数组的大小,并重新编译程序,但这种数组也会再次填。为了解决以上困绕,C语言支持动态内存分配即在程序执行期间分配内存单元的能力,利用动态内存分配,可以设计根据需要选择扩大或缩小的数据结构。 内存分配函数,要使动态地分配存储空间,要调用三种内存分配函数的一种,这些函数都声明在文件中,这些函数能申请的内存空间属于堆区。malloc函数————

2022-11-03 15:04:28 234

原创 数据结构———算法的时间复杂度和空间复杂度

一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法 的时间复杂度。6. 实例6基本操作执行最好1次,最坏O(logN)次,时间复杂度为 O(logN) ps:logN在算法分析中表示是底 数为2,对数为N。在计算 机发展的早期,计算机的存储容量很小。5. 实例5基本操作执行最好N次,最坏执行了(N*(N+1)/2次,通过推导大O阶方法+时间复杂度一般看最 坏,时间复杂度为 O(N^2)4. 实例4基本操作执行最好1次,最坏N次,时间复杂度一般看最坏,时间复杂度为 O(N)

2022-10-29 19:02:56 63

原创 C++实现通讯录管理系统

通讯录是一个可以记录亲人,好友的工具。利用c++来实现一个通讯录管理系统。系统中需要实现以下功能:添加联系人:向通讯录中添加新的联系人,主要信息包括(姓名、性别,年龄,联系电话,家庭住址,)最多记1000人。显示联系人:显示通讯录中所有联系人。删除联系人:按照姓名删除指定联系人。

2022-10-22 21:35:28 1322

原创 自定义类型————结构体

C语言提供了一系列的内置数据类型,如:char,short,int,long,long long,float,double,bool。用户可以在程序中用它们定义变量,解决一般的问题,但当在处理一些比较复杂的问题时,这些内置数据类型还不能满足应用的要求,所以用户需要自己建立一些数据类型,并用它来定义变量。比如描述一本书时。

2022-10-08 01:04:02 369 2

空空如也

空空如也

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

TA关注的人

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