自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 数据结构: 链表回文结构/分割链表题解

这题思路是分割链表,分成小节点链表和大节点链表,并且始终保证小节点的指针指向小节点链表的尾部,大节点指针指向大节点链表的尾部,再让小节点指针的尾和大节点指针的头相连。需要注意的是,这题要改变头节点,所以要设置哨兵位。最后也要记得把大节点指针的尾连上空指针。再把数据的两端进行比较,遇到不等的或者第二个头走到空,就结束了。全等返回真,不等返回假。先找到链表的中间节点,再对中间节点的下一个节点进行逆置,返回值为最后一个节点。结合逆置链表+找到链表的中间节点就可以解决了。这道题的难点是空间复杂度为O(1)

2024-07-21 22:03:52 231 1

原创 C++: 位图和布隆过滤器

所以在需要设置的位&0,其他位&1,就能保证只有这个需要改变的bit位设置为0,不造成对其他数据的影响。高效地插入和查询,可以告诉你,某种东西一定不存在或者可能存在,用多个哈希函数,将一个数据映射到位图中,不仅可以提升查询效率,而且很大节省空间。运用哈希的思想,将整型映射到比特位上,比特位上的值为0就是不存在,1就是存在。b.存在的值,不会判定为不存在,如果判定不存在,则一定不存在。不存在的值,可能会发生哈希冲突,判定为存在。a为0或者1,当1 | a=1,通过按位或的特性,把比特位上的值设置为1.

2024-07-18 16:14:12 847

原创 数据结构 : 移除链表元素/合并两个有序链表题解

像这种移除元素的,加个哨兵位头节点会比较方便,因为旧的头会有被移除的情况,不好控制。这里只需要用cur指向待遍历的节点,prev指向cur的前一个节点就可以。考虑到有连续被删除的节点,所以判断相等应该在循环里进行。3.考虑两个都不为空,声明两个指针代替两个链表的头节点进行遍历,哪个节点val值小就进行尾插,尾插后该指针往后走。剩下的节点都是升序了,直接尾插就好。1.cur是空,prev是空,prev一开始是指向空的。不相等,prev往后走,cur往后走就好。2.prev是空,cur不是空。

2024-07-17 22:26:55 191

原创 C++:哈希表特性及开散列哈希表的模拟实现

它是一个顺序表,每个节点是一个指针,下面挂着的都是指针。相当于这个哈希表是一个指针数组。如果遇到哈希冲突,就把这个值进行头插。需要找的时候,就在这个链表上找。这个方法一般设置负载因子为1,在元素数据等于哈希表容量时,就要扩容。这样每个节点下也不会说挂太多值。在好的哈希函数之下,即使有哈希冲突,节点下面挂的节点并不会太多,查找的效率很高,时间复杂度就可以看作O(1)了。

2024-07-17 14:53:21 849

原创 数据结构:链表插入排序/删除重复节点题解

cur节点指向即将判断的第一个节点,next节点指向即将判断的第二个节点。这里要声明3个节点,头节点是已经给了的,始终指向第一个存在的位置,如果它要被删除,那么它要更换别的不被删除的位置,如果所有的节点都可以消消乐,那么就要让它指向空。2.删除的重复节点是头节点和不是头节点要分别处理,是头节点,那么头节点要换到next,不是头节点,就不需要更换头节点了。4.在判断cur节点和next节点值相等的循环中,跳出循环时,next走到下一个节点,下一个节点是空和不是空要分别处理。插入排序的思路很简单,基本都知道。

2024-07-16 21:54:12 158

原创 数据结构: 链表环形题题解

3.判断两人相遇,必须要在慢指针和快指针都走完以后再判断,这样回合制才合理,否则顺序颠倒,遇到无环的可能也返回错误。2.快指针在移动两个节点之前,要检查一下它下一个节点是否为空节点,如果是空的话,说明无环,直接返回就可以。2.由于已经处理过了,就是走到同样长的位置了,所以要先判断两指针是否相遇,然后再走下一个节点。前言:题目都是leetcode的原题,拿来复习一下链表,并养成解题习惯。}这么写有bug,count--我是放在循环体里处理的。代码实现还要注意一下细节的处理,1.链表为空,只有一个节点的链表。

2024-07-13 16:34:43 203

原创 C++: map和set的使用

set和map都是关联式容器

2024-06-09 13:57:12 329

原创 C++: 二叉搜索树及实现

由于使用递归,所以需要取root的引用,参数就要给root,而在类外是没有办法获取作为私有的root的,因此只能把实现的细节写在private里。

2024-05-27 22:00:59 610

原创 C++: 多态

在Func调用基类的对象a1时,Func从传来的引用,基类的对象a1中去找虚函数指针,找虚表,然后找到要调用的函数。如果是派生类的对象b1,就从b1中去找虚函数指针,找虚表,找到相应的地址和指向的函数,从而实现了多态,即相同的接口,传的对象不同,实现不同的行为。

2024-05-23 18:46:32 860

原创 C++: 继承

C++的语法复杂,因为多继承和菱形继承复杂,还有了虚继承,虚基表,表中存偏移量。这些就一直在填多继承语法的坑。

2024-05-21 20:37:10 890

原创 C++: 优先级队列的模拟实现和deque

1.11 优先级队列是一种容器适配器,根据严格的弱排序,它的第一个元素总是它所有元素中最大 的。适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),这种设计模式将一个类的接口转换成客户希望的另一个接口。比方说,在stack里面,把push接口转换成调用另一个容器的push_back,这个容器的类放在私有里,是根据初始化来定的,你希望这个底层容器是vector,那么在调用stack的push时,实际调用的就是vector的push_back进行插入元素操作。

2024-05-19 14:19:34 911

原创 C++: stack类和queue类的使用及模拟实现

1.11 stack是一种容器适配器,专门用在具有先进后出的上下文环境中,插入和删除都只能从一端操作。1.12 stack作为容器适配器实现,它底层是其他类或容器。它只需要提供一些函数接口实现功能就好。1.13stack的底层容器可以是任何标准的容器类也可以是其他特定的容器类。这些容器应该支持以下操作:empty:判空push:压一个元素入栈top:取栈顶的元素pop:在栈顶出数据。

2024-05-17 21:10:44 463

原创 C++ : list类及其模拟实现

1.list 是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。2.list的底层是带头双向可循环链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。3.list和forward_list非常相似:最主要的不同在于forward_list 是单链表,只能朝前迭代,让其更简单高效。4.与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。

2024-05-05 22:48:04 1051

原创 c++: vector和其模拟实现

vector是顺序表,在数据结构学习顺序表时,插入的数据是int,但实际上顺序表作为一个数组,里面的元素可以不止是整型数组,可以是char等其他类型的。这一点是有必要转变的。vector运用动态内存分配空间,比起其他容器,vector在插入和读取数据上比较方便,但是在删除时要一个个挪动数据,这一点可能会有点效率低,因此需要频繁删除的文件不适合用vector存储。vector在使用中需要掌握主要的几个接口,其他情况看文档和c++官网的说明就可以使用。本次模拟实现只是为了更深入了解vector的功能。

2024-05-01 15:36:28 365

原创 C++: string类的模拟实现

本次模拟实现主要是为了更深入地了解string类的各种接口和函数的功能。所以并不是写一个能和库媲美的模拟实现,只是实现其中主要和常用的功能。

2024-04-27 15:34:20 863

原创 C++ :string类模板的使用

学完模板以后,基本都知道模板分为函数模板和类模板。它将底层逻辑封装起来,向外提供接口,当使用的时候,只要调用一份模板实例化对象就可以,不需要自己写。这大大提升了写代码的便利。C语言中,字符串是以'\0'结尾的一些字符的集合。为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数和字符串是分离开的,底层空间要用户自己管理,不注意还会越界访问。所以要学习string类。在使用string类时,必须包含#include头文件和using namespace std;

2024-04-19 19:35:07 1014

原创 C++: 模板初阶

当给函数传参的时候,传的参数不一样,编译器会根据参数进行推演函数的参数类型应该是什么样,然后编译器自己写一份这样的函数给用户调用,所以并不是没有这份代码了,它就不存在了。这种情况,如果模板函数和调用时更匹配,编译器会用模板函数实例化,而不会用非模板函数的类型转换。在汇编的时候,或者把函数的地址打印出来,可以看到不同参数调用同一份模板会产生不同的地址的。如果显式实例化类型不匹配,编译器会尝试使用隐式实例化,如果转换失败,那么编译器会报错。函数模板只是一个模具,它只有在调用的时候,才会实例化。

2024-04-15 20:18:09 344

原创 C++: 内存管理

调用operator new 申请空间在申请的空间上执行构造函数,完成对象的构造。

2024-04-14 14:09:07 554

原创 C++: 类和对象(下)

最后一个计算日期之间相减的方法,我用了日期的前置++,调用了前置++的方法,前置++里面,又调用了+=的运算符重载,在+=这个方法里,我写了日期相加天数以后,超过本月天数和超过12个月的预防措施。这么写之后,该函数就是该类的朋友,函数可以使用类的成员(包括对象和函数),但是朋友是单向的,不是双向的。1.初始化列表的初始化顺序,是按照下面成员变量声明的顺序进行的,不是按照列表写在前后的顺序。则Time类的成员Date都可以访问,但Date类的成员,Time不能随意访问。在Time类中,写了Date类的声明。

2024-04-12 20:06:51 596

原创 C++ : 类和对象(上)

2.用户没有显式定义时,编译器会生成一个默认赋值运算符重载,以值的方式拷贝。对内置类型是直接赋值,对自定义类型调用该自定义类型的赋值运算符重载来完成赋值。3.像拷贝构造一样,赋值运算符重载也面临着对申请过资源的情况,必须自己写一个赋值运算符重载,而不能依赖系统给的。否则可能会发生两个不同对象占用同一块空间的尴尬局面。并且一个空间的销毁也会影响另一个空间。前置++和后置++重载。

2024-04-05 21:58:47 686

原创 C++: auto/范围for/类

1.声明和定义全部放在类体中。成员函数如果在类体中定义,编译器可能会把它当作内联函数。前面说了,内联函数声明和定义是不能分离的,因为内联函数会直接展开,如果分离是找不到地址的。2.类声明放在.h文件中,成员函数的定义放在.cpp文件中,注意,在定义成员函数时,成员函数的名字前面和返回类型的后面要加。

2024-04-04 22:55:27 727

原创 C++: 命名空间/C++输入输出/缺省参数/函数重载/引用/内联函数

2.一个变量可以有多个引用3.引用一旦引用一个实体,再不能引用其他实体。

2024-04-01 22:23:30 1060

原创 数据结构:排序

后面的数再和已经有序的数组中最后一个比,比它小再往前依次比,直到找到比手中的数更小的数,就放它后面了。最后再把有序的新数组的数复制到之前的数组。数组第一个数和第二个数比,大的往后,然后第二和第三比,大的往后,走一趟确定一个最大的数,然后排剩下的,把剩下的中最大的排在倒数第二。以此类推,当这个分母越大,逼近于N时,间隔就越小,间隔趋近于1,整体越发有序,当gap=1时,就是有序排序了。关于这个排序稳定性的说明,它取数是依次取的,就算值相等,那么先取的在前面,后取的在后面,根本不会改变相同值的位次。

2024-03-31 23:15:41 724

原创 数据结构:堆和二叉树遍历

堆顶就是这个堆最小的数,堆顶和这个堆的最后一个数换位置,然后再把最后一个数取出,再pop这个数。答:先取出50个建小堆,剩下的数和堆顶相比,遇到大于堆顶的数就直接替换掉堆顶的数。替换一次,小堆也要向下调整一次,保持它是一个小堆。向下调整就是每次取个数,由于和堆的最后一个数交换了位置,取出之后的二叉树需要调整一下才能成为一个堆。如果是大堆,就比较堆顶的和左右子树,大于它,堆顶和大的那个交换,这样层层交换下去。此问题也可以用于:内存空间不够,建堆数量有限,如何在大量的数据中取出前k个最大(小)的数。

2024-03-20 23:19:55 677

原创 数据结构:树和二叉树

也就是说,二叉树的所有节点的孩子,最多只能有两个。如上图所示,F节点是所有节点的根节点,也是祖先节点。2.若 2i+1 < n , 左孩子序号: 2i+1, 2i+1>=n 则无右孩子。3.对任何一棵二叉树,如果度为0的叶子节点数是N0,度为2的节点数为N2,则有N0=N2+1。1.如果根节点是第1层,那么一颗非空二叉树的第i层上最多有2^(i-1)个节点。4.若规定根节点是第一层,具有n个节点的满二叉树的深度为h=log(N+1).2.如果根节点是第1层,那么深度为h为的二叉树最大节点数是2^h-1。

2024-03-12 15:55:15 429

原创 数据结构:栈和队列

队列:一种特殊的线性表,只能从固定的一端入数据,从另一端出数据。一般把出数据的一端叫队头,入数据的一端叫队尾。队列要频繁的头删尾插,如果用顺序表,就要在删除时,不断地挪动后面的数。所以一般用链表实现。栈:一种特殊的线性表,只能从固定的一端入数据和出数据。一般把出入数据的一端叫栈顶,另一端叫栈底。栈的出入顺序遵从——后入先出的原则。下面是stack.c文件,具体实现栈的各个功能。压栈:把数据放入栈中,叫压栈/入栈/进栈。上图压栈按照1234的顺序连续放,出的时候是4321。出栈:把数据移除栈中,叫出栈。

2024-03-06 20:13:30 531

原创 【原创】烟花实现,基于windows操作系统

我尝试了一下,在9-15是最合适的,选择了12个结点。我首先把c语言本地化,然后复制了许多特殊字符,尝试它们在控制台能打印出来的结果,把能够打印出来的筛选字符都列出来。花筒直接用宽字符打印出来就可以,烟花的花束需要设置一个结构体,和贪吃蛇的蛇身一样(贪吃蛇的实现见上篇文章),只不过是单向向上移动,而且移动的速度要快许多。烟花的实现是我自己独立实现的第一个项目。借助贪吃蛇的删尾的思路,在原坐标处打印两个空格字符就可以覆盖掉。下面是花筒,上面是烟花在上升时的花束和升到制高点时绽放的花体。(虽然是长方形的烟花)

2024-02-12 22:45:59 556

原创 贪吃蛇的实现,基于windows操作系统

收尾部分主要是游戏玩了一把game over以后,因为各种原因结束而打印不同信息。打印完了要把蛇的结点依次释放。然后再把食物释放,把传来的维护蛇的指针置为空。如果想设置再来一把的消息,可以在test.c文件里进行。要注意两个getchar。第一个getchar用来读取信息,通过一个变量来接收,用于判断玩家到底要不要开下一把。第二个getchar用来接收读取回车字符,但是没有变量接收它,也就是它不产生实际作用。因为它的目的只是用来吸收回车,使这个回车键不至于影响到下一次的输入判定。

2024-02-12 22:20:48 1093

原创 数据结构:用顺序表和单链表实现通讯录(下)

如果测试文件中不需要调用,但在函数实现中需要用到,可以写在函数定义的slcontact.c文件(亦即可以不声明)。如下图所示,通讯录是一个结构体,里面存有数据和下一个结点的地址。删除联系人时,需要查找联系人(也可以封装一个函数),找到以后再删除,删除完了再展示一下当前通讯录(这一点可不写)如果要改变当前指针的地址,就用二级指针接收,如果不需要改变,就可以用一级指针接收。需要注意,顺序表是直接创建的结构体,这里是创建一个结构体指针。添加联系人时,需要一个创建新结点的函数以及一个尾插的函数。

2024-02-01 17:42:16 528

原创 数据结构:用顺序表和单链表实现通讯录(上)

首先简要介绍顺序表和链表的概念和区别以作区分。顺序表:逻辑上是线性的,物理性质上也是线性的。逻辑是线性的(连续的)体现在它可以通过第一个数找到接下来的数。物理性质上的线性体现在分配给它的内存是连续的。它本质上就像一个数组,可以通过下标来访问成员。单链表:这里说的单链表是指不带头单向不循环链表。链表和顺序表是不同的。链表在逻辑上是线性的,但在物理性质上是非线性的。需要的时候申请一块内存,但这块内存和其他内存不一定连续,它可能是散落在四周的,只是通过记住下一个节点的位置,使这些单独存在的空间有了联系。

2024-01-31 17:57:49 611

原创 C语言:编译和链接

我们写的代码实际上是一个文本文件,对文本文件运行不会生成可执行程序。但是在VS或者gcc等开发环境中,内置了编译器和链接器,使它生成一个计算机可以理解可以执行的二进制程序,这个可执行程序用.exe为后缀。编译和链接主要就是解释代码是如何从文本文件变成可执行文件的。编译这个过程就是把一个工程中的各源文件,通过编译器,编译成.o为后缀的目标文件。链接就是把这一个个的.o为后缀的目标文件整合处理成一个.exe为后缀的可执行程序。需要注意,.o为后缀的文件也是计算机可以理解的二进制文件。

2024-01-19 17:53:21 959

原创 C语言文件操作

文件可以保存数据,如果没有文件,我们写的程序的数据保存在电脑内存中,程序结束后,向内存申请的空间就会被操作系统回收,数据就没啦。流是一个抽象的名词,用于对各种设备的统称。每个文件都在内存中开辟了一个相应的文件信息区,用来存放文件的信息。程序文件包括源程序文件(.c后缀),目标文件(windows环境后缀是.obj),可执行程序文件(后缀.exe)。比如说10000,用ASCII形式,就要占5个字节,用二进制形式,占用4个字节。每当打开一个文件,系统会自动创建一个FILE类型的结构体变量,用来操作这个文件。

2023-12-15 15:52:53 472

原创 C语言动态内存管理malloc/calloc/realloc/柔性数组

介绍三个库函数,它们可以直接向内存申请特定大小的空间,然后就可以使用这些空间了。这三个库函数分别是malloc calloc realloc明明已经有结构体、数组、int、float、double等类型可以直接创建,向内存申请空间。为什么还要这三个库函数呢?前者申请创建的内存大小是不能改变的,创建时是多少就是多少。而malloc、calloc和realloc申请的内存空间是可以改变的。如果感觉内存不合适,随时可以再加或者减。前者创建的内存是在栈区,而通过malloc等函数申请的空间在堆区。

2023-12-09 14:34:11 1128

原创 C语言联合和枚举

枚举的每一个成员都有默认值,第一到最后一个依次从0递增。如果中间某个成员定义为388(或某个数),后面的也依次递增(389...不再按照默认值)。枚举有类型检查,有作用域,一次可以定义多个常量,便于调试,增加代码可读性。它也是由多个不同类型的成员构成。不同的是,联合体的成员共用一块空间。枚举可以定义常量,枚举里面可以包含可能的全部取值。枚举中,定义完1个常量后,用逗号。联合体的大小至少是最大成员的大小。是成员中最大对齐数的整数倍。联合体不能同时取所有成员的值,而只能取其中一个。改变b的值也会改变a的值。

2023-12-06 19:26:09 393

原创 C语言结构体和位段

2.编译器在读取内存的时候有些是8个字节8个字节的取,如果不采用对齐数,就可能出现一次读取没读到完整的字节,要读取好几次才能读取到一个变量。不一样的是,stu是自己定义的标签。4.结构体有嵌套的情况下,嵌套的结构体成员对齐到自己成员中最大对齐数的整数倍上,结构体总大小是内部所有成员中最大对齐数的整数倍。1.有些编译器只能从特定的对齐数上取数,比如int型从4的对齐数取数,如果不采用对齐,那么取不到数。位段的内存申请不是按照比特申请的,是按照char和int的方式,也就是1个字节或者4个字节来申请的。

2023-12-05 18:47:42 1281 1

原创 C语言数据在内存中的存储

也可能是 44 33 22 11的顺序存储,地址从左到右,由低到高,44是低位,存在低位地址,说明该模式是小端存储。如果留下的是00,这显然是高位的数,低地址存高位内容,就是大端。留下的是01,也就是1,这是低位的数,存在低地址,所以是小端。使用反码存储,是因为计算机可以把符号位和数值位进行统一处理,加法和减法也可以统一处理,补码和原码之间的换算也是相同的,不需要额外的硬件电路,非常方便。,因为只能存1个字节,就是8个比特位的数,就算把数塞满,最多也就是127,如果符号位是1的话,那就是负数。

2023-12-04 16:58:44 522

原创 C语言内存函数

这里主要介绍两个内存函数:memcpy和memmove这两个函数都是库函数。

2023-12-03 13:03:24 561 1

原创 C语言字符函数和字符串函数

当*m==*n时,flag是不变的,flag储存的是他们相等的第一个字符的位置。例如:目标字符是swimming,源字符是min,strstr会从swimming的第一个字符s开始找,找它是否和源字符的第一个字符m相等,相等就下一个对比。作用是把一串字符复制到另一串字符中,用源字符取代目标字符,源字符会替代目标字符的 末尾的 \0。相同作用的还有strncat,多了一个参数num,将源函数追加到目标字符后面,会追加\0,如果源字符小于num,那也不会多加内容。在C语言中,0是假,非0是真。

2023-11-30 20:45:14 963

原创 C语言回调函数/qsort

当一个函数的地址/指针被当作参数,传给另一个函数,这个指针被用来调用它所指向的函数时,这个被调用的函数就是回调函数。回调函数不是函数实现方调用,而是特定场景由另一方调用,用于对该事件的回应。return x+y;int x = 0;int y = 0;int i = 0;int j = 0;return 0;把函数Add作为函数Operation的参数,定义函数Add,定义函数Operation。在Operation中,传的是函数,所以形参用函数指针p变量接收Add的地址。

2023-11-26 14:44:25 382 1

原创 C语言二维数组传参/函数指针变量/函数指针数组/转移表

(*(p+0)+0)访问arr[0][0],*(p+0)表示第一行的地址解引用,解引用后就是二维数组的第一个元素arr[0],arr[0]既是二维数组的第一个元素,也是第一行数组的数组名,作为数组名,它又是首元素的地址。二维数组传参传的是首元素的地址,在这个例子中,首元素的地址----arr[0]----的地址,arr[0]是一个一维数组,它存入的是arr[0]中首元素----arr[0][0]---的地址。以上是函数指针数组的声明,p[3]结合表明这是个数组, int * () 表示是一个函数指针。

2023-11-25 20:58:24 1236

空空如也

空空如也

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

TA关注的人

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