- 博客(48)
- 收藏
- 关注
原创 平衡二叉搜索树之 AVL 树的模拟实现【C++】
我上一篇文章提到的普通二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。AVL树就可以解决上述问题,让搜索树的查找效率在任何情况下都能稳定是O(logN)保证每个结点的左右子树高度之差的绝对值不超过1这样就能保证树中的节点分布接近满二叉树,高度非常接近logN【N为树中节点的个数】,进而让一次查找的效率为O(logN)为什么是保证每个结点的左右子树高度之差的绝对值不超过1,而不是保证左右子树高度一样呢?
2024-10-05 14:22:42 1325 64
原创 普通二叉搜索树的模拟实现【C++】
二叉搜索树又称二叉排序树,是具有以下性质的二叉树:若它的左子树不为空,则左子树上所有节点的值都小于根节点的值若它的右子树不为空,则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉搜索树空树也是二叉搜索树。
2024-09-28 11:22:32 1423 60
原创 多态(下)【C++】
纯虚函数是一种特殊的虚函数,它是没有函数体的虚函数class <类名>public:virtual <类型><函数名>(<参数表>) = 0;纯虚函数的特点:子类继承父类的纯虚函数之后,可以对它进行重写,在子类中被重写的纯虚函数就拥有函数体,并能正常使用了纯虚函数只有声明,没有具体的实现。它为子类提供了一个统一的接口,具体的实现细节则由各个子类根据需要来定义。纯虚函数的声明以必须以= 0结尾,表明该函数没有实现,它只是一个接口。不能直接调用没有被重写的纯虚函数,因为它们没有实现。
2024-09-16 10:50:42 1166 69
原创 多态(上)【C++】
在C++中,虚函数是使用virtual关键字修饰的非静态成员函数。虚函数的主要作用是允许在派生类中重新定义基类的函数,从而实现多态。关于虚函数的一些注意点:虚函数就是为了实现多态而存在的,而且支持虚函数是需要付出一定代价的所以如果不实现多态,就不要定义虚函数静态成员函数不能做虚函数因为①虚表指针存在对象里,但是静态成员的生命周期比对象长,而且静态成员函数里面没有this指针,就找不到对象②因为静态的特性:在以该父类为起始的整个继承体系中只有一份,如果实行多态的话就有多份了,这不符合静态的特性。
2024-09-13 15:27:24 1474 59
原创 继承(下)【C++】
举个例子数据冗余:即D类里面有两份A的成员,而且这两份完全重复,没有必要都存在访问会有二义性:因为D类里面有两份A的成员,那么通过D类的对象访问A类的成员就不知道要访问这两份中的那一份。
2024-08-22 17:48:19 1685 86
原创 继承 (上)【C++】
继承(inheritance)机制是面向对象程序设计使代码复用的最重要的手段它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类(或者子类)。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承的目的是为了代码重用扩展基类的行为,并建立一个类型之间的层次结构。
2024-08-17 11:28:52 1342 64
原创 priority_queue模拟实现【C++】
适配器模式是一种设计模式,它允许将不兼容接口的类一起工作。希望使用一个类,但其接口与其他代码不兼容。希望创建一个可重用的类,它能够将接口转换为其他接口。希望使用第三方库或遗留代码,但其接口与其他代码不兼容。目标接口(Target):这是期望使用的接口,客户端代码只能与目标接口交互。源接口(Adaptee):这是需要适配的类,其接口与目标接口不兼容。适配器(Adapter):这是一个类,它实现了目标接口,并将调用转换为对源接口的调用。
2024-08-08 21:40:59 2159 65
原创 模板进阶【C++】
写一个比较函数,如果是直接写成下图的函数模板,我们就只能按照规定好的大小比较方式进行比较。如下图,当传给A类的模板参数,第一个是int时将会调研偏特化的类模板实例化对象。因为函数模板特化的作用基本只有这个,所以其实函数模板的特化是有替代的,那就是。实例化c对象的时候传给类模板的模板参数都是指针类型,所以调用了偏特化的类模板。第一个模板参数不是int的时候,才会调用基本类模板(母板)进行实例化对象。的参数类型是int*,那就会优先调用int*特化的模板函数。的就会调用偏特化的类模板进行对象的实例化。
2024-08-02 22:04:38 1531 57
原创 queue的模拟实现【C++】
适配器模式是一种设计模式,它允许将不兼容接口的类一起工作。希望使用一个类,但其接口与其他代码不兼容。希望创建一个可重用的类,它能够将接口转换为其他接口。希望使用第三方库或遗留代码,但其接口与其他代码不兼容。目标接口(Target):这是期望使用的接口,客户端代码只能与目标接口交互。源接口(Adaptee):这是需要适配的类,其接口与目标接口不兼容。适配器(Adapter):这是一个类,它实现了目标接口,并将调用转换为对源接口的调用。
2024-07-21 21:29:24 1841 72
原创 stack模拟实现【C++】
适配器模式是一种设计模式,它允许将不兼容接口的类一起工作。希望使用一个类,但其接口与其他代码不兼容。希望创建一个可重用的类,它能够将接口转换为其他接口。希望使用第三方库或遗留代码,但其接口与其他代码不兼容。目标接口(Target):这是期望使用的接口,客户端代码只能与目标接口交互。源接口(Adaptee):这是需要适配的类,其接口与目标接口不兼容。适配器(Adapter):这是一个类,它实现了目标接口,并将调用转换为对源接口的调用。
2024-07-19 20:43:43 1279 53
原创 list模拟实现【C++】
在文件mylist.hpp中定义上一个命名空间mylist把list类和它的成员函数放进命名空间封装起来,防止与包含的头文件中的函数/变量重名的冲突问题。
2024-07-11 09:59:02 2469 64
原创 vector模拟实现【C++】
在文件中定义上一个命名空间myvector把vector类和它的成员函数放进命名空间封装起来,防止与包含的头文件中的函数/变量重名的冲突问题。
2024-07-03 21:48:02 3190 54
原创 模拟实现string【C++】
在文件mystring.h和中都定义上一个命名空间mystring把mystring.h中类的声明放进命名空间,把mystring中的函数实现也放进命名空间不同源文件的同名的命名空间经过编译链接之后可以合成在一起。
2024-06-28 10:04:51 2539 48
原创 模板初阶【C++】
不能简单地直接类名+::而是模板类型声明+类中的成员函数的定义[注意此时类名后面还是要加,因为这样才是一个完整的类类型],这样类实例化对象的时候就可以推导出对应的成员函数的类型由于模板类不完整,所以不能直接用它去限定作用域即在类外实现成员函数等用::区限定时,不能直接限定,要先指定类型。
2024-06-23 12:00:25 2034 47
原创 内存管理【C++】
T* p=new T(传给自定义类型的构造函数的参数)T代指类型,p可以是任意合法标识符T* p=new T【n】{{传给第一个自定义类型的构造函数的参数},{传给第二个}T代指类型,p可以是任意合法标识符,n是要申请的连续的类型空间的个数例。
2024-06-01 11:22:31 2166 77
原创 类和对象【三】析构函数和拷贝构造函数
析构函数(destructor) 与构造函数相反,当对象结束其生命周期,如对象所在的函数已调用完毕时,系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如:在建立对象时用new开辟了一片内存空间,delete会自动调用析构函数后释放内存)。来自百度百科拷贝构造函数是C++中一种构造函数的重载用已有对象创建一个新对象,并将已存在的同类对象的数据成员拷贝到新对象中。拷贝构造函数的形参是一个对该已有对象的引用,并且通常会被声明为const,以防止通过引用修改原对象。
2024-04-27 16:10:34 1307 77
原创 字符型(char)数据在内存中的存储
最高位(最左端的那一位)为符号位,符号位只表示正负(0为正,1为负)不存储数据。所以有符号char的在内存中取值范围为10000000~01111111。char,int,short int类型的值的加减其实是一个循环。那么怎么判断自己的电脑用的编译器char是有符号还是无符号的呢?所以我的电脑的编译器中只写char时char是有符号的。虽然数据在内存中都是以二进制的方式进行存储的,但是。在内存中存储的11111111其实存储的是-1。所以有符号char(signed char)
2024-04-27 09:43:02 700 25
原创 浮点数在内存中的存储
比如,2^10的E是10, 所以保存成32位浮点数时,E必须保存成10+127=137 即二进制的。即 浮点数的小数的二进制表示是1(或0)*2的-k + 1(或0)2的-(k+1)以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。,因为凑不出二的几次方加二的几次方,正好等于小数点后的那几个数。有效数字M不再加上第一位的1, 而是还原为0.*xxxx的小数。浮点数的小数点后数的二进制表示是以2的-k加出来的。,double的E也是无符号数,所以E的范围为。
2024-04-27 09:34:43 601 18
原创 类和对象【二】this指针,构造函数和成员初始化列表【超详细】
C++编译器给每个非静态的成员函数增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),这个指针就是this指针在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成在创建对象时调用的特殊方法。其主要作用是给对象的成员赋值。在C++中,构造函数通常没有返回类型,并且不能被声明为const。在创建类的对象时,构造函数自动被调用此外,构造函数可以重载,即可以有多个名字相同的构造函数,但参数列表必须不同。
2024-04-20 17:30:30 1319 62
原创 类和对象【一】类和对象简介
类体 };记得加分号class是类的关键字ClassName是自定义的类名类体所处的作用域是一个新的作用域,即类域每一个类都有自己的类域例。
2024-04-12 20:18:05 1303 53
原创 函数重载和引用【C++】
函数重载:重载函数是函数的一种特殊情况。为方便使用,C++允许在同一作用域中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指1.参数的个数 2.类型 3.顺序)必须至少有一个不同根据这些同名函数的参数表的不同,达成传入参数类型不同,调用的函数不同的效果引用是给已存在变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。即使用一个变量的引用就是使用该变量,修改它的引用也是修改变量自己例。
2024-04-05 17:00:39 1807 51
原创 函数参数缺省和内联函数【C++】
直接在函数定义//声明的返回值前+一个关键字inline即可例内联函数的调用方法和普通函数一样因为被包含的头文件会在预处理时展开,所以包含了头文件的文件就内使用该头文件中定义的东西c语言编译和链接例。
2024-04-03 12:24:09 1136 47
原创 链表的极致——带头双向循环链表
双向带头循环链表是链表结构最复杂,但使用最方便的链表。[图中phead表示链表的头节点(哨兵);d1,d2等表示链表存储的数据;d1,d2等左侧的方框存储是指向该节点的上一个节点的指针(prev),右侧方框存储指向该节点的下一个的指针(next)]
2024-03-30 19:44:42 1727 24
原创 命名空间【C++】(超详细)
命名空间关键字(namespace)+命名空间的名字+{ 定义的东西 }int b = 0;void dfs();命名空间中可以定义很多类型的东西如 变量,函数,结构体,类,其他的命名空间等等只要可以定义的东西都可以放到命名空间中定义命名空间只能在全局或者另一个命名空间中定义再没有用作用域指定该变量是哪一个作用域时先在局部域中寻找是否有变量/函数的定义在局部域中找不到定义,再去全局域和展开 的命名空间中寻找【不分相后再使用作用域指定该变量是哪一个作用域时直接去该作用域去寻找该变量的定义。
2024-03-30 19:34:04 2935 36
原创 模拟实现堆的接口函数
为什么要将队列里的数据的数据类型重命名?这是为了以后如果改变了SL结构体中数据存储的类型时,不用到处改函数参数等地方的数据类型,只要改typedef后的int 为对应要改成的数据类型就可以。至于给结构体重命名则仅是为了方便使用。
2024-03-16 17:30:56 1413 27
原创 树和二叉树的介绍
树是一种数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:每个节点有零个或多个子节点;没有父节点的节点称为根节点;每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树。
2024-03-16 14:40:31 824 7
原创 详解队列的接口函数
为什么要将队列里的数据的数据类型重命名?这是为了以后如果改变了SL结构体中数据存储的类型时,不用到处改函数参数等地方的数据类型,只要改typedef后的int 为对应要改成的数据类型就可以。至于给结构体重命名则仅是为了方便使用定义该结构体后,使用该结构体再定义一个结构变量,将其初始化后便可用其操作队列。
2024-03-02 16:31:49 763 17
原创 用C语言手把手教你写贪吃蛇
定义一个结构体Snake将贪吃蛇游戏的状态和蛇的状态放入其中,方便管理pSnake:我们使用单链表来维护蛇的身体,pSnake就指向蛇身单链表的第一个节点SnakeSpeed:因为程序执行得太快,所以需要停顿给玩家反应时间,停顿时间越长蛇的速度越慢,停顿时间越短!!
2024-02-03 16:51:37 1611 19
原创 c语言编译和链接
当可执行程序被操作系统加载到内存中时,由于所有的符号已经在链接过程中被重定位,因此程序可以直接使用这些符号,而不需要再进行地址绑定。在静态链接过程中,链接器会在编译后的目标文件中将所有的符号(函数名、变量名等)和它们的地址进行绑定,并将这些地址填写到可执行文件中。在C语言程序链接过程中,重定位是一种重要的步骤,它涉及将不同的目标文件中的符号(函数或变量)的地址合并到一个单独的可执行文件中。C语言的链接过程中,地址和空间分配是一个重要的环节,它涉及到程序的内存布局,即程序在内存中如何分布及其各自的地址范围。
2024-02-01 21:30:57 1862 33
原创 字符串相关函数【超详细】(strcpy,strstr等string.h中的函数)
size_tstrlen返回值【size_t】:无符号整型函数参数【str】:要计算长度的字符串的首地址char*strcpy返回值:目标字符串(destinatuon)的首地址第一个参数(destinatuon):目标字符串的首地址第二个参数(source):源字符串的首地址char *strcat返回值【char*】:目标字符串的首地址参数1【destination】:目标字符串的首地址参数2【 source】:源字符串的首地址intstrcmp。
2024-01-25 11:02:49 1790 36
原创 排序算法进阶——归并排序【详细图解,递归和非递归】
再比较两个序列的第一个元素的大小,将小的那一个元素放在申请的空间的第一个【假设排升序】,再让放入的那个元素之后的一个元素与那个第一次比较时没放入的元素比较,再把小的那一个放入申请空间的第二个位置上…归并算法一般应用于合并两个已经有序的序列,使合并后的序列也有序,是一个时间复杂度为O(N)的算法,不过一般要借助两个要排序的序列的元素个数个额外的空间。归并排序采用分治策略,将序列递归地分成短序列,然后将各个有序的短序列合并成一个有序的长序列,不断合并直到原序列全部排好序。
2024-01-23 17:28:58 2693 35
原创 希尔(Shell)排序
原因是,当n值很大时数据项每一趟排序需要移动的个数很少,但数据项的距离很长。将要排序的序列按一定间隔(增量)分组,将每一组的数据按插入排序进行排序,再缩小间隔,再分组,再将每一组的数据按插入排序进行排序,希尔排序根据增量不同,分组不同,相等的元素可能会被分到不同的组,进而可能在不同的插入排序过程中相等的元素的相对位置改变。希尔排序代码实现其实很简单,就是把直接插入的代码中的增量1,全部换成变化的增量,希尔排序的时间的时间复杂度为O(N^1.5),希尔排序时间复杂度的下界是。与插入排序的代码比较。
2024-01-19 17:36:40 525 3
原创 详解栈的接口函数
栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。栈是允许在同一端进行插入和删除操作的特殊线性表。允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(PUSH),删除则称为出栈/退栈(POP)。
2024-01-18 18:43:14 1253 3
原创 排序算法(初阶)【冒泡,插入,选择排序】
比较次数O(n^2),比较次数与关键字的初始状态无关,总的比较次数N=(n-1)+(n-2)+…插入排序是指在待排序的元素中,假设前面n-1(其中n>=2)个数已经是排好顺序的,现将第n个数插到前面已经排好的序列中,然后找到合适自己的位置,使得插入第n个数的这个序列也是排好顺序的。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。比较是相邻的两个元素比较,交换也发生在这两个元素之间。
2024-01-17 22:26:55 1248 2
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人