自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 【C++】运算符重载

像Stack这样的类,虽然也都是内置类型,但是_a指向了资源,编译器自动生成的赋值运算符重载完成的值拷贝/浅拷贝不符合我们的需求,所以需要我们自己实现深拷贝(对指向的资源也进行拷贝)。例如,对于加法运算符+,其重载函数的名称为。上面代码定义一个类A,包含一个公有成员函数add,创建对象obj,接着定义一个指向A类成员函数的指针pf,通过函数指针和.* 调用成员函数完成相加计算。来管理流的绑定关系,默认情况下,cin绑定到cout,输入时自动刷新cout,这可能影响性能,因为每次输入都要刷新输出缓冲区。

2025-04-07 20:13:46 832

原创 【C++】类和对象(1)

类中的变量称为类的属性或成员变量;类中的函数称为类的方法或者成员函数。为了区分成员变量,一般习惯上成员变量会加一个特殊标识,如成员变量前面或者后面加_或者m 开头C++中struct也可以定义类,C++兼容C中struct的用法,同时struct升级成了类定义在类里面的成员函数默认为inline。

2025-03-07 18:29:14 923

原创 C++基础(2)

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间, 它和它引用的变量共用同一块内存空间。类型& 引用别名 = 引用对象不需要指针就可以交换两个变量的值int main()int a = 2;//引用: b和c是a的别名int& b = a;int& c = a;//为别名b取别名,d相当于还是a的别名int& d = b;++d;//取地址return 0;

2025-02-04 22:50:21 786

原创 C++基础(1)

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量,所以下面的rand变量就不存在冲突了。C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找一个变量/函数/ 类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。

2025-01-28 22:00:24 1065

原创 排序算法(3)——归并排序、计数排序

O(n*logn)O(n)稳定性:稳定缺点:缺点在于需要O(N)的空间复杂度,归并排序应用更多的是解决在磁盘中的外排序问题。适用性:归并排序适用于各种数据规模的排序,而且对于大规模数据的排序效果较好。它的时间复杂度稳定在O(nlogn),不会因为数据规模的增大而导致时间复杂度的增加。由于其空间复杂度较高,通常在内排序中不会使用归并排序,而是选择快速排序。在外排序中,对于无法一次性加载到内存的大规模数据进行排序,归并排序则是一个很好的选择。排序方法时间复杂度(平均)时间复杂度(最好)

2024-12-16 19:36:52 767

原创 排序算法(2)——快速排序

快速排序是英国计算机科学家托尼・霍尔(C. A. R. Hoare)在 1960 年年提出的一种二叉树结构的交换排序方法。:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

2024-12-12 20:20:38 926 1

原创 排序算法(1)

1.希尔排序是对直接插入排序的优化。2.当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经基本接近有序,只需最后插入排序进行少量的比较和交换操作,这样就会很快。这样整体而言,可以达到优化的效果。3.希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定,有学者经过大量计算,得出结果大约在O(n^1.25) 到 O(1.6*n²)范围内,我们暂且按照这个来算。不稳定。

2024-11-29 19:27:09 981

原创 【数据结构】二叉树(2)

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。是按照一定的次序访问二叉树中的所有节点,并且每个节点仅被访问一次的过程。如果二叉树不为空,且左右子树不为空,返回左子树中叶子节点个数加上右子树中叶子节点个数。1、首先将二叉树的根节点push到队列中,判断队列不为NULL,就输出队头的元素。由于要访问每个节点的左右孩子,所以队列的元素类型为节点的指针。如果二叉树为空,二叉树的深度为0。

2024-11-23 16:02:58 1428

原创 【数据结构】二叉树(1)

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。一棵二叉树是结点的一个有限集合,该集合:或者为空由一个根结点加上两棵别称为左子树和右子树的二叉树组成二叉树不存在度大于2的结点二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

2024-11-02 21:31:39 1199 2

原创 【数据结构】堆的实现

基本思想:向堆尾插入新元素时,维护堆的性质,需要对该元素向上调整,从新插入的节点开始,与其父节点比较,若新节点的值比其父节点的值小,则交换它们,并将新节点的父节点当作目标节点继续向上调整,若目标结点的值比其父结点的值大,就停止向上调整,此时该树已成堆。(以小堆调整为例)若想将此二叉树调整为小堆,左右子树都必须是一个小堆,才能调整。若想将此二叉树调整为大堆,左右子树都必须是一个大堆,才能调整。

2024-11-02 21:11:26 1102

原创 【数据结构】栈和队列经典题目

' ( '入栈,++s, 遇到 ')' , 与栈顶元素' ( ' 相匹配,把' ( '弹出栈,++s,遇到 ' { '入栈,++s, 遇到 ' [ '入栈 ,++s,遇到 ' } ' , 与栈顶元素 ' [ ' 进行匹配,不配对,返回false,字符串无效。将一个栈当作输入栈用来入数据,一个栈当作输出栈用来出数据,由于栈具有后进先出的特性,若输出栈为空,则将输入栈中的数据全部导入到输出栈,这样输出栈从栈顶到栈底的顺序就是队列的输出顺序。请你仅使用两个栈实现先入先出队列。例如:( ) { [ } ]

2024-10-20 16:33:59 935 1

原创 【数据结构】栈和队列

静态栈int _top;// 栈顶}Stack;上面是定长的静态栈的结构,实际中一般不实用,所以我们主要实现下面的支持动态增长的栈。动态栈//定义数据类型//指向动态开辟的数组int top;//确定栈顶位置//栈的容量}ST;}QNode;包括队头指针、队尾指针、队列长度。int size;}Queue;

2024-10-20 16:31:12 1069

原创 【数据结构】7道经典链表面试题

题目描述:给你一个链表的头节点head,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪next指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数pos来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos不作为参数进行传递。仅仅是为了标识链表的实际情况。如果链表中存在环,则返回true。 否则,返回false。题目描述:给定一个链表的头节点 head,返回链表开始入环的第一个节点。如果链表无环,则返回null

2024-10-10 19:45:26 1274

原创 【数据结构】算法的空间复杂度

空间复杂度也是一个数学表达式,是对一个算法在运行过程中临时占用的存储空间大小的量度 。(临时占用的存储空间为函数体内分配的空间,不包括形参占用的空间)一般也作为问题规模n的函数。空间复杂度不是程序占用了多少字节的空间,因为这没太大意义,所以空间复杂度算的是变量的个数。 空间复杂度计算规则基本跟时间复杂度类似,也使用大O渐进表示法。注意:函数运行时所需要的栈空间(存储参数、局部变量、一些寄存器信息等)在编译期间已经确定好了,因此空间复杂度主要通过函数在运行时候显式申请的额外空间来确定。

2024-09-29 15:54:24 416

原创 【数据结构】算法的时间复杂度

算法在编写成可执行程序后,运行时需要耗费时间资源和空间(内存)资源 。因此衡量一个算法的好坏,一般是从时间和空间两个维度来衡量的,即时间复杂度和空间复杂度。一个算法所花费的时间与其中语句的执行次数成正比例,算法中的基本操作的执行次数,为算法的时间复杂度。推导大O阶方法:1、用常数1取代运行时间中的所有加法常数。2、在修改后的运行次数函数中,只保留最高阶项。3、如果最高阶项存在且不是1,则去除与这个项目相乘的常数。得到的结果就是大O阶。

2024-09-26 19:13:18 1224

原创 【数据结构】双向链表专题

带头链表里的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,“哨兵位”存在的意义: 遍历循环链表避免死循环。以参数的形式初始化链表:开始的时候创建一个空链表,LTNode* plist = NULL;我们要对空链表进行初始化,保证让链表只有一个头结点(哨兵位),为我们后续插入操作做准备。由于要改变plist的指向,所以传二级指针。以返回值的形式初始化链表:初始化可以不传递二级指针,以返回值的形式返回哨兵位,调用完LTInit函数后,plist指针接收其返回值:

2024-09-09 19:54:56 459

原创 【数据结构】单链表的应用

给你一个链表的头节点head和一个整数val,请你删除链表中所有满足的节点,并返回。思路: 创建新链表,找值不为val的节点,尾插到新链表中。给你单链表的头节点head,请你反转链表,并返回反转后的链表。给你单链表的头结点head,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

2024-09-07 21:36:58 544

原创 通讯录的实现

通讯录其底层结构就是顺序表,这里大量使用了顺序表相关知识和功能,实现了顺序表的应用,可参照【动态顺序表的实现】这篇文章一起学习。我们将项目分成三个模块来书写,使用VS2022编译器编写通讯录效果:

2024-09-03 19:13:51 259

原创 【数据结构】单链表专题

图中指针变量 plist保存的是第一个节点的地址,我们称plist此时“指向”第一个节点,如果我们希望plist“指向”第二个节点时,只需要修改plist保存的内容为0x0012FFA0。链表中每个节点都是独立申请的(即需要插入数据时才去申请一块节点的空间),通过指针变量保存下一个节点位置才能从当前节点找到下一个节点。且每节车厢都有车门,假设每节车厢的车门都是锁上的状态,需要不同的钥匙才能解锁,每次只能携带一把钥匙的情况下。与顺序表不同的是,链表里的每节"车厢"都是独立申请下来的空间,我们称之为“链表中每个

2024-09-03 19:09:06 1177

原创 C语言函数详解

自定义函数给程序员写代码提供了更多的创造性。比如:我们要写一个函数判断一年是否是闰年。//函数定义return 1;//函数调用printf("闰年\n");elseprintf("非闰年\n");return 0;那如果我们将函数的定义放在函数的调用后边int main()int y = 0;//函数调用printf("闰年\n");elseprintf("非闰年\n");return 0;实际上,如果只是定义了 Add 函数,而不去调用的话, Add 函数的参数 x 和 y 只是形式上存在的,不会向内存

2024-08-25 16:33:16 1003

原创 【数据结构】动态顺序表的实现

顺序存储结构:把数据元素放到地址连续的内存单元里面,其数据间的逻辑关系和物理关系是一致的,比如我们常用的数组就是顺序存储结构。链式存储结构:是把数据元素存放在任意的存储单元里面,这组存储单元可以是连续的,也可以是不连续的。此时,数据间的物理关系不能反映其逻辑关系。所以每一数据元素均使用一个结点来存储,不仅需要存储数据元素,而且还要存储数据元素之间的逻辑关系(将结点分为两部分,一部分存储数据元素本身,称为数据域;一部分存储下一个结点的地址,称为指针域。)

2024-08-23 16:47:17 1106

原创 预处理详解

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副用就是表达式求值的时候出现的永久性效果。宏参数和#define 定义中可以出现其他#define定义的符号。但是对于宏,不能出现递归。当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。当我们把a替换到宏的体内时,就出现了#

2024-08-03 11:01:00 1282 2

原创 编译和链接

预处理阶段主要处理那些源文件中#开始的预编译指令。比如:#include, #define,处理的规则如下:将所有的 #define 删除,并展开所有的宏定义。处理所有的条件编译指令,如: #if、#ifdef、#elif、#else、#endif 。处理#include 预编译指令,将包含的头文件的内容插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件。删除所有的注释。添加行号和文件名标识,方便后续编译器生成调试信息等。或保留所有的#pragma的编译器

2024-07-31 00:09:55 760

原创 C语言之文件操作(2)

从流中读取字符,并将它们作为C字符串存储到str中,直到读取了(num-1)个字符,或者到达了换行符或文件结尾,无论哪种情况先发生。换行符使fgets停止读取,但它被函数认为是有效字符,并包含在复制到str的字符串中。在复制到str的字符后会自动追加一个终止空字符。返回值:如果读取成功,该函数将返回str。如果在试图读取字符时遇到文件结尾或者遇到错误导致读取失败就会返回NULL。从内存向磁盘输出的数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。

2024-07-28 22:35:19 1348

原创 文件读取结束的判定

文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets ) 例如:fgetc 判断是否为 EOF(读取正常,返回读取到字符的ASCII码值;读取过程中发生错误或遇到文件末尾,返回EOF) 。fgets 判断返回值是否为 NULL (读取正常,返回存储字符串的字符数组的地址;读取过程中发生错误或遇到文件末尾,返回NULL)。feof 的作用:在文件读取已经结束的基础上,判断文件读取结束的原因是否是遇到文件末尾而结束(检测相应的标记)。

2024-07-28 20:02:04 446

原创 C语言之文件操作(1)

磁盘(硬盘)上的文件是文件。程序文件数据文件。(从文件功能的角度来分类的)2.1程序文件。

2024-07-27 00:00:15 979

原创 C语言柔性数组详解

2.柔性数组的特点结构体中的柔性数组成员前面必须至少有一个其他成员。sizeof 返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用malloc 函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的预期大小。

2024-07-21 23:52:09 815

原创 动态内存经典笔试题分析

出了函数,局部变量p已经销毁,函数返回后,str依然为空指针,把hello world拷贝放到空指针指向的空间去,拷贝必然存在对空指针的解引用操作,程序就会崩溃。这部分代码要表达的意思其实是想把malloc开辟的100个字节的空间的地址传给str,接着拷贝内容。情况1:当跳出函数后,恰好p指向的空间没有被操作系统使用,就可以打印出来hello world。情况2:当跳出函数后,p指向的空间已经被覆盖了,就不能完成任务。请问运行Test 函数会有什么样的结果?请问运行Test 函数会有什么样的结果?

2024-07-21 15:57:10 373

原创 动态内存管理

我们已掌握的内存开辟方式:但是上述的开辟空间的方式有两个特点:这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。函数原型如下:malloc的申请和使用 到内存窗口观察开辟的空间是否能使用: C语言提供了另外一个函数free,是专门用来做动态内存的释放和回收的,函数原型如下:free的使用 4.callocC语言还提供了一个函数叫 calloc ,也是用来动态内存分配的。函数原型如下:那 realloc 函数就可以做到对动态开辟内存大小的调整,函数原型如下:

2024-07-21 00:38:23 868

原创 联合和枚举

目录1.联合体1.1联合体类型的声明1.2联合体的特点1.3相同成员的结构体和联合体对比1.4联合体大小的计算 1.5联合体的练习 2.枚举类型2.1枚举类型的声明2.2枚举类型的优点2.3枚举类型的使用运行结果: 运行结果:使用联合体是可以节省空间的。1.5联合体的练习 2.枚举类型2.1枚举类型的声明 运行结果:2.2枚举类型的优点1.增加代码的可读性和可维护性 以上代码可改写为:2.和#def

2024-07-19 21:57:51 891

原创 C语言内存函数

memcpy函数从source的位置开始向后复制num个字节的数据到destination指向的内存位置。虽然使用memcpy函数能完成任务,但是也需谨慎使用,memcpy不负责空间重叠问题。如果source和destination空间有任何的重叠,复制的结果都是未定义的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。这个函数在遇到 '\0' 的时候并不会停下来。以下程序会是我们期待的1 1 1 1 1吗?memmove和memcpy的。为单位设置成想要的内容。如果换成设置整型呢?

2024-07-17 20:02:48 765

原创 字符函数和字符串函数(2)

在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用一个全面的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,,每一个错误码都有它对应的错误信息,而一个错误码是数字,很难理解是什么意思,strerror函数就可以将错误码对应的错误信息字符串的地址返回,利用字符串的地址就可以打印错误信息。当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码存放在errno中。

2024-06-29 15:51:53 1073

原创 字符函数和字符串函数(1)

C语言中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。这些函数的使用都需要包含一个头文件是islower 是能够判断参数部分的 c 是否是小写字母的。通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回 0。运行结果:练习写一个代码,将字符串中的小写字母转大写,其他字符不变。

2024-06-28 15:58:30 1047

原创 指针运算笔试题解析

运行结果: 输出结果: 运行结果:运行结果: 运行结果:运行结果: 输出结果:

2024-06-26 19:45:19 217

原创 C语言sizeof与strlen详解

sizeof 计算的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据。strlen 是C语言库函数,功能是求字符串长度。统计的是从 strlen 函数的参数 str 中这个地址开始向后,。strlen 函数会一直向后找 \0 字符,直到找到为止,所以可能存在越界查找。1. sizeof是操作符。2. sizeof计算操作数所占内存的大小,单位是字节。3. 不关注内存中存放什么数据。

2024-06-25 21:05:21 571

原创 qsort排序

我们发现函数参数部分整型数组接收,所以这个函数只能排序整型数据。而qsort是用来排序的库函数,,它可以对指定数组(包括字符串,二维数组,结构体等)进行排序,底层使用的是快速排序的方式。在使用冒泡排序的情况下,我们想要改造这个函数,让它能够排序任意类型的数据,我们发现两个整型元素的比较可以直接使用 '>',但是两个字符串,两个结构体的比较不能直接使用 '>'。我们可以封装成函数,然后把传递给排序函数。

2024-06-22 20:16:46 797

原创 计算器的实现

函数指针数组的用途:转移表。

2024-06-19 11:41:24 220

原创 C语言之指针(4)

需要注意的是常量字符串的内容不能被修改,所以我们用const来修饰,警示自己这个字符串不能被修改。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际上会指向同一块内存。解释:p先和 * 结合,说明p是一个指针变量,然后指针指向的是一个大小为10个整型的数组。我们知道,指针数组是一种数组,数组中存放的是地址(指针)。数组指针变量是指针变量?存放的是整型变量的地址,能够指向整型数据的指针。注意:[] 的优先级要高于 * 的,所以必须加上()来保证 p 先和 * 结合。

2024-06-17 18:44:24 115

原创 C语言之指针(3)

pp 操作是对pp进行解引用,pp里面存的是p的地址,然后解引用找到p,p中存的是a的地址,所以*pp等价于&a,**pp等价于对&a进行解引用,最终找到a。,数组元素的访问在编译器处理的时候,也是转换成首元素的地址+偏移量求出元素的地址,然后解引用来访问的。,这里的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)。,sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小, 单位是字节。除此之外,任何地方使用数组名,数组名都表示首元素的地址。

2024-06-16 11:41:58 702

原创 C语言——冒泡排序

冒泡排序的核心思想就是:两两相邻的元素进行比较。

2024-06-15 21:10:17 140

空空如也

空空如也

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

TA关注的人

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