自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 1.并查集

思路:遍历两次vector,分别处理==和!思路:将相连城市合并成一个集合,最后计算根的个数。适合于描述这类问题的抽象数据类型称为。并查集的逻辑结构是森林。

2025-04-02 14:50:54 307

原创 34.智能指针

解决方法:把_next和_prev的类型改成weak_ptr<ListNode>,weak_ptr不会增加shared_ptr的引用计数,可以保证资源正确释放。lock 在资源还没有销毁之前,返回一个shared_ptr,增加一个shared_ptr,增加了引用计数,可以用来保证weak_ptr资源的有效性。对于指针是内置类型,拷贝时应为浅拷贝,但浅拷贝对于指针来说没有问题,手动控制释放就行了,对于对象而言,若浅拷贝会导致多次析构资源的问题。

2025-04-01 17:39:50 906

原创 33.异常

C++标准库也定义了⼀套自己的⼀套异常继承体系库,基类是exception,所以我们日常写程序,需要在主函数捕获exception即可,要获取异常信息,调用what函数,what是⼀个虚函数,派生类可以重写。例如:聊天app,因为网络问题消息没有发送出去,这个可视为网络异常,catch捕获后重新发送三次,若依旧没有成功再抛出,这就是异常重新抛出。抛出异常后,程序暂停当前函数的执行,直到找到类型匹配的catch子句,如果到达main函数依旧没有找到匹配的catch字句,cout<<"未知异常"<<endl;

2025-04-01 13:32:27 292

原创 32.C++11(下)

思路:用一个key-value的哈希表村存储操作符对应的操作(lambda表达式),遍历一遍vector,根据key值(操作符)查找,若找到了,说明现在要取数据,取出栈上的数据,第一个为右操作数,第二个为左操作数,利于operator[key]返回可调用对象的引用,计算完后入栈;是⼀个函数模板,它也是⼀个可调用对象的包装器,可以把他看做⼀个函数适配器,对接收的fn可调用对象进行处理后返回⼀个可调用对象。没有实现移动构造,且没有实现析构,拷贝构造,拷贝赋值,编译器会默认生成一个默认的移动构造。

2025-03-31 13:52:06 657

原创 31.C++11(上)

左值:表示数据的表达式(变量名,解引用的指针等),持久状态,存储在内存中,可以获取地址。(const定义的左值,不能赋值,但可以取地址)右值:字面量常量,表达式求值过程中创建的临时对象,匿名对象等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边。不能获取地址。

2025-03-29 17:53:13 838

原创 30.用哈希表封装实现myunordered_map和myunordered_set

T为节点里存的数据的类型,KOfT是为了让unordered_map取出key值的仿函数,Ref为T的引用或者const引用,Ptr为T的指针或者const指针,为了一份模板可以同时实例化出iterator和const_iterator。K为键值,T为节点里存的数据的类型,KOfT是为了让unordered_map取出key值的仿函数,Hash是将K值转化成无符号整形的仿函数,默认支持能强转成整形,对string做了特化。_bucket为哈希表的指针,为了跨单个桶时,能找到下一个桶。哈希表的结构如下所示。

2025-03-28 15:16:40 130

原创 29.哈希算法和哈希表、哈希桶的实现

第一种:设置一个key的值,表示空。处理时,hashi = h(key) = key%M = key%(2^x),这样就保留了2进制的后x位,但是前32-x位没有参与运算,于是做了这样的处理,hashi = hashi ^ (key>>(32-x)),如图所示,散列方式采用的是:除法散列法,链地址法处理哈希冲突的方式是:在key映射的位置存一个单链表头结点的指针,key值映射的位置冲突时,就尾插到单链表的尾节点。要尽量避免M为某些值,比如2的幂,10的幂,key%(2^x),相等于保留key的后x位。

2025-03-27 22:51:23 920

原创 28.unordered_set和unordered_map的使用

3)效率:set/map增删查效率O(logN),unordered_set/unordered_map增删查平均效率O(1)1)迭代器:set/map是双向迭代器,unordered_set/unordered_map是单向迭代器。2)功能:set/map有序+去重,unordered_set/unordered_map无序+去重。使用要求:unordered_set/unordered_map和set/map的区别。unordered_set/unordered_map和set/map的区别。

2025-03-27 10:32:38 254

原创 27.用红黑树封装实现mymap和myset

分析:set和map通过组合的方式,将一颗红黑树封装成队友的map和set。第一个参数传的都是键值Key的类型,第二个参数传的是节点的数据的类型,对于set来说有些多余,毕竟都是Key,但。但若要实现--end()达到反向遍历的效果,可以特殊处理,只不过要传root根节点的指针,当_cur为nullptr即end()时,让_cur等于中序遍历的最后一个(即根的最右节点的指针)需要注意的是:为什么能确定cur是parent左子树的根时parent的左访问完了?仿函数实现在map和set的内部(存疑)

2025-03-26 14:16:45 889

原创 26.红黑树及其模拟实现

若grandparent为根节点,处理完后cur变为根节点,parent为空指针,由于最外层循环条件为parent->_col为红色,要处理空指针解引用的问题,以及cur此时为根节点,根节点为红色的问题。规则3,如果当前结点是红色,左右孩子只能是黑色,即不能有连续的红色节点。注:新增节点的父节点为空,新增节点为新的根,在insert最开始处理,不计入调整。,达到走uncle路径的黑色节点数量不变,同时走cur路径的黑色节点数量也不变。1)新增节点的父节点是黑色,不需要调整,没有了连续的红色节点。

2025-03-25 12:06:49 764

原创 25.AVL树及其模拟实现

AVL树是最先发明的自平衡二叉查找树,AVL是⼀颗空树,或者具备下列性质的二叉搜索树:它的左右子树都是AVL树,且左右子树的高度差的绝对值不超过1。3)插入后平衡因子为-2或2,说明原来是-1或1,一边高一边低,插入到高的那边了,需要旋转,旋转完后停止更新。可以看到,数据量为100万,在release下,find的效率极高,至于Insert,new节点的效率比较大。,一边高一边低,插入到低的那边了,左右子树一样高了,停止更新。,两边一样高,插入在左边或右边了,会影响上层节点,要向上更新。

2025-03-23 15:50:53 776

原创 24.map和set的使用

可以看到,operator[]内部调用insert,insert返回一个pair<iterator,bool>的结构,插入成功,pair.second为true,反之为false,pair.first为key位置所在的迭代器,operator[]返回该迭代器位置的value的引用。对于C++,简单很多,只需要将定义一个节点指针cur从头开始走,插入到set中,直到set插入失败,即回到环的开始节点了,此时插入失败的节点指针就是入环的第一个节点。这样原链表节点的映射关系,拷贝链表也有了。

2025-03-22 16:47:32 750

原创 2.Linux基本指令(下)

将"hello linux"重定向到hello.txt中,若存在hello.txt,清空内容,再写入内容,若不存在,创建hello.txt,然后将内容写入到hello.txt。由于Linux一切皆文件,显示器也是文件,ll /dev/pts查看显示器所在目录,使用左终端即1号,将"hello world"重定向到右终端2号。可以看到时间不是00:00,是因为00:00是格林威治时间,北京是东八区,有8小时时差。date + %Y-%m-%d_%H:%M:%S -d @0 (将时间戳0转换成时间)

2025-03-20 21:54:08 699

原创 23.二叉树进阶面试题

(再次循环,从根开始一直访问左子树,存入根的值,直到左路节点被访问完了,取出左路节点,访问右,赋值给cur)实现过程:与前序遍历的思想类似,只不过区别在于根的访问时机,中序遍历是:左子树 根 右子树,第一个访问节点为最左节点,即栈上存左路节点的最顶层节点,于是只需将原访问根的顺序改为,取出节点时访问即可。106思路:和前序遍历反过来差不多,后序遍历是 [左子树,右子树,根],根在最后,是倒序的方式,但是倒序是:根,右子树,左子树,划分区间与105思路一致,但是递归构建时优先构建右子树。

2025-03-20 15:44:43 682

原创 22.二叉搜索树及其实现

最优情况下,⼆叉搜索树为完全⼆叉树(或者接近完全⼆叉树),其高度为: log2 N。最差情况下,叉搜索树退化为单支树(或者类似单支),其高度为: N。所以综合而言⼆叉搜索树增删查改时间复杂度为: O(N)4.可以插入相同的值,也可以不支持插入相同的值。二叉搜索树实现(key_value版)1.非空左子树的值全都小于等于根的值。2.非空右子树的值全都大于等于根的值。3.它的左右子树也是二叉搜索树。二叉搜索树的删除Erase。二叉搜索树(key版)二叉搜索树的性能分析。

2025-03-18 20:14:16 178

原创 21.多态

通过监视窗口可以看到,p,s,t对象各有一个虚函数表指针_vfptr(virtual function table 虚函数表指针),且指针的值不同,说明指向不同的空间,而且指向的内容函数指针不同,p对象为它的Person::func的函数指针,重写的s和t对象为各自重写的函数指针。时,只调用了父类A的析构函数,没有调用子类B的析构函数,导致内存泄漏。原因,b对象中有_vfptr,虚函数表的指针,存在对象的起始位置,类型为void**,在32位环境下是指针是4字节,根据内存对齐规则,对齐后为12字节。

2025-03-17 21:19:16 1019

原创 1.Linux基本指令(上)

Change时间(Ctime)应该是指文件的元数据(metadata)发生变化的时间。例如printf,既是命令,也是C语言的函数,若不指定,查到的是第一册的命令printf。pwd 打印当前所处的内目录(process进程,work工作,directory目录)Linux中,任何一个目录,即便是一个空目录,默认系统都会自带.和..目录。Modify时间(Mtime),文件内容最后一次被修改的时间。Access时间(Atime)指文件最后被访问的时间。对于目录,列出当前目录下的文件(显示文件的属性)

2025-03-16 15:57:34 512

原创 20.继承

子类构造要调用构造,但是私有的成员子类调用不了,所以子类就无法实例化出对象。答案是C,因为多继承的类的对象内存模型是:按继承顺序依次存储,子类的成员存在最后,因此p1==p3!其中,ptr和&pp的值一样,都为0x012ff76c,都是子类对象中父类那段空间的地址,说明了。多继承的在内存中的模型:先继承的父类在前,后继承的父类在后,子类成员在最后。(类名::父类静态成员名)继承父类成员看作一个整体对象(看作子类的成员),要求调用父类的默认构造。被继承的类叫父类/基类,继承产生的新的类叫子类/派生类。

2025-03-13 20:47:52 519

原创 19.模板进阶

关系如图,在Test.cpp中,在编译时,只有Add()和func()的声明,编译也能通过,可以在链接的时候找。但是只有func()这个具体函数在汇编时进入了符号表,Add()函数模板没有实例化,汇编时没有进入符号表。链接时,Add()在符号表中找不到,链接错误。一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。设计目的:T1和T2是原类型,这样既能用原类型,又能用指针和引用,又达到了特化的效果,一举三得。

2025-03-12 14:03:56 541

原创 18.deque&priority_queue

_deque_iterator有四个成员变量,cur是指向buff当前位置的下一个指针,first是指向buff开始位置的指针,last是指向buff结束位置的指针,node是指向当前buff所在位置的二级指针。deque有四个成员变量,start是指向开始位置的迭代器,finish是指向结尾位置的迭代器,map是一个二级指针,指向一个指针数组,map_size是一级指针数组的大小。进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;2.头部和中间插入删除效率低。

2025-03-11 17:08:42 768

原创 17.stack&queue

stack和queue都是容器适配器,封装现有容器,提供特定数据结构的操作模式。

2025-03-09 16:19:21 283

原创 16.模拟实现list

这意味着它实际上是在初始化时由编译器生成的一个静态数组,std::initializer_list 只是对这个数组的一个包装,以便提供标准的接口(如迭代器)。因为iterator和const_iterator只在*(解引用)重载和->(箭头解引用)重载的返回值和this指针的类型不同(const 类名* const this和 类名* const this)。it->_a1,实际有两个->,第一个it.operator->()返回AA*,然后AA*->_a1,返回_a1。stl_list.h源码分析。

2025-03-09 15:07:24 311

原创 15.list

在release版本下,数据量为1000万的情况下,list排序是 list拷贝数据到vector,vector排完再拷贝回list的时间的1.5倍。3)转移链表x的[first,last)区间的节点,插入到自身链表position位置之前。默认升序,若要排降序,lt.sort(greater<int>());2)转移链表x的i位置上的节点,插入到自身链表position位置之前。顺序结构容器,允许在任意位置以常数时间插入和删除,迭代器是双向的。由两个案例可见,list的sort()排序效率很低。

2025-03-07 22:20:55 517

原创 14.模拟实现vector

模拟实现vector和易错点总结

2025-03-07 21:04:02 890

原创 13.vector

由此可看出iterator是原生的T*的指针,那么可以推断出,start时开始位置的指针,finish时数据结束位置的指针,end_of_storage时内存结束位置的指针。相比于string的reserve()函数,string在n小于等于容量时reserve()行为描述是不具有约束力的缩容,而vector的描述是不缩容。发现这里使用的定位new显式调用构造函数,原因:使用内存池是先开空间,然后要用定位new显式调用构造函数。n大于size,用默认构造的val填充,直到size为n。

2025-03-07 18:06:15 546

原创 12.模拟实现string

加入一个char buff[N],每次尾插一个字符时都加到buff上,buff满时,s+=buff,然后buff相当于清空,循环往复,最后再加上剩余的buff。传参时就拷贝构造一个tmp对象,然后与*this交换,*this达到拷贝效果的同时,*this的资源也由tmp出函数栈帧时,编译器自动调用tmp的析构函数销毁,时,并不深拷贝,只是浅拷贝,使s2内_str的指向和s1一致,然后++引用计数。string存一个指针,指向数组,由于g++默认64位,指针是8字节,因此string是8字节。

2025-03-06 15:27:19 611

原创 11.string(下)

/查找子串,找到了返回pos位置,找不到返回string::npos(size_t npos= -1;//交换内容(内存)find_first_not_of();

2025-03-03 19:59:11 253

原创 10.string(上)

1)早期C/C++中auto的含义是:使用auto修饰的变量,表示变量具有自动存储期,意味着变量的生命周期限于它所在的代码块(如函数、循环体等)。begin有两个重载,一个是普通迭代器的,一个是const迭代器的,用begin和cbegin一样,编译器会默认调用最匹配的。//数据量小的时候存buff上,大于16,buff废弃。4)当在同一行声明多个变量是,这些变量必须是相同类型,因为编译器只对第一个类型进行推导,其他的沿用。3)范围for(自动赋值,自动迭代,自动判断结束,适用于所有容器)(迭代器的封装)

2025-03-02 17:57:26 998

原创 9.模板初阶

此时要么统一i,d的类型,使编译器推导实例化,要么指定Add函数的类型显式实例化。//重新开一块空间,将_array的数据拷过去,然后释放_array。插入操作扩容时,开一块更大的空间,把原来数据拷贝过去,释放原空间,更改指针指向。泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。若直接调用Add(i,d),编译器将无法推算出T的类型。//typename和class可以混用,没有区别。//让_array指向新空间。//修改capacity。//声明和定义分离要声明模板参数。模板是泛型编程的基础。

2025-03-01 17:06:35 247

原创 8.C/C++内存管理

char2也是局部变量,因为char2是一个数组,"abcd"这个常量字符串会给char2进行初始化,char2在栈上开辟5个字节的空间,然后初始化一份 a,b,c,d,"\0"。注:operator new() 全局函数,malloc加强版,对malloc实现了异常处理机制,返回值为void*类型,需要强转。6)申请自定义类型对象时,malloc/free只完成空间的开辟/销毁,new/delete会调用构造函数和析构函数。

2025-03-01 16:14:14 680

原创 7.类和对象(下)

用途:类A,类B,其中类B想大量访问类A中的私有和保护的成员变量,此时可以把类B设置为类A的友元类。第二种写法,创建了A类型临时对象,用1构造。3)用static修饰的成员函数称为静态成员函数,可以访问静态成员,不能访问非静态的,因为不存在this指针。内部类的本质是一种封装,当A类和B类紧密相连,且A类设计出来只是为了给B类使用,这时就可以把A类设置成内部类。3.引用,const成员变量,没有默认构造函数的自定义类型,必须在初始化列表初始化,否则,编译错误。A是B友元,B是C友元,A不是C友元。

2025-02-27 21:21:34 997

原创 6.日期类的实现

【代码】6.日期类的实现。

2025-02-27 15:42:56 199

原创 5.类和对象(中)

的对象时候,C++允许我们通过运算符重载的形式指定新的含义。2)拷贝构造函数的第一个参数必须是自身类类型的引用,可以有其他参数,但必须给出默认值。4)如果一个重载运算符函数是成员函数,由于它的第一个运算对象默认传给隐式的this指针,那么参数会少一个。第一个参数是自身类类型的引用,若有其他参数,其他参数都有默认值的构造函数称为拷贝构造函数。2)有返回值,目的是为了连续赋值:d1=d2=d3,返回值建议为类类型的引用,减少拷贝。8)重载操作符至少有一个类类型的参数,不能改变运算符在内置类型的实际含义。

2025-02-25 15:57:52 749

原创 4.类和对象(中)

对于自定义类型成员变量,调用这个成员变量的默认构造函数初始化,没有默认构造函数就报错。拷贝赋值:拷贝构造(同类对象初始化创建)和 赋值重载(把一个对象赋值给另一个对象)。一个类,默认生成6个默认成员函数,C++11以后增加2个(移动构造和移动赋值)7)编译器默认生成的构造,对内置类型成员的初始化没有要求,初始化不确定。6)无参构造、全缺省构造、编译器默认生成无参构造,都叫做。5)默认生成,内置类型不处理,自定义类型调用对应。3)一个类只能有一个析构函数,未显式,默认生成。作用:对象实例化是初始化对象。

2025-02-24 17:19:14 303

原创 3. 类和对象(上)

实际上真实的函数为:void Print(Date* const this) 在调用时隐式传对象的地址,上述程序正常运行,因为Print函数不存在于对象中,函数地址在编译链接的时候找。C++不支持显示写这个参数和传参,但是可以在函数体内显示调用this指针。类的成员函数访问成员变量,本质都是通过this指针来访问的。编译器在编译链接时,就要找到函数的地址,不是在运行时找。类定义形成了类域,类域没有展开using的说法。,大小是1字节,给1字节是为了标识对象存在。类的函数:方法或成员函数。

2025-02-24 16:57:01 301

原创 2.C++基础(下)

void f(int x) {} 和 void f(int* ptr) {},C++中,void*不能给任意类型的指针。5)sizeof的含义不同,引用结果是引用类型的大小,而指针大小是地址空间所占的字节数,32位4字节,64位8字节。可以传const对象,临时对象(表达式、类型转换(函数返回值)),常量,普通对象。就是编译器需要一个空间暂存表达式的求值结果时,临时创建的一个未命名的对象。6)指针容易出现空指针和野指针的问题,引用很少出现,引用相对更安全。4)引用可以直接访问对象,指针需要解引用才能访问。

2025-02-24 16:23:07 266

原创 1.C++基础(上)

2)using namespace 空间名 :: 成员名 将命名空间中的某个成员展开。命名空间,需要使用namespace关键字,后面跟着命名空间的名字,然后接一对{}。std::cin是istream类的对象,窄字符的标准输入流。std::cout是ostream类的对象,窄字符标准输出流。3)函数声明和定义分离时,缺省参数不能同时出现,规定必须。std::endl是一个函数,加一个换行符刷新缓冲区。特别地,::a,左边不写,默认是全局域。特别地,include展开,拷贝类文件。

2025-02-24 14:10:31 280

空空如也

空空如也

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

TA关注的人

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