自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 【Linux】ELF文件与库的加载

了解了动静态库的制作与使用后,我们直到库本质上就是.o文件的集合。我们在开发过程中,也经常将所有的源代码先编译成.o后统一进行链接,为什么不直接将所有的.c源文件编译成可执行程序呢?

2025-04-02 18:43:25 940

原创 【Linux】动静态库的制作与使用

我们学习c/c++至今,每一次代码的编写都使用到了c/c++的标准库。库其实就是将一些常用的方法总结了起来,并进行实现,之后当我们再需要使用该方法时,就直接使用库中实现好的即可。所以,库其实就是常用方法的二进制集合。本质上,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。静态库Linux(.a) windows(.lib)动态库Linux(.so) windows(.dll)1.动静态库中,其实根本不需要包含main函数,所有的库不论动静,本质上都是源文件对应的.o目标文件。

2025-03-31 17:00:43 799

原创 【Linux】Ext文件系统

在之前,我们已经了解了进程以及文件IO方面的知识,但是这些都是在内存中进行的。而文件在加载到内存之前都是存储在外设——磁盘(disk)中的。那文件是怎么在磁盘中存储的呢?我们在下面一起讨论。

2025-03-30 10:59:09 722

原创 【Linux】基础IO

首先我们已经知道,在Linux下,一切皆文件。文件 = 文件内容 + 文件属性,所以一个文件的内容为0kb,但是其也占磁盘空间。所以对文件的操作其实就是对文件的内容和属性进行一系列的操作。对文件操作,需要先打开文件,而打开文件的不是别人就是进程。所以对文件的操作,本质上是进程对文件操作。一个进程有可能同时会打开多个文件,且一个文件可能同时被多个进程打开。所以操作系统要对打开的文件进行管理——先描述,在组织。C语言里面的库函数fopen/fclose等文件操作的函数,本质上是对系统调用的封装。

2025-03-27 13:02:49 1054

原创 自定义minshell

我们在前面已经了解了进程的概念,以及如何进行进程控制。接下来我们就使用这些知识,来自己实现一个shell即命令行解释器!!!

2025-03-24 21:26:35 708

原创 进程控制~

我们可以通过./cmd来运行我们的程序,而我们运行的程序就是bash进程常见的子进程。当然我们也可以通过fork()系统调用来创建进程。NAMESYNOPSISfork会对子进程和父进程返回不同的返回值,对子进程返回0,对父进程返回子进程的pid,如果返回值小于0,则说明子进程创建失败。

2025-03-19 21:04:17 845

原创 栈(LIFO)算法题

注意,我们需要重复处理,而不是处理一次相邻的相同元素就结束了。对示例来说,如果只进行一次处理,结果为aaca,但是处理之后又出现了相邻的重复元素,我们还得继续处理,最后结果就是ca。解法:借助栈来模拟我们可以将字符串中的元素依次入栈,元素入栈前判断是否与栈顶元素相等,如果相等就弹出栈顶元素,继续判断下一个元素。等到字符串全部入栈,栈中的就是最终答案。但是我们没有必要弄一个stack出来,因为这样最终结果是逆序的,我们可以采用string来模拟栈的行为。

2025-03-16 22:08:23 694

原创 字符串算法题

题目要求找出所有字符串的公共前缀,如果没有公共的前缀就返回空字符串。我们以第一个字符串为标准,依次比较所有字符串的每一位,如果都相同,则比较下一个位置,如果不同,那么前一个位置就是最长的公共前缀。在纵向比较的时候要避免越界,因为第一个字符串的长度有可能比后面的字符串长,所以除了字符不相等外,i越界,也是一个判断条件。两个两个字符串进行比较,用它们得出的前缀和与第三个字符串继续比较。重复该过程。如果在某一个比较过程中发现前缀和的长度变为0,那就说明所有字符串没有公共的前缀和。

2025-03-16 20:57:40 882

原创 【Linux】进程

按课本上来说,一个正在执行的程序的实例就是一个进程;按操作系统内核来说,使用了CPU资源的实体,就是一个进程。这样说还是有点抽象。程序其实就是一个又一个的二进制文件,当它们还没有被运行时存储在磁盘中,所以我们通过./cmd的方式,将它们加载到了内存中,此时内存中就会有一份该程序的代码和数据的拷贝,那么一个程序被加载到了内存中是否就是一个进程呢?首先我们要知道的是,可能同时有多个程序被加载到了内存中如果这些都是进程的话,那么操作系统就要对这些进程管理,而操作系统对任何软硬件的管理都是先描述在组织。

2025-03-15 16:34:05 667

原创 哈希表算法题

因为数组是无序的,所以我们无法直接使用双指针。找两个数之和为target,我们可以固定一个数x,然后在其前面找有没有一个数等于target-x。如果没有,我们x就走到下一个位置。然后重复找前面有没有一个数等于target-x的过程。这个算法是否正确呢?答案是肯定的。因为如果我们从后往前看的话,就知道,其实就相当于是个反向的暴力。我们在反向遍历的过程中,一直在找该数的前面有没有target-x的这个数出现过。

2025-03-15 12:34:40 549

原创 链表算法题目

cur2指向头节点,cur1指向空,然后用cur2遍历原链表,遍历的同时,让cur2的next指向cur1,实现逆置,然后让cur1走到cur2的位置,然后cur2走到下一个位置。所以我们也要保证进位不为0。返回的过程中,将该层的head的next的next指针指向自己即head的前一个节点的next指针指向自己,此时就达到了后一个指向前一个,接着将head的next指针指向空,避免成环。简单来说,对于原链表来说,每两个一组的节点,第一个节点是新链表的第二个节点,第二个节点是新链表的头节点。

2025-03-08 21:20:39 929

原创 【Linux】冯诺依曼体系结构-操作系统

我们所使用的计算机,如笔记本等都是按照冯诺依曼来设计的:截止目前,我们所知道的计算机都是由一个一个的硬件组装起来的,这些硬件又由于功能的不同被分为了输入设备,输出设备,存储器和cpu。:键盘,鼠标,话筒,摄像头,网卡,磁盘等等……:显示器,网卡,磁盘,打印机等等……而存储器其实就是我们所说的内存,而CPU是由运算器和控制器组成的。

2025-03-04 16:48:51 854

原创 分治——归并排序算法题

在合并阶段,我们无法在原数组进行合并,需要借助一个。

2025-02-25 21:38:30 723

原创 分治——快速排序算法题

分治解决问题的思想就是大事化小,将一个大问题分解成若干个子问题。这道题其实就是让我们对数组进行操作,使操作之后的数组呈现出三段区间[0,left],[left+1,right-1],[right,size-1],这三个区间的元素分别都是0,1,2.既然是进行数组分块,我们就可以使用双指针的思想来解决:首先定义一个指针i;然后在分别创建两个指针和我们的目的是将数组分为三块,。

2025-02-24 17:08:48 943

原创 模拟算法题

模拟算法题我们只需要按照题目的意思一步一步走,将这些步骤转换成代码即可题目要求将字符串中所有的问号都改为其他字母,但是要求不能与左右两边的字母重复,返回一种结果即可。遍历原字符串,当遍历到问号时,我们遍历26个英文字母,找到既不与前面相同也不与后面相同的字母,修改该位置,继续遍历。在遍历的过程中需要注意首元素以及尾元素,它们只需要判断相邻的一个元素即可,要避免越界访问。

2025-02-06 18:12:20 700

原创 位运算算法题

法一:我们直接借助一个字符数组来模拟哈希表统计字符串即可,并且我们没有必要先将所有字符都放入字符数组中,边插入边判断,当我们要插入某个字符的时候,发现其已经出现了,此时必然重复,直接返回false。法二:因为字符串只包含26个小写字母。我们可以用一个int变量的26个bit位来依次表示26个小写字母。0表示没出现,1表示出现,如果遍历到那个字符,发现其对应的二进制位为1,表示该字符重复出现,返回false。我们首先定义一个int变量mark来记录字符的出现次数。

2025-02-02 17:40:50 976

原创 基础位运算

左移操作符,使二进制向左边移动指定位数,同时在其右侧补0左移操作符可以用来提高乘法的效率:2*n -> 1<<n,x*2*n -> x << n。

2025-01-30 21:08:34 727

原创 前缀和——矩阵区域和

我们这里的mat数组是从0,0位置开始的。而我们在预处理dp数组时,为了避免边界情况(计算后的下标小于0),下标是从1,1开始的。所以我们在预处理时加最后的d时,其实对应的是mat数组的mat[i-1][j-1]还有就是使用dp数组时,answer返回数组的下标是从0,0开始的,而dp数组从1,1开始才是有效数据。就如示例一种answer的(0,0)位置的值,它的左上下标已经越界了,所以我们要对其进行处理。题目所求的矩阵, 本质就是需要求一段矩阵的和,所以快速求矩阵的和我们就可以使用二维前缀和来解决问题。

2025-01-26 16:39:55 976

原创 前缀和——连续数组

因为最终结果ret = i - dp[sum].说明此时(0,i)这个区间满足要求,长度是i+1.而直接用公式i-mp[sum] = i.为了满足结果,所以dp[0] = -1.但是我们在遍历的过程中,可能有很多相等的sum,它们对应的下标不同,但是如果哈希表中已经有了sum,就没必要再插入了,因为后面插入的sum对应的下标更大,最终的结果就更小。我们可以对数组进行转换,让我们找0,1相等的数组,我们可以将0变为-1,此时问题就转变为求和为0的最长的子数组。经过转换,这道题就类似于求和为k的子数组了。

2025-01-24 17:01:33 313

原创 前缀和——和可被k整除的子数组

所以我们的问题就转化为了,当遍历到i位置的时候,其实sum%k就已知了,我们只需要在(0,i-1)这个区间里面,找有多少个前缀和的余数 == sum%k的即可。还有就是有可能导致漏答案:[-1,2,7] k = 2,当遍历到2时,此时-1%2 = -1,如果不进行修正,2这个答案就漏掉了,但是我们对余数进行修正—— (-1+2)%2 = 1,与当前位置的前缀和1的余数相等。第三点就是C++负数对正数取模,它的结果是一个负数,我们需要对其进行修正,所以我们让其加上一个k,sum%k +k。

2025-01-24 17:00:57 277

原创 前缀和——和为k的子数组

当right走到了结尾之后,此时left++,right又要回到left的位置重新遍历,所以left和right并不是向同一方向移动,所以不能使用滑动窗口解决问题。我们将数组分为两部分,一部分是以i为结尾的子区间,另一部分是x区间,而这两个区间之和就是dp[i],所以满足k+x = dp[i]。所以如果以i为结尾的子数组和为k的话,则x子数组一定满足dp[i]-k。所以我们需要借助一个哈希表,将前缀和存在里面,我们只需要在里面找到有几个和为dp[i]-k的即可。找一段连续的子区间,该子区间的和为k。

2025-01-23 15:35:30 415

原创 初识——【Linux】make和makefile

make和makefile是linux系统里用于自动化编译和构建程序的工具。们通过定义一系列的规则来指定如何编译和链接程序,从而简化了编译过程,尤其是有多个源文件的时候。

2025-01-23 14:47:41 953

原创 前缀和——除自身以外数组的乘积

但是我们需要对数组f,g 数组进行特殊处理,当i分别为0和n-1时,f,g数组会分别越界,所以我们可以对这两个位置进行特殊处理:f[0]表示(0,-1)这个区间的积,该区间不存在,所以我们可以将其置为1。我们要计算某个位置左右区间所有元素的积,那么我们就可以分别记录下左右区间的积,最后将两个值相乘即可。同样,我们借助来个数组来存储f,g。f[i]表示(0,i-1)这段区间的积,g[i]表示(i+1,n-1)这段区间的和。时间复杂度:处理前后缀积数组需要遍历两边数组,最后遍历下标也需要遍历一边数组,综上,

2025-01-21 20:52:36 440

原创 初探——【Linux】程序的翻译与动静态链接

我们所写的C/C++程序计算机是看不懂的,它只认识0101这样的机器码。所以我们就需要借助编译器对这些源代码进行翻译,使之成为计算机能够执行的二进制指令。这个过程通常分为几个关键步骤:预处理、编译、汇编和链接。

2025-01-21 20:12:37 777

原创 前缀和——寻找数组的中心下标

时间复杂度为O(n)

2025-01-20 17:51:07 628

原创 前缀和——模板 二维前缀和

A区域就是dp[i-1][j-1],D区域其实就是arr[i][j],现在剩下的就是C和B了。这里的dp[i][j]表示的是从(1,1)~(i,j)这个区间的和。输入一个m行n列的矩阵,然后进行q次操作,每次操作输入4个数,作为两个点的坐标,计算这两个点为对角线的矩阵的和。因为我们这里的下标是从1开始的,所以我们在申请空间的时候,行和列都得多申请一行/列。时间复杂度:处理dp数组时,我们需要遍历一遍数组m*n,接着我们进行q次操作,但是每次操作的时间复杂度都是O(1),所以综上,暴力解法那我们就遍历贝。

2025-01-19 14:18:07 806

原创 【Linux】权限

linux操作系统下有两种用户:超级用户root和普通用户。既然有两种不同的用户那就涉及不同用户的权限问题。而在,所以用户的权限都体现在对文件的操作上。下面我们就来了解一下文件的权限。

2025-01-19 02:30:00 653

原创 前缀和——【模板】前缀和

题目还是很好理解的,先分别输入两个数,一个是数组的长度,一个是操作的次数。我们接着下面的图来分析,要求2~4这个区间的和,其实就是红色线对应区间的值减去绿色线对应的区间的值。题目已经给了我们区间的起始位置和结束位置,我们只需要遍历一遍数组,从子区间的起始位置开始计算,直到子区间的结束位置即可。我们该题下标从1开始,我们开数组的时候开n+1个空间,第一个空间的值赋为0即可,不会影响dp数组和最后的结果。当我们有了前缀和数组,让我们求l~r这个区间的和,其实就是前缀和数组dp[r] - dp[l-1]的结果。

2025-01-18 12:10:59 809

原创 【C++】异常和智能指针

C++11提供了一套新的错误处理机制——异常。在C语言阶段,当程序出现错误时是通过返回错误码来表示程序出错的类型,我们还需要去查询错误码来找到错误,最后才能解决错误。而C++提供的异常机制可以通过try、catch、throw关键字来发现错误,同时抛出一个错误对象,里面包含错误的具体信息,并在catch里面进行解决问题。

2025-01-18 10:38:21 1083

原创 二分查找算法——点名

此时下标i就是结果。一共有0~n-1这n个数,数组有n-2个数,数组的下标与学号是统一的,说明0~n-2个数都在数组中,那么缺少的数就是n-1。但是我们需要注意边界情况:如果数组的下标和元素都是一一对应的,那么此时left和right会在数组的结束位置,但此时的下标并不是结果,下标+1才是结果。我们观察上图可以发现,在根据二段性分成的两个区间中,右区间的左端点的下标就是缺失的数,所以我们要寻找右区间的左端点。我们先将0~n-1这n个数的和求出来,然后减去数组的和,剩下的就是丢失的数。

2025-01-15 21:11:22 749

原创 二分查找算法——寻找旋转排序数组中的最小值

因为数组原本是升序的,每一次旋转都是将最大值转到了前面,所以我们的数组应该是先上升,然后突然降到最小值,然后持续上升。数组本来是升序的,我们要在旋转后的数组中,返回最小值。题目上面要求我们使用logn的算法解决,所以这道题肯定是二分没跑了。寻找数组的最小值,我们管它旋转没旋转,旋转几次,我们直接遍历一个数组,同时更新最小值即可。时间复杂度:我们使用了二分算法,每一次都丢弃了一半内容,所以。时间复杂度:我们需要完整的遍历一边数组才能拿到最小值,所以。空间复杂度:我们在该过程中,只只用了有限个变量,所以。

2025-01-14 20:48:26 268

原创 二分查找算法——寻找峰值

我们看上图,之所以说一定有结果是因为即使高的那边一直递减,那么他也是大于左右两边的,满足峰值要求。另一边有可能有结果是因为,那一边有可能一直递减,也有可能出现递增,所以判断这一边意义不大,直接舍弃即可。圆圈的位置都是峰值。图一和图二,它们之所以是峰值,是因为峰值的要求是大于左右两边的元素,而他们的另一边是无限趋于负无穷大的,所以边缘位置也是大于左右两边的,所以属于峰值。既然峰值元素要求大于左右两边的元素,那么暴力解法就是遍历整个数组,找到一个元素,该元素满足既大于左边又大于右边,返回该位置即可。

2025-01-13 23:12:59 374

原创 二分查找算法——山脉数组的峰顶索引

因为题目明确说明,arr一定是一个山脉数组。在上升阶段包含峰值,都满足当前位置大于前一个位置,在下降阶段,都满足当前位置小于前一个。当mid落到有区间,该位置的值不可能是结果,所以我们直接让right跳过mid,所以right = mid-1.当mid落到左区间,该位置的值有可能就是峰值,所以我们不能让left跳过mid,所以left = mid;因为我们这里并没有单独处理等于的情况,所以这里不能用简单二分,而得用查找区间右端点的写法。因为题目明确告诉我们这是一个山脉数组,所以它的二段性还是非常明显的。

2025-01-13 22:22:32 269

原创 二分查找算法——搜索插入位置

我们可以对数组进行分析,target会将数组分为两个部分,[0~target]<=target,[target+1,size-1]>target。查找完成后,会剩余一个元素,该元素要么是target,要么不是。如果不存在,我们就在遍历一边数组,找到第一个大于target的元素,返回该元素的下标即可。查找一个数在不在我们可以用简单二分来解决,但是这道题涉及到如果不存在,需要返回待插入的位置,所以简单二分是解决不了的。因为数组是排序的,所以应该插入的位置就是target插入之后,依旧满足数组是有序的。

2025-01-13 21:54:45 300

原创 二分查找算法——x的平方根

我们可以分析x和结果之间的关系,结果一定在1~x/2之间。然后我们仔细观察,这个区间还存在二段性:结果会将区间分为两部分,结果的左边包含结果,它的平方一定是小于等于x的;结果的右边区间平凡一定是大于x的。我们只需要从1开始遍历,然后判断该值的平方等不等于目标值x。我们仔细观察这个区间的划分,是不是有点像之前的查找区间的右端点。我们可以使用查找区间的右端点来解决。题目还是很简单的,就是对一个数进行开平方,返回的结果需要向下取整。因为我们查找的区间是[1,x/2],所以对于当x<=1,需要特殊判断。

2025-01-13 16:41:58 386

原创 二分查找算法——在排序数组中查找元素的第一位置和最后一个位置

时间复杂度:最坏的情况就是数组中没有目标值,此时我就会遍历一遍数组,所以时。

2025-01-12 15:46:03 703

原创 C++11——3:lambda表达式、类的新功能、STL的变化、包装器

C++11还引入了lambda表达式,并且因为一些新特性的引入,类以及STL都发生了一些变化。句装器的引入也解决了一些复杂问题。下面就是一个简单的lambda表达式。1.lambda表达式语法lambda表达式的格式为:[capture-list] (parametres) -> return type {function body}下面给出一些lambda表达式的例子:我们看这些lambda的使用方法就跟函数是一样的,但是要注意,它们是匿名函数对象,不是函数。lambda表达式的函数体

2025-01-11 15:11:13 650

原创 二分查找算法——二分查找

3次,剩下n/8……进行x次之后,剩余1个数,n/2^x = 1,2^x = n,解得,x = log n。那么之所以有二分查找,而没有三分、四分查找算法的原因是因为,二分这样的舍弃行为的时间复杂度是很优秀的,比其他的分割方式都要优秀。如果其小于目标值,说明可以舍弃这个数,而数组是有序(升序)的,当前数的左边区间的所有数一定小于该数,也就一定目标值,所以我们可以一次舍弃到一个区间。因为区间的值都是未知的,即使最后区间只有一个数->right == left,那个数也是未知的,所以我们也要进行判断,

2025-01-07 23:04:22 388

原创 滑动窗口——最小覆盖子串

需要注意的是:如果字符串t包含重复字符,比如"aaac",那么在s中寻找子串的时候必须包含所有的字符,不是说同样的字符出现一次就行了。统计子串中的字符,当哈希表中出现了字符串t的所有字符之后,就记录此时子串的起始位置和长度。在进行滑动窗口之前,我们要记录哈希表mp_t的size,因为在滑动窗口过程中,mp_t会插入元素,导致size变化,所以我们要提前记录一下。空间复杂度:在该过程中,需要用到哈希表来存储数据,但是存储的都是字母,所以空间可以算是常数级的,空间复杂度为O(1).继续判断,重复该过程。

2025-01-07 20:56:32 562

原创 C++11——2:可变模板参数

C++11引入了可变模板参数(variadic template parameters)的概念,它允许我们在模板定义中使用可变数量的参数。这样,我们就可以处理任意数量的参数,而不仅限于固定数量的参数。

2025-01-06 21:51:34 825

课程设计大作业贪吃蛇C/C++语言

贪吃蛇源码

2024-07-05

空空如也

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

TA关注的人

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