- 博客(50)
- 收藏
- 关注
原创 力扣:基本计算器
摘要:本文介绍了实现基本计算器的算法思路,通过中缀表达式转后缀表达式(逆波兰表达式)的方法进行运算。关键步骤包括:处理空格和负数、优先级判断、递归处理括号子表达式、后缀表达式求值等。文中分享了实现过程中的常见问题:负数与减号的区分、特殊括号情况处理、调试输出影响性能等,并提供了C++代码实现方案。该算法能够正确处理复杂表达式运算,如"(1+(4+5+2)-3)+(6+8)"等情形。
2025-06-12 19:52:19
649
原创 C++11下(智能指针)
上图就是用RAII思想创建的简单智能指针,当我们new了一个对象进来后,由我们的指针进行接受,并初始化成员变量_ptr指向堆空间new的那块区域。如果是p1申请空间失败还好说,并不会出事,怕的就是p1申请空间成功,而p2申请空间失败,此时抛出异常程序结束。std::weak_ptr 是 C++ 智能指针家族中的一员,但它不支持RAII,属于弱指针,专门设计用来解决 std::shared_ptr 的。unique_ptr是以类模板的方式实现的删除器,如果是仿函数,只需要传仿函数类型即可,但是要显示实例化。
2025-06-07 01:45:13
741
原创 C++11(中)
C++11 引入的可变参数模板(Variadic Templates)是模板编程的重大革新,允许模板接受任意数量、任意类型的参数,极大提升了代码的泛化能力,并且也支持左值引用传参与右值引用传参。主要使用场景为,当我们自定义类型时,需要针对不同情况进行不同的排序,如果专门写个仿函数比较,感觉有点重,但如果是使用Lambda时,就显得很方便别人看也很易懂。在循环判断时,我们用count函数,count函数会用str字符串去查早map里是否有匹配的string字符,如果有则返回其存在的数量,如果没有则返回0。
2025-06-04 01:01:05
666
原创 C++11(上)
第一段代码还好,仅仅只是返回一个string,而第二段代码需要返回的是vector的vector,传值返回就需要创建相同的临时变量,通过临时变量在进行拷贝构造,代价是非常大的。可以看到i,调用的是左值引用,ci是const左值引用,3因为是一个常量所以也是const 左值引用,当move了i后,i属性变为右值,但const 左值引用以及可以引用右值,所以程序能正常运行。不要忘记之前说的,当一个右值引用的变量绑定了一个右值后,该变量的属性依旧为左值,所以编译器这里把x识别为左值,调用的就是左值引用的f函数。
2025-06-01 00:13:47
933
原创 C++:二叉搜索树
如上图需要删除4,我们去寻找4的右子树的最左节点也就是5。一颗树的右子树的最左节点与一颗树的左子树的最右节点,是仅大于该子树的根或仅小于该子树根的节点。比如上图删除6节点,因为6节点的左子树为空,所以我们只需要将6节点的父亲及4节点的right链路6节点的右边,不需要管6是否有又节点。如上图,当我们需要删除4节点的时,因为4拥有左右子树,不能简单直接删除,会破坏二叉搜索树的特性,因此我们需要使用替代法。
2025-05-14 20:21:45
711
原创 Linux:进程控制
替换后,新程序会占用原进程的资源,包括进程 ID、打开的文件描述符等,但会拥有全新的代码段、数据段和堆栈段,原进程的代码和数据将被完全覆盖。进程等待是指进程在执行过程中,由于某些条件不满足而暂时停止执行,进入一种等待状态,直到所等待的事件发生或条件满足后,才会再次被唤醒并继续执行。用于进程管理的系统调用函数。在本篇文章中,我将带领大家来深入浅出的认识进程控制的概念,包括进程退出,进程等待,以及进程替换等知识。程序替换简单来说,就是进程在执行代码的过程中,替换原有的代码和数据,但不会替换进程的其他数据。
2025-04-21 21:33:37
881
原创 Linux:进程地址空间
从上图输出可以看到,我们的子进程继承了父进程的全局变量val,当子进程中的val产生了修改时,父进程的val值并没有变化,但父子进程在打印val的地址时,会发现val的地址是一样的。但这不就冲突了吗,我们知道地址是唯一的,一段相同的地址可以同时打印不同的值,这并不符合我们之前理解的概念。”这个机制的工作原理是:如果子进程想修改某段数据,操作系统会先在内存中找一块新的空地,把需要修改的数据复制到这块新地方,然后更新子进程的“门禁卡”(页表),让它指向这个新的地址。但是对于大饼,大饼同样也需要管理。
2025-04-09 19:26:41
883
原创 Linux:环境变量
如果我们输入echo $PATH命令,会看到多个由冒号分隔的路径(例如/usr/bin:/bin:/usr/local/bin等)。上图我们通过 file /usr/bin/ls 来输出ls命令的属性,可以看到ls也是用c语言写的程序,所以我们在使用ls -a或ls -l 时候程序都会对传入的的命令进行命令行分析,来决定输出的文件形式。,一张命令行参数表,一张为环境变量表。上图可以看出,argc代表的是传入了多少个命令行参数,而argv则是传入的命令行参数,而我们在命令行上输入的内容都会存入argv中。
2025-04-02 15:38:43
1200
原创 Linux:进程状态总结
在PCB中有一个struct结构体,我们先暂称为list_head,这个结构体里就存放着prev和next,然后next就指向下个PCB的next,prev就指向上个PCB的prev,而不是指向首字节,对于为什么要这么操作,是因为在操作系统在,task_struct里存放着许多list_head。所以通过上图的理解,对进程状态的管理,其实就可以转化为对链表的管理,进程的状态变化,本质是在不同的队列中进行流动,本质都是对数据结构的增删查改。所以在操作系统中,一个进程的结构体,可以同时属于多种类型的数据结构。
2025-02-15 15:37:09
803
原创 Linux:进程概念详解
分析上图代码,一开始我们输出当前进程的PID和PPID,接着通过fork进行创建子进程后再次打印PID和PPID,我们会发现此时除了第一条打印的语句我们理解,还多了一条打印的语句。并且观察PID,会发现PID为 19215 的PPID正是一开始打印的PID 19214,那么就能够证明了fork会创建子进程,并且子进程会继承父进程fork()之后的代码,所以会打印两句输出语句。通过上图运行可以看到,我们一直运行mycode的文件时,它的PID是依次递增的,但一直不变的是PPID。但进程并非仅仅是数据和代码。
2025-02-15 01:05:58
716
原创 C++进阶:Hash表总结及模拟实现unordered_map与unordered_set
简单来说,哈希表就是将一些没有规律的值存储在一段有序的区间内,通过哈希函数将数据映射到这个区间中的某个位置,从而实现快速查找。在C++中unordered_map与unordered_set底层都使用的是哈希表,所以对unordered_map与unordered_set封装本质上也是是对哈希表的更上层的封装,以及对原哈希表结构进行优化处理。如果关键字是 [a, z] 的小写字母,我们可以开一个大小为 26 的数组,每个字母的 ASCII 码减去 a 的 ASCII 码就是数组的下标。
2025-02-04 16:06:25
465
原创 C++进阶: 红黑树及map与set封装
红黑树整理与AVL树类似,但在对树的平衡做控制时,AVL树会比红黑树更严格。AVL树是通过引入平衡因子的概念进行对树高度控制。红黑树则是对每个节点标记颜色,对颜色进行控制。
2025-02-02 18:20:21
697
原创 Linux:初识进程
分析上图代码,一开始我们输出当前进程的PID和PPID,接着通过fork进行创建子进程后再次打印PID和PPID,我们会发现此时除了第一条打印的语句我们理解,还多了一条打印的语句。并且观察PID,会发现PID为 19215 的PPID正是一开始打印的PID 19214,那么就能够证明了fork会创建子进程,并且子进程会继承父进程fork()之后的代码,所以会打印两句输出语句。gval是一个全局变量,父子进程都可以看到,当我们fork之后,子进程会开始对gval值进行修改,而父进程只对gval值进行查看。
2025-01-13 09:51:53
720
原创 C++进阶:AVL树
一:AVL树的介绍一:AVL树的介绍AVL树(Adelson-Velsky and Landis树)是一种自平衡的二叉搜索树(BST),它通过在每个节点维护一个平衡因子,确保树的高度差不超过1,从而使得树的操作(如查找、插入和删除)的时间复杂度保持在 O(logn) 的水平。因为我们在普通的二叉树插入的时候,也许会出现下图这种极端的情况:那么如果此时搜索5或4的时候时间复杂度就为O(N)。那么为了解决这种情况苏联的两位数学家就发明了AVL树。在AVL树树中有个关键的概念,那就是。
2025-01-05 16:50:13
1039
原创 力扣二叉树题解含思路(C++实现)
这里小编想多一嘴,为什么cur会回到6节点,因为我们采用的方式是递归,递归函数会进行压栈,当我们压入4节点的函数栈帧时候,6节点栈帧会保存在4节点下面,而当4节点函数结束时候,此时函数栈帧进行弹出销毁,6节点就是栈顶,所以此时cur的值就是6.而且因为递归的关系,就算指向改变了也不会影响中序遍历的顺序,因为已经将顺序全部压入栈中了。其实这题如果忽略题目要求就很简单,因为是标准的搜索二叉树,就通过中序遍历存入list题目就解决了,但小编应题目要求,空间复杂度为O(1)及在原树上操作。
2024-11-10 19:20:32
794
1
原创 初见Linux:基础开发工具
前言:这篇文章我们将讲述Linux的基本开发工具,以及讨论Linux的生态圈,最后再了解vim开发工具。Yum:YUM(Yellowdog Updater Modified)是一个在Linux系统中用于管理软件包的工具,特别是在基于RPM(Red Hat Package Manager)格式的发行版上,如Red Hat Enterprise Linux、CentOS和Fedora等。YUM允许用户轻松安装、更新和删除软件包,并自动处理依赖关系。在Linux下安装软件的方法。
2024-11-09 15:01:12
767
原创 初见Linux:权限篇
从上图我们取消了dir目录中拥有者的w权限,接着进入dir,ls后发现dir目录下拥有一个test.txt文件,此时将test.txt文件进行删除发现没有权限。我们可以看到此时用户为dog,test.txt对于dog用户只用r的权限,但从上图dog用户可以直接删除test.txt文件,这是为什么,是不是不符合常理。因此可以排除r权限,那会不会是w权限呢?在Linux中的访问权限中,有三种不同角色的访问权限,分别问拥有者的访问权限,所属组的访问权限,以及other(其他人)的访问权限。很好的做到了用户隔离。
2024-10-28 01:01:56
640
原创 C++:多态
从上图调试信息可以看见,主函数的基类b与派生类的c 和 fun1()里的基类b1与派生类的c1它们的虚函数表指针都是同一个地址,那么就可以断定,虚函数表不是单独存在的,而是对象共用的。接着我们要取虚函数表地址,经过之前的例子我们可以知道存虚函数表是存在于对象的首地址,所以 *((int*)&p)的意思是先&p取到p的地址,然后(int*)&p将p的地址强制转换成int*类型,最后在解引用获取到地址的数值。因为在系统内存中是不会考虑你是什么类型的地址,存的都是二进制的0101,所以只看你的内存地址对不对。
2024-09-27 14:40:49
641
原创 C++:继承
但你总不可能是老师的时候,你的年龄,性别是一套信息,而当你是学生的时候你的年龄性别又是另一套信息,这不符合常理。继承嘛,继承遗产是继承,继承家业也是继承。所以如下图因为老师和学生同时都拥有人的属性,所以通过继承,让老师和学生都继承Person类,就相当于他们都拥有了Person的成员变量,而他们自己的成员变量又是独有的。那么从上图可以看到,创建了一个int类型的b引用去引用a,这里并不是直接引用a而是引用中间的临时变量,而临时变量是具有常性的,所有普通的引用不行,必须有经过const修饰的引用才行。
2024-09-18 11:31:42
761
原创 C++:关于反向迭代器的学习分享
反向迭代器的begin位置对应容器的end位置,反向迭代器的end位置对应容器的begin位置,为了方便理解,下图是一个list的begin位置以及end位置,那么相对于的就是list的反向迭代器的rbegin位置以及rend位置。那么反向迭代器的operator++()与 operator--()函数会调用正向迭代器的operator--()与operator++(),并且内部都是对正向迭代器的函数复用操作。那么反向迭代器的初始化其实就是通过传入的正向迭代器的参数对反向迭代器里的it进行初始化。
2024-09-03 19:16:28
729
1
原创 C++:模拟实现list
上篇文章简单介绍了list的接口使用,那么这篇文章将通过模拟实现list以及常用接口来更好的去理解list类,观看本章前将默认读者对链表的数据结构有初步的了解。list在库里是一个带哨兵位的双向循环的链表结构,并且list是一个类模板并不是一个指定的类型,所以在模拟实现时需要写成模板。
2024-08-31 11:35:52
1357
原创 C++:list篇
我们可以看到,当erase后如果在对it迭代器进行操作,vs则会进行强制检查(根据编译环境不同,处理环境也不相同),则不允许再继续使用,如果想继续使用的话,C++同样也给出了方案,可以看到erase会返回一个迭代器,而返回的迭代器就是下一个链表的位置。那么从上面的begin与end可以看出,使用迭代器遍历list,仅仅只需要解引用迭代器以及++迭代器就能取得我们想要的值与让迭代器走向下一个节点,那么有没有想过一个问题,list的迭代器与vector这种类似数组的迭代器底层是否是一样的呢?
2024-08-27 21:01:50
1684
原创 C++:vector篇
从上图可以看出,一开始创建了vector<int>类型的v1,并且通过push_back函数(这个函数后面会说明),对v1进行插值,接着又创建了v2并以v1为拷贝对象使用拷贝构造,使用范围for打印结果可以看出,v2把v1的数据进行了拷贝,并同时也进行了扩容的操作。从上图看到,在vector中的成员变量不像之前的sting,他采用了三个类模板的指针变量,_start(开始) , _finish(完成), _end_of_storage(结尾的存储位置),分别对应了str的指针,top以及capacity。
2024-08-24 10:46:01
987
原创 C++:模拟实现string
为了更好的理解string底层的原理,我们将模拟实现string类中常用的函数接口。为了与std里的string进行区分,所以用命名空间来封装一个自己的strin类。
2024-08-19 16:51:43
1060
原创 C++:string类篇
从上图可以看到,我们创建了一个string类的iterator(迭代器)变量it,并用s1.begin()函数的返回的迭代器值赋值给it,接着就类似指针的操作,将it解引用并循环输出值。2.string& append (const string& str, size_t subpos, size_t sublen):截取string对象中的一部分内容到自身内容后.1.string& append (const string& str):使用已有的string对象数据拓展自身对象数据。
2024-08-19 11:45:08
1056
原创 C++:初阶模板
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟< >,然后将实例化的类型放在< >中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。从上图可以看到,模板仅仅至少充当一个中介的角色,当给模板传入实参,编译器会根据实参的类型去推演自动生成对应类型的函数,可以从下图的汇编码能更好的证明这一点。可以看到如果按照之前的方式仅仅通过访问限定符去定义类是完全不行的,在 C++ 中,模板类的成员函数定义必须指定模板参数,因为这些成员函数的定义是在模板类的上下文中进行的。
2024-08-14 22:25:23
527
原创 C++:内存管理
通过任务管理器可以看到此时vs的运行窗口直接占用了2G左右的内存就不动了,说明此时堆上已经没有空间申请,当程序继续运行也没有发生而是捕捉到了编译器抛出的异常,输出bad allocation(糟糕的分配),提示程序员问题的出处。int* p1 = (int*)malloc(sizeof(int)):因为C++是C的延申,所以C++兼容C语言,在C++里也可以使用C语言的代码,malloc从堆中分配了一个int类型的空间,这个大家都熟悉.除非给每个对象都传入参数。p2指向的空间是通过new分配来的。
2024-08-13 09:27:10
954
原创 C++:类与对象(中)
需要释放的资源成员都是自定义类型,不需要写析构,前提是自定义类型里写了析构函数,编译器会自动调用自定义类型成员的析构函数,这点与上面的构造函数类似。这里就需要额外创建一个对象,先保存d1的值,再让d1+1,并且因为这个额外的对象是一个局部对象,如果传引用返回就会造成野指针现象,必须穿值返回。,那么此时传d2进成员函数Print就不会发生报错,权限也只是平移,那么在传d1的时候也同样不会报错,权限可以被缩小这种机制有助于增强代码的安全性和可读性,确保对象在被标记为const时保持不变。
2024-08-10 09:00:15
1431
原创 C++:类和对象(上)
A1类的对象a与A2类的对象b通过sizeof计算出它们的大小都为1,这是为了确保每个对象在内存中占有独立的空间,即使是空类也需要有独特的地址。此时将代码进行调试并转到反汇编指令时发现,d1.Init()与 d2.Init()都call向同一块空间,那么也就说明d1的成员函数与d2的成员函数是共用的,所以类成员函数的是存放在一个公共的代码区域段的地方,那么这样做也是为了节约空间。类中的函数称为类的⽅法或者成员函数。类同样拥有自己的域,类的所有成员都在类的作⽤域中,同时类域不影响变量⽣命周期。
2024-08-06 18:19:45
1058
原创 C++篇:入门(2)
而a的值被修改为20,可以看出在b=c这步操作里,是将c的值赋到了别名b中,而b的本体其实是a,修改b的值同时也是修改a的值。然后,通过返回k的引用来返回一个整型的引用,而因为k是函数内的局部变量,而当函数进行执行完则进行销毁,此时k的引用指向一个已经不存在的内存位置,使用引用进行返回相当于跨过了将值传递给临时变量的步骤。因为返回的是参数,而函数在返回的时候并不是直接返回值,而是会通过一个临时变量将k的值存储起来可能是寄存器的存储,当函数栈帧销毁时,再把存储的值赋给ret1,此时ret1的值是安全的。
2024-08-03 19:41:01
1176
原创 C++篇:C++入门基础(1)
上图代码,小编创建了一个int类型的全局变量rand,并在主函数里尝试输出rand,此时可以看出函数在编译的时候就进行了报错,给出的理由是rand重定义,表明rand在这里是一个函数,而自己又给rand定义成了一个int类型的全局变量,那么在c++的编译是时候是不会通过的。如上图,在函数Add中定义了三个形参a,b,c。C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同,通俗的来说,函数重载就类似于,有很多个同名同姓的人,但每个人都是不同的个体。
2024-08-02 13:43:42
1343
原创 数据结构——排序(C语言版)
a[hole] = a[left]:将找到的大于基准值的元素移到之前坑洞的位置,即hole所指向的位置。这样,prev指向的是当前已经处理好的小于基准值的部分的最后一个元素的位置。希尔排序法的基本思想是:先选定⼀个整数(通常是gap = n/3+1),把 待排序⽂件所有记录分成各组,所有的距离相等的记录分在同⼀组内,并对每⼀组内的记录进⾏排序,然后gap=gap/3+1得到下⼀个整数,再将数组分成各组,进⾏插⼊排序,相当于在插入排序之前对原数据进行一个预排序,当gap=1时就相当于 直接插⼊排序。
2024-07-31 13:43:08
1121
原创 数据结构——链式二叉树(C语言版)
根据顺序,从根开始并没有先输出值而是先开始递归根的左子树,从上图的左子树的递归展开图中,当节点递到3的左子树(NULL)时,先输出NULL接着开始归,重新归到3节点时输出3,接着递归3的右子树(7),并重复步骤,当1的左子树递归完后就输出1节点的值并执行递归1的右子树。想要计算二叉树的深度,就要计算根的左子树与右子树的深度,将左子树的深度与右子树的深度进行比较,并返回较大值,如上图,通过递归展开,会得知左子树的深度为3,右子树的深度为2,最终返回左子树的深度+1,所以上图二叉树的深度为4。
2024-07-27 23:23:54
965
1
原创 数据结构——堆(C语言版)
第三步:在循环里创建一个if语句,如果父亲节点的值小于孩子节点,那么就进行向上交换,孩子变父亲,父亲变孩子,然后将父亲位置赋值给孩子,继续向上找父亲节点位置进行循环判断是否交换,如果不需要交换(父亲节点>孩子节点)就直接退出循环。从上图可以发现,在堆顶(数组下标为0)的位置中存放的数据,是这个堆中最大的值,并且堆中某个结点的值总是不大于其⽗结点的值,我们将这种堆称之为大根堆。从上图可以看出⼆叉树不存在度⼤于 2 的结点 ,并且⼆叉树的⼦树有左右之分,次序不能颠倒,因此,二叉树又是一个有序树。
2024-07-22 21:50:03
940
1
原创 数据结构——栈与队列(C语言版)
一:栈栈的概念:栈(Stack)是一种常见的数据结构,它基于后进先出( Last In, First Out, LIFO)的原则工作。这意味着最后进入栈的元素最先被移除,而最先进入栈的元素最后被移除。栈通常有两个主要操作::将元素添加到栈的顶部。:从栈的顶部移除元素。栈的特性决定了:栈只能访问栈顶的数据,并遵循着先入后出的原则,如果像访问栈底数据,只能将栈上剩余的数据全部依次弹出,不能去遍历,否则会破坏栈的性质。
2024-07-18 13:50:41
980
1
原创 浅谈力扣138题——随机链表的复制
可能有读者会有疑惑,那可不可以直接遍历原链表节点的val值,让原链表random指向的节点中的val值去匹配新链表节点random指针的指向的节点中val值。因为要返回的是全新的的链表,链表中的每个节点都是需要去申请来的,所以,原链表节点中的random指针指向的节点,与新链表的节点中的random指向的节点是毫无关联的。,唯一相同的只有他们的next指针都是指向下一个链表,所以新链表与原链表是毫无关联,不能单纯的通过原链表的random节点去匹配新链表的random节点。这里一定要理解,新链表的地址。
2024-07-13 00:09:09
733
原创 关于力扣——环形链表|| 的一些见解
通过题目给出的示例图,我们可以得知,链表的尾节点指向前面链表的其中某一个节点,这个节点可以在头可以在尾也可以在中间,而我们需要找到链表尾节点的下一个节点及入口循环链表的入口点。当slow走到入口点时,假设此时fast的位置在图中标记的地方,这里需要知道由于slow只走一步并且fast只走两步,所以slow。一个指针从起始点开始走,一个指针从相遇点开始走,这两个指针会在入口点相遇。一个指针从起始点开始走,一个指针从相遇点开始走,这两个指针会在入口点相遇。,这道题的意思是要找出环形链表的入口点。
2024-07-11 14:41:34
556
2
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人