自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 【C++】智能指针的工作原理与底层实现

我们发现,对于同种类型的智能指针,引用计数是公有资源,所以在设计智能指针时,我们一定要保证引用计数在++、--的过程中是线程安全的,否则在面临这种多线程场景的时候,引用计数就可能会出现问题!当p2生命周期结束调用析构函数时,引用计数只会从2减到1,并不会释放p2中的指针,那么该指针中的资源也不会释放。原因:在赋值或拷贝时,wead_ptr只是指向资源,让我们能够访问到,但是不会增加shared_ptr的引用计数,且不参与资源释放的管理,但是weak_ptr可以访问到shared_ptr的引用计数。

2024-12-03 01:19:12 855

原创 【C++】字符串相乘

介绍一种比较简单的方法,就是先将字符串逆序,然后取出其中每一位的数相乘、相加。最后再考虑进位问题。

2024-11-14 16:47:00 355

原创 【C++】单例模式

单例模式:顾名思义,这个对象是全局的,且只有唯一的一个实例(不能创建出两份)。用途:多个线程同时访问一个全局资源时可能会用到。例如,在C++的内存管理中,内存池只有一份,但是会有多个线程访问内存池,那么内存池的设计就可能需要单例模式。所以单例模式还是比较重要的。

2024-10-23 09:52:19 1654

原创 【C++】内存管理

首先ptr1有4个字节,但ptr2有44个字节。多出来的四个字节存开的自定义类型的个数,让delete []知道需要调用几次析构函数,前提是用户显式写了析构函数。如果用户没有写析构函数,编译器会进行优化,将那4个字节省掉,ptr2只有40个字节了!new delete/new[] delete []/malloc free要匹配使用,如果不匹配就会出问题。delete一个自定义类型时,先调用析构函数,在调用operator delete。注意析构函数是可以直接调用的,但构造函数不可以,需要调用定位new。

2024-10-19 14:50:48 376 1

原创 【C++】右值引用和移动语义(带你理解C++为何如此高效)

常见右值:常数(10),匿名对象,函数返回值(函数返回出去的是个临时对象),x+y这个表达式的结果也是右值。但是像这种返回的就是个左值,因为它返回的是个左值引用。补充:匿名对象是右值,有名的是左值。

2024-10-14 09:12:13 661

原创 【C++】线程库常用接口

Linux系统中,系统调用pthread_create要求传进来函数参数要是void*,返回值是void*,下面一个参数是作为该函数的参数,类型是void*。所以C++的线程库要对100,x,mtx封装成结构体,后面还要把这个结构体的每一个成员解析出来交给线程函数去调用,这其中有很多步骤只是值拷贝,而不是引用传参。其中条件变量是配合flag使用的,一旦调用c.wait()(非原子,需要调用互斥锁),该线程必定会阻塞(且在阻塞前会解锁),等待其他线程唤醒。可用于一些小的修改,小的操作,保证线程安全。

2024-10-11 16:52:06 519

原创 【C++】哈希表:字母异位词分组(体会泛型编程的强大)

利用map的特性,第一个值存排好序的string,第二个值存vector<string>。这样就可以很好的将异位词分组。

2024-09-20 11:21:09 293

原创 【面经】static关键字总结

static中文意思是静态的,是C/C++中常见的一个关键字。它一般用于修饰变量(局部变量/全局变量)和函数。对于变量来说,static关键字用来控制变量的存储方式,作用范围和生命周期。下面我们分别在C语言和C++中讨论static的用法。

2024-09-19 23:32:00 1003

原创 【Linux】软硬链接&动静态库

1.硬链接就是文件名和inode的映射关系。2.建立硬链接就是在指定目录下,添加一个新的文件名和inode number的映射关系!3.建立硬链接后,把目标文件删除。这个操作相当于重命名。其实就是删除了文件名和inode number的映射关系而已。4.属性中有一列数字,就是硬链接数。也是文件的磁盘级引用计数:有多少文件名字符串通过inode number指向目标文件的inode。所以任何一个目录,刚开始新建的时候,引用计数一定是2。因为有隐藏文件.(当前路径)。

2024-09-04 14:23:11 1127

原创 【数据结构】八大排序代码实现(C++)

因为建小堆的话,数组第一个数就是最小的,而我要升序排列,那么第一个数直接就排好了,不需要调整。我们必须从第二个数开始调整堆,但此时数据之间的关系全都乱套了,无法向上或向下调整恢复堆的特性,只能重新建堆,而建堆的代价是很大的,时间复杂度是O(n*logn)。让根结点与最后一个子结点交换,那么最大的数就排好了,再让交换后的堆向下调整,此时根结点就是次大的数,和倒数第二个子节点交换,那么次小的数就排好了,依此类推。先遍历数组,找到最小的数,和下标为0的数交换,再次遍历数组,找到次小的数,和下标为1的数交换。

2024-08-11 18:08:11 1603

原创 【C++】链表操作技巧综合:重排链表(带你理顺链表的做题思路)

不只是针对这一道题目,而是针对所有的链表题目:1.尽量多运用哨兵位的头结点。2.尽量避免在原链表上做修改,这样代码会显得很乱。尽可能在哨兵位的头结点后进行尾插或头插,这样更有条理。

2024-08-06 20:42:18 265

原创 【C++】位运算:消失的两个数字

然后遍历数组nums和1~N中的所有整数,分别求出每一个整数第x位的值。等于1的分为一类,等于0的分为一类。那么a和b一定分别在这两类中,相同的值也一定在同一类中,这样异或就可以抵消。首先需要求出ret的二进制表示中为1的x位(只要为1,任何一位都可以),因为这一位是a和b不同的一位,可以用来区分a,b。1.可以将数组和1~N中的所有整数全部异或在一起,就可以得到缺失的两个数(a,b)相异或的结果(ret)。最后将这两类整数分别异或在一起,得到的值就是缺失的两个数(a,b)。2.下面的任务就是将它们分开。

2024-07-21 22:05:34 364

原创 【C++】位运算:两整数之和

异或的作用是无进位相加,所以需要通过异或运算(^)来替代加法运算,但是我们无法确定进位的信息。所以需要与运算(&)来得到进位的信息。本题不能只用+ -,那大概率用到位运算符。

2024-07-21 18:02:37 272

原创 【C++】位运算与相关算法问题

那么先将第5位向右移到第1位,就会得到.......0101,然后&00000...0001,结果就是1。n: .....0101001,要将第三位改成1就需要| ...100,而...100这个数是1向左移位的结果。结果是0,答案就是0,结果是1,答案就是1。在位运算中,比较重要的就是1.按位与(&),2.按位或(|),3.按位异或(^)。和标题2的方法有些类似,只不过是将1向左移x位,然后| n就可以了。我们需要知道计算机是怎么处理-n的:先将n按位取反,然后加1。^:(1)相同为0,不同为1。

2024-07-20 17:35:56 655

原创 【C++】和可被K整除的子数组

所以就得到公式:在求余数时,不论a是否是正数,都有(a%b+b)%b,这个表达式的结果一定是正数。在C++或Java中:a(负数)%b(正数)=c(负数)。想要修正成正数就需要让c+b。若 (a-b)%k=p,则a%k=b%k;

2024-07-18 23:54:43 275

原创 【C++】前缀和:和为K的子数组

如果一个区间和为sum,如果它的前缀和为sum-k,那么后缀和一定是K。需要借助哈希表(查找效率很高)。

2024-07-18 22:36:22 233

原创 【C++】二维前缀和

和一维前缀和的方法类似,我们需要预处理一个求和矩阵,然后再求和。上面两张图片总结出来了两个公式,这是解决此类问题的关键。使用前缀和算法:O(n*m)+O(q)。暴力解法:O(n*m*q),必定超时。

2024-05-29 17:42:56 513

原创 【C++】前缀和:一维前缀和

优化的思路也很简单,就是得到一个求和数组arr,使arr[i]=a1+a2+...+ai。然后每次求l到r之间的数时,直接arr[r]-arr[l-1]就可以得出!如果暴力求解的话,时间复杂度为O(n*q)。这样,时间复杂度就降为O(n)+O(q)。

2024-05-29 14:12:53 234

原创 【C++】二分查找算法:x的平方根

题目中没有数组,我们可以造一个从0到x的数组,然后利用二分查找找到对应的值即可。二分查找的特点:数组具有二段性(不一定有序)。看到题目可能不容易想到二分查找。这题考察我们对算法的熟练程度。时间复杂度:O(logn)。

2024-05-26 21:24:07 357

原创 【C++】二分查找:在排序数组中查找元素的第一个和最后一个位置

难点:要求时间复杂度度为O(logn)。需要找到左边界和右边界就可以解决问题。题目中的数组具有“二段性”,所以可以通过二分查找的思想进行解题。代码:细节问题:首先考虑边界情况,数组为空先判断一下。然后就是循环条件不能写等于,否则mid始终等于right(找左边界时)/left(找右边界时),会死循环。还有找左边界时,mid要向下取整,找有边界时,mid要像上取整。否则只剩两个值时,mid始终等于right(找左边界时)/left(找右边界时),会死循环。

2024-05-26 20:13:48 535

原创 【C++】二分查找算法

算法的特点:我们所查找的“数组”具有二段性。这里的二段性不一定有序。而是我们可以找到某种规律,可以让我们把数组分为两部分,然后舍掉一部分,对另一部分进行求解。暴力解法:可以将数组遍历一遍,就可以找到。时间复杂度为O(n)。不算太差,可以接受。在后面的题目中,我会举一个无序的但是可以用二分查找算法解决的题目。本题中数组的有序就是二段性的一种体现。时间复杂度:O(longn)。

2024-05-26 17:02:31 320

原创 【高阶数据结构】红黑树

所以p是红色,既然p是红色,那么g一定是黑色,否则,之前的红黑树是有问题的。如果x=1,则a,b,c,d,e代表每条路径有1个黑色结点,那么cur一定不可能是新增结点,但是cur和p是两个连续的红节点,已经违反了规则三,所以cur原本的颜色其实是黑色,它之所以变成红色是由其子树的变化影响的。这是x=0的情况,想要满足红黑树的规则三和规则四,就需要将p,u变成黑色,将g变成红色。上图是情况一和情况二合并的情况,同样的道理,也是p变黑,g变红,然后进行一次右单旋。RBTreeTest1()为测试代码。

2024-05-25 14:15:14 467

原创 【高阶数据结构】AVL树的旋转与底层(C++实现)

双旋的情况就是在60这个子树上插入一个新的结点,插入过后需要经过两次旋转。旋转后的结果就是30和90都变成了60的子树。原本为60的子树,变成了30和90的子树。右单旋的所有情况可以抽象为上图:图中,a,b,c均为高度为h(h取0,1,2......)的AVL子树。对比一下右单旋的图片,左右双旋的抽象图是把30结点的右子树细致的分为60的结点和60的左右子树。从程序运行结果可知:在Release版本下,插入100万个随机数,其中实际插入约63万个数值。1.按照搜索树的规则插入,然后更新父亲的平衡因子。

2024-05-19 20:37:34 404

原创 【Linux】进程的地址空间

上图父进程的代码和子进程一致,只不过没有改变g_val的值。子进程中改变了g_val的值,而父子进程互不影响,结果也符合预期,子进程中的g_val是300,父进程中的g_val还是100。但是,父子进程中g_val的地址却是一样的!直接震碎三观!这里我们要知道,这肯定不是物理地址,是虚拟地址。

2024-05-19 14:04:42 693

原创 【C++】继承【下】

1.数据和方法放到一起,把想给你访问的定义为公有,不想给你访问的定义为私有或保护。2.一个类型放到另一个类型里面,通过typedef成员函数调整,封装另一个全新的类型。

2024-05-19 14:03:22 581

原创 【Linux】命令行参数和环境变量

上图中的./myprocess -a -b -c -d这个东西叫命令行字符串,argv显然是变长数组,argc是一个整型,命令行字符串以空格分隔,argc代表其中字符串的个数,argv里面存了对应的字符指针,最终以NULL结尾。所谓能力越大,责任就越大,既然用户得电脑配置高,用户一定会给电脑安排与之配置相对等得任务,所以,进程永远是多数,cpu永远是少数,在并行的同时就会存在并发。如果在修改nice值时,输入很大的数,比如100,系统只会取nice值的上限就是19,然后和原来的优先级相加。

2024-05-18 18:35:41 929

原创 【C++】多态(上)超详细

封装,继承,多态不只是C++的三大特性,而是面向对象编程的三大特性。

2024-05-12 21:51:08 974

原创 【C++】继承(上)(超详细,保证你学会)

通过这种方法,Student和Teacher这两个类就继承了Person的成员变量和成员函数,可以直接调用它们。如图,如果成员变量和成员函数在基类中是公有的话就可以直接访问!但如果是私有和保护的话就无法访问。

2024-05-11 16:49:29 1163

原创 【C++】滑动窗口:将x减到0的最小操作数

题意是需要在数组的前后两段区间进行解题,但同时对两段区间进行操作是比较困难的,我们可以将中间这段区间只和与nums_sum-x(数组总和-x)进行比较,这样就可以很好的将两段区间合并成一段区间,进而使用滑动窗口算法解题。滑动窗口算法我在《优选基础算法》中滑动窗口的前两个题目中介绍的比较清楚,大家可以去看一看。时间复杂度:O(n)。空间复杂度:O(1)。这个题目难在要转化一下才能用滑动窗口。

2024-05-03 17:28:10 475

原创 【C++】滑动窗口:最大连续1的个数

找到所有符合题意的子数组,跳出最长的那个就可以了。需要嵌套的两层循环,时间复杂度是O(N^2),对于一个在Leetcode上中等难度的题目来说大概率会运行超时,所以我们需要对暴力穷举法进行优化。当size>K时->left++,这时right不用再回来,因为right回来后它还是会在原来的位置停下来(根据零的个数),所以我们需要不停的往右移动left,知道它越过一个0后停止。那么我们需要同向的双指针left和right来作为子数组的两个端点,用计数器size统计0的个数,用len来记录最大子数组的长度。

2024-05-03 15:34:10 585

原创 【C++】滑动窗口:长度最小的子数组

那么我们来介绍一下什么是滑动窗口:滑动窗口其实就是同向的双指针算法,利用题目的单调性来进行优化暴力穷举法。由于同向的两个指针遍历数组的动作很像窗口两端的滑动,所以称这种算法为滑动窗口。如何使用滑动窗口呢?进窗口->判断->出窗口->更新结果。(更新结果的位置不固定)。时间复杂度:大概遍历两次数组,所以时间复杂度为O(n)。

2024-05-02 18:48:31 581

原创 【C++】双指针算法:四数之和

固定一个数b,然后定义两个指针left和right,分别从两端遍历数组,如果这四个数大于目标值则right--。在做个题目前强烈建议大家先看看我的上一篇博客:有效三角形个数,看完之后再去leetcode上写一写三数之和,搞懂那两个题目之后再来看这道题目就比较容易了。首先我们需要把这个数组排一下序,然后固定一个数a,然后在剩下的区间利用三数之和的思路解决。这道题目十分困难,在leetcode上的通过率只有36%,大家要做好心理准备。四数之和实际上和三数之和的思路差不多,只不过比三数之和多了一个步骤。

2024-05-02 16:22:39 703

原创 【C++】双指针算法:和为s的两个数字

虽然在牛客上是个中等题,但我感觉是比较简单的。大家在看完这篇文章后可以看看我的上一篇文章:有效三角形的个数。本文章的题目的解法只是有效三角形的个数这道题目的一个环节。看懂这篇文章后可以更好的解决有效三角形个数那道题目!

2024-04-25 23:53:21 395 1

原创 【C++】双指针算法:有效三角形的个数

然后固定最大的数,定义一个左指针和右指针从数组的两边开始遍历。如果左右指针对应的数之和大于另一个较大的数,那么左指针右边的数与右指针的数之和一定大于那个较大的数。如果左右指针数字之和不大于另一个较大的数,则左指针往右移动一位。那么只需要判断a+b>c是成立的,那么这三个数就一定能构成三角形。我们都知道,判断三个数能否构成三角形需要判断三次:任意两个数之和大于第三个数。可想而知,这种解法的时间复杂度是很高的,而且每种情况还要判断三次。这需要先固定其中两个数,另一个数字取数组剩下的数。

2024-04-25 09:28:01 544

原创 【C++】双指针算法:盛最多水的容器

有两种方法:第一种:暴力穷举法,就是用两次循环将所有的可能性算出来,然后求出最大值。这种方法最容易想到,但时间复杂度是O(n^2),一定会超时的!第二种:仔细观察题目特点,任意两条线之间的体积=短的那条线*两条线之间的距离。例如数组{2,3,8,1,7,6}。2和6之间的距离=2*5。根据体积的计算特点,对于2来说,它和其他数字之间的体积一定小于2和6之间的体积,所以这些情况就可以直接舍掉,最大体积一定在{3,8,1,7,6}中产生。同样的道理,3和6之间的体积为3*4。

2024-04-21 19:50:21 758

原创 【C++】STL:vector常用接口的使用和模拟实现

这篇文章主要给大家讲讲vector常用接口的模拟实现,STL库中的实现一层套着一层,十分复杂,目前阶段还不适合看源代码。而模拟实现可以让我们从底层上了解这些接口的原理从而更好的使用这些接口。另外我还会讲一些在vector使用过程中特别容易出错的点!还有就是这篇文章很有难度,类和对象基础不太好的同学可能看不懂,建议回去复习一下构造,拷贝构造和const引用,然后再来看这篇文章会好很多。当然,这些知识我也写过博客,其中描述的很详细,大家也可以去看看!

2024-04-21 16:04:54 721

原创 【C++】双指针算法:快乐数

也就是说,从0到2^31之间的所有数字经过一次操作后所得的结果一定在落在【1,810】这个区间之内,所以在0到2^31之间任意一个数经过811次操作后,每一次操作的结果一定都落在【1,810】区间内,而这个区间一共有810个整数,811次操作会得到811个整数,就一定可以推出至少有两次操作的结果是相等的!慢指针进行一次操作,快指针进行两次操作,因为最后的结果是一个闭环,所以快慢指针一定会相遇,相遇时判断它们是否等于1。这个原理就是鸽巢原理,意思就是有n个巢,n+1个鸽子,那么一定只少有一个巢中有两只鸽子!

2024-04-19 23:32:34 658

原创 【C++】双指针算法:复写零

从这个例子中结果,我们发现cur指针最多遍历到元素4就不会往后遍历了,如果我们先确定cur读取的最后一个数据的位置,让cur从那个位置从后往前遍历,让dest从后往前修改就不会出现0把原来还没读取的数据覆盖的情况。修改后的结果就是arr={1,0,0,2,3,0};这个代码是我第一次写这道题目时写的代码,并不是最精简的,读起来有些费劲,我在后面给出了简化版的。但这种方法需要考虑一个边界情况:如果数组是arr={1,0,2,3,0,4};这次举题目中示例一的例子:arr={1,0,2,3,0,4,5,0};

2024-04-19 19:16:30 508 1

原创 【C++】双指针算法:移动零

1.cur:负责遍历数组,查找非0元素。2.dest:在cur扫描过的区间内,起到划分非0元素和0元素的作用。有了这两个指针,数组就被我们划分为三个区间:【0,dest】这个区间全是非0元素。(换句话说:dest指向非0元素的最后一个值)。【dest+1,cur-1】这个区间全是0元素。【cur,n-1】这个区间是未扫描区间。如果在cur扫描数组的过程中,这三个区间中的元素始终能保持对应的性质,就可以满足题意。

2024-04-18 18:33:13 362

原创 【C++】力扣OJ题:构建杨辉三角

今天给大家介绍一道我认为比较经典的编程练习题,之所以介绍它是因为这道题涉及到二维数组的构建,如果用C语言动态构建二维数组是比较麻烦的,而用C++中STL的vector<vector<int>>,就可以立马构建出来,这也是C++相对于C的优势所在!

2024-04-16 14:10:57 344

空空如也

空空如也

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

TA关注的人

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