数据结构
文章平均质量分 74
各类数据结构的介绍以及实现
编程之路,妙趣横生
仰望星空,脚踏实地
展开
-
实现AVL树
注意:我们下面实现的AVL树,实现的是kv模型,也就是存储key值和对应的value值, 模拟map//三叉链//方便进行AVL树进行调平//存储键值对int _bf;//平衡因子(balance factor), _kv(kv),_bf(0){}原创 2024-04-14 22:12:42 · 616 阅读 · 0 评论 -
实现红黑树
/颜色定义成枚举类型enum ColorRED,BLACK//节点结构定义//三叉链//键值对//颜色变量Color _col;原创 2024-05-12 13:04:00 · 907 阅读 · 0 评论 -
set与map使用
前置学习内容:前面介绍STL容器的文章已经讲解了STL通用的很多接口,因此本篇博客仍然重点展示较为新颖的的接口与用法。原创 2024-04-14 15:44:56 · 778 阅读 · 0 评论 -
搜索二叉树
也就是以要删除的节点为根节点,找左子树的最右节点(subRight)或者右子树的最左节点(subLeft),然后将要删除的节点值和subRight或subLeft的值进行交换,于是就转化成了删除只有1个孩子的节点的问题。这里重点体会参数root给引用的妙处,当最后的root是nullptr时,同时也是父节点的左指针或右指针的别名,所以root = new Node(key) 直接就把新开辟的节点和父节点链接起来了!由于删除后要保证仍然是搜索二叉树,因此我们使用。要删除的结点是叶子节点,没有左右孩子。原创 2024-04-10 10:59:06 · 1048 阅读 · 0 评论 -
C语言实现顺序表
顺序表是线性表的一种,它是用一段物理地址连续的空间来存储数据的一种线性结构,本质就是数组,顺序表有静态顺序表和动态顺序表,当空间不够时,动态顺序表可以实现增容,因此我们此处要实现的是动态顺序表的增删查改。结构体的成员变量是我们要关注的重点, a指向了我们动态内存开辟空间的起始地址,size记录了顺序表中当前有多少个元素,capacity表示顺序表的容量,当元素个数达到容量时,我们便需要扩容,动态顺序表的意义也就在于此。注意,size是当前顺序表元素个数,也恰好是要尾插元素的下标。头文件包含,函数声明。原创 2023-05-17 11:44:01 · 84 阅读 · 0 评论 -
排序素来美如玉,层进理解获芳心
1.希尔排序是对直接插入排序的优化2.gap取值对排序的影响:总结:gap>1都是预排序,gap==1时,数组已经接近有序,整体而言达到了优化的效果细节:①gap越大,大的数可以更快到后面,小的数可以更快到前面,但越不接近有序②gap越小,大数据和小数据都挪动越慢,但是越接近有序③gap == 1, 就是直接插入排序3.希尔排序的时间复杂度:这是一个尚未证明的问题,有人总结出了经验公式,我们且认为是在O(n^1.25) 到 O(1.6*n^1.25)原创 2023-07-21 12:30:59 · 153 阅读 · 2 评论 -
判断完全二叉树&&二叉树补充知识
根据完全二叉树最后一层节点数量范围判断完全二叉树是不可靠的, 因为完全二叉树最后一层从左到右要求是连续的~本篇博客就分享到这了,二叉树也就暂告一段落了,接下来要分享的是各大排序算法,欲知后事如何,且听下回解说~*推论:偶数个节点的完全二叉树度为1的节点有1个,奇数个节点的完全二叉树度为0的节点有0个。所以 n0+n1+n0-1 = 2n => 2n0+n1-1 =2n。如果是完全二叉树,那么当遍历遇到空节点之后,后面就没有非空节点了~而非完全二叉树,那么当遍历遇到空节点之后,后面还有非空节点。原创 2023-07-15 19:33:43 · 42 阅读 · 2 评论 -
树OJ题 (5)---二叉树的前序遍历&& (6)---二叉树遍历
1.先解释一下函数第二个参数的意思,因为二叉树是逻辑结构,存储结构是数组,leetcode题目设计的就是不知道数组的大小,因此函数外部会传入一个变量,函数形参用returnSize指针来接收该变量地址,目的就是为了能够改变外部的数组大小的变量~2. 数组空间是malloc出来的,但是我们并不知道要开多大空间,因此自己定义了求节点个数的函数 分析错误原因:解决方案:传i的地址&i,用*pi来接收i的地址,这样的话每一个栈帧虽然都有一个pi,但是这些pi都指向了i,直接(*pi)++即可原创 2023-07-14 19:59:56 · 36 阅读 · 0 评论 -
树OJ题 (3)---对称二叉树 && (4)---另一棵树的子树
思路:和上篇博客检查两棵树是否相同思路非常类似,判断一棵树是否是对称二叉树关键就是比较左子树的根和右子树的根是否相等,然后递归往后走。ps:为了用代码实现我们的解题思路,我们手动添加_isSymmetric()函数,在题目给定函数调用即可。思路:调用上篇博客实现过的判断两棵树是否相同的isSameTree()函数。2.左子树的根和右子树的根有一个不为空,返回false。3.判断root的左子树和subRoot树是否相同。4.判断root的右子树和subRoot树是否相同。原创 2023-07-14 18:30:00 · 47 阅读 · 1 评论 -
树OJ题 (1)---检查两棵树是否相同 && (2)---单值二叉树
依旧是递归的思想~,每棵树无非看成三部分,根,左子树,右子树,而比较整个树无非就是遍历所有节点,而遍历节点有前中后序,我们肯定选用前序,这样更简单一点。代码递归展开图这里就不再展示了,这种带返回值的递归的还是比较复杂的,递归展开图还是很能帮助我们理解整个的递归过程~~~假如说左子树和右子树都相等,但是根不相等,采用中序乃至后序便会进行了大量不必要的比较操作~2.比较左右子树,采用递归写法~,左右子树都相等才返回true, 因此用&&来解决。核心逻辑是 分别比较每个根节点和自己的左右孩子是否相等,然后递归~原创 2023-07-14 13:12:27 · 44 阅读 · 2 评论 -
经典树之二叉树
本文重点知识:二叉树的遍历,求二叉树节点个数,叶子节点个数,树的高度,第k层节点个数,查找值为x的节点并返回该节点地址普通链式二叉树的增删查改价值不大,只能单纯的存储数据~,因此普通的二叉树价值并不大,某些特殊的二叉树树有其特定的用途比如搜索二叉树就可以用来快速查找特定数据(最多只需要查找高度次,搜索二叉树就是每个节点的左子树比自己小,右子树比自己大~,当然搜索二叉树也是有其缺陷的,后面会引出AVL树,红黑树,B树等等~原创 2023-07-14 12:43:56 · 44 阅读 · 2 评论 -
独树一帜的完全二叉树---堆
--------------------------------------------------------------------------------------------------------------------------------小插曲:建堆时间复杂度。我们给了一个数组,把数组的元素依次插入堆中,使得数组元素在我们另外开辟的一块连续空间中成为堆,然后写了一个循环,每次pop堆顶数据后打印出来,由于堆顶的数据是堆中最小的(小堆),因此打印出来的数据就是升序的~原创 2023-07-13 21:18:04 · 121 阅读 · 0 评论 -
树的基本知识梳理
前面博客重点讲解了顺序表,链表,栈和队列等等线性数据结构,今天我们开始讲解难度更大的一个内容,就是另外一种数据结构,叫做树,和之前那些数据结构不同,之前的数据结构都是线性数据结构(除了头和尾,每一个元素都有一个前驱和一个后继),而今天讲的树则是非线性结构~原创 2023-07-12 14:02:16 · 65 阅读 · 0 评论 -
队列OJ题 --- 设计循环队列
选用数组来实现也是一样需要front 和rear的,而此时front 和 rear都是下标,同样的,为了解决 front == rear 是满还是空的问题,我们仍然认为rear+1 == front是满,所以要存放K个数据,我们需要 k+1个位置来存储~上图也是满了的情况,rear = 1, (rear+1) % (k+1) == 2 就等于front, 因为当 rear 比 k 小了,被除数肯定比除数小,%还是被除数,所以取模没有任何影响,因此取模这段代码就解决了判满问题~原创 2023-06-21 11:58:10 · 111 阅读 · 0 评论 -
栈与队列OJ题 --- 用栈实现队列
我们不妨这样,队列入数据都进第一个栈,队列出数据时如果第二个栈不为空,就直接从第二个栈出数据,如果第二个栈为空,就把第一个栈中的所有数据都捯到第二个栈后再出数据,总之出数据都从第二个栈出,我们分析一下这样是否可行~这就是我们前面说的,pushst栈中有数据时,先捯到popst,再获取popst栈顶(队头)元素,pushst没有数据时,直接获取popst栈顶返回即可。可以看到,入数据是1,2,3,4,5,6,出数据也是1,2,3,4,5,6,符合队列先进先出的特点,所以我们的想法是没有问题的。原创 2023-06-20 18:10:23 · 35 阅读 · 0 评论 -
栈与队列OJ题 --- 用队列实现栈
捯数据肯定是一个一个捯,从 非空队列 捯数据 到 空队列 其实就是 获取非空队列的队头数据 从队尾入到空队列,然后弹出非空队列的队头数据。之前博客已经详细介绍过了栈的实现,我们是直接动态内存开辟了一个数组来实现栈的先进后出的功能的,而这道题目是要求用两个队列来实现。我们直接假设第一个队列是非空的,第二个队列是空的,然后只需要if判断一下,如果假设正确,直接往下执行即可,如果假设错误,只需要更正一下即可~我们的初衷是要弹出栈顶元素,即非空队列的队尾数据,因此非空队列只剩下一个数据时,停止再捯~原创 2023-06-20 12:05:47 · 42 阅读 · 0 评论 -
栈 典型OJ题目--- 括号匹配问题
可以看到当字符串只有右括号的时候,直接进入else语句中的STTop代码,但是由于没有左括号入栈,因此栈为空,STTop中的assert断言就会报错。②s是题目中已经给定的函数形参,是一个字符串,字符串是以'\0'为结束标志的,因此while(*s)就作为while循环体继续执行的条件。这六个括号中的一个,你需要做的是 写一段代码来判断给定的字符串中的这些括号是否匹配,什么叫括号是否匹配?③If else 用来判断是左括号还是右括号,左括号就入栈,右括号就与出栈的左括号进行比较。下面是这道题的主体代码。原创 2023-06-19 19:40:26 · 61 阅读 · 0 评论 -
别样的数据结构---队列
队列的认识和栈一样,队列同样是一种线性表,特点是只允许在一端进行插入操作(队尾),在另一端进行删除操作(队头)符合 FIFO(first in first out),先进的先出(队列的核心特点)入队列:进行插入数据操作的一端为队尾出队列:进行删除数据操作的一端为队头队列可以用数组来实现,也可以用链表来实现,显然用链表来实现更优,因为数组插入数据或者删除数据可能需要大量挪动数据队列的实现。原创 2023-06-19 12:08:14 · 32 阅读 · 0 评论 -
别样的数据结构---栈
要注意的就是assert后面写的条件成立,就正常执行下面代码,不成立会报错,而我们希望是非空继续往下执行,STEmpty函数内部的判断逻辑就是当栈为空的时候,返回True,因此我们我们要加一个逻辑取反操作,表明非空时继续执行下面代码。②当然插入的时候注意插入的下标,由于我们初始化的时候选用的top初值为0,因此top就指向了靠近栈底元素的下一个位置,而要插入的元素的下标位置也正好是该位置,因此直接插入即可。测试代码当中中途弹出了一个栈顶元素2,之后有入栈3,4,最后打印出来的结果就是2,4,3,1。原创 2023-06-19 10:30:28 · 26 阅读 · 0 评论 -
顺序表与链表比较&&存储体系结构
若要访问的数据是以链表的形式存储的,由于链表的节点地址是随机的,这时加载一段,后面的节点大概率不会加载到缓存中,因此缓存不命中率较高,当然还会有另外一个问题---缓存污染,因为加载一段,当前节点后面的数据往往不是我想要的,但是会加载进高速缓存,若高速缓存满了,还可能会把我要访问的数据挤出去,因此造成缓存污染。若要访问的数据是以数组的形式存储的,由于数组的元素存储是连续的,这时加载一段,基本就会把数组的数据都加载到缓存中,因此缓存命中率比较高。寄存器(集成到cpu),高速缓存,内存,硬盘······原创 2023-06-17 23:33:40 · 20 阅读 · 0 评论 -
链表OJ题目详解(11)---复制带随机指针的链表
题目描述题目分析:这道题乍一看很复杂,其实不是很难,意思就是让你原封不动地复制一个链表,不过这个链表特殊一点,不仅每个节点有指向下一个节点的指针,还有一个指向了该链表中某个随机节点的指针解题思路①拷贝节点插入到新节点的后面②控制拷贝节点的random③拷贝节点接下来尾插组成拷贝链表,并且恢复原链表。原创 2023-06-17 22:09:29 · 24 阅读 · 0 评论 -
链表OJ题目详解(10)---求链表入环的第一个节点
题目描述这道题显然是上一道题的一个进阶,上一道题是判断链表是否有环,这道题是求环的入口点。原创 2023-06-17 20:49:17 · 32 阅读 · 0 评论 -
链表OJ题目详解(9)---判断链表是否带环
若L为奇数:L-2, L-4, L-6····· 5, 3, 1, -1,会跳过相距为0的时刻,此轮无法相遇,进入下一轮追击。思路:定义快慢指针,快指针每次走两步,满指针每次走一步,若快指针和慢指针相遇了,则带环,若快指针已经走到了空或者尾还没有和慢指针相遇,说明不带环。L , L-1, L-2, ············2, 1, 0 ,因此距离一定会经过减为0的过程,因此一定能相遇。若L为偶数:L-2, L-4, L-6····· 4, 2, 0,会经过为相距为0的时刻,也就是可以相遇。原创 2023-06-17 19:18:08 · 21 阅读 · 0 评论 -
链表OJ题目详解(8)---找两个相交链表的第一个公共节点
当然判断链表相交需要遍历链表,可以发现,这个过程在求交点的第一步---求链表长度同样需要 ,因此在求交点的第一步顺带实现。③两个指针再同时往后走,第一次相遇的节点即是两个相交链表的第一个公共节点。②定义两个头指针,分别指向两个链表的头,长度短的链表的头指针先走差距步。②定义两个指针,分别指向两个链表的头,长度短的链表的指针先走 差距步。分别遍历两个链表,判断尾节点是否相等,相等则为相交,否则不相交。①遍历两个链表,求出两个链表的长度,求出长度差距。①遍历两个链表,求出两个链表的长度,求出长度差距。原创 2023-06-17 10:58:04 · 26 阅读 · 0 评论 -
链表OJ题目详解(7)---链表的回文结构
这道题关键就是对前两步的实现,大家要对链表的逆置和找中间节点函数的实现熟练掌握哦~③一个指针从头开始走,另一个指针从中间节点开始走,依次比较对应节点是否相等。其中前两步我们之前的链表题目均已讲解,这里就不赘述了。②把链表的后半部分(中间节点到尾节点)进行逆置。本篇博客就分享到这啦,欢迎大家交流指正~原创 2023-06-16 22:01:09 · 30 阅读 · 0 评论 -
链表OJ题目详解(6)---链表的分割
当所有的节点都比指定的节点大的时候,这时候第一个链表为空,只有带哨兵位的头节点,我们返回lesstail->next 的时候,也就返回了第二个链表的头节点,因此避免了讨论。思路:创建两个新的链表,把小于x的节点尾插到第一个链表,把大于等于x的节点尾插到第二个链表,然后把第二个链表链接在第一个链表后面。所以这道题我们选择使用带哨兵位的头节点来解决这个问题,这样的话无论第一个链表为不为空,我们都返回的是第一个链表的带哨兵位的头节点。若第一个链表为空呢?定义两个链表中的带哨兵位的头节点,尾节点(方便尾插)原创 2023-06-16 21:21:33 · 35 阅读 · 0 评论 -
链表OJ题目详解(5)---合并两个有序链表
这类问题我们已经见到过很多次了,就是空指针解引用导致报错,看下题目给的测试用例就会发现,当其中一个链表为空的时候,while循环压根没有进去,直接来到了最后把非空链表拼接到新链表的代码处。思路:创建一个新的链表,依次比较两个有序链表中的元素,把小的节点尾插到新链表中,若有一个链表已经为空,说明合并完成,返回新链表的头结点。到此,第一个链表已经为空,接下来的工作就是把不为空的那个链表链接到新链表的后面即可。第二步:依次比较两个链表的节点,取小的尾插(若一样大,则随便取一个)原创 2023-06-15 20:44:17 · 47 阅读 · 0 评论 -
链表OJ题目详解(4)---求链表倒数第k个节点
上篇博客已经介绍了如何求解链表的中间节点,而求链表的倒数第k个节点无疑是前一个问题的变形,因此我们仍然采用双指针来求解,不过这次可不是两个指针走的速度不一样了,而是快指针先走一段,然后快指针和慢指针再同时走。一般地,要求倒数第k个节点,快指针先走k步,然后快慢指针一起走,当快指针走到尾时(快指针走了n-k步,慢指针也就走了n-k步),慢指针就走到了目标节点。可以看到,快指针先走两步,然后快指针和慢指针一起走,当快指针为空时,慢指针就走到了倒数第2个位置。举个栗子,假如我们要求的是下面链表的倒数第2的节点。原创 2023-06-07 16:02:26 · 43 阅读 · 0 评论 -
链表OJ题目详解(3)---求链表的中间节点
快指针和慢指针开始都指向头节点,快指针每次走两步,慢指针每次走一步,当快指针走到最后一个节点或者空节点的时候(和节点个数为奇数还是偶数有关系),慢指针指向的节点就是中间节点。因为不知道链表有奇数个节点还是偶数个节点,因此while循环条件采取&&的形式,有一个不满足,说明该跳出循环了。思路一:两次遍历链表,第一次求出节点个数count,第二次遍历count/2次,找到中间节点。求链表的中间节点就分享到这了,文章仍有许多不足,欢迎大家交流指正~~~奇数个节点:fast走到尾,slow为中间节点。原创 2023-06-07 15:39:04 · 37 阅读 · 0 评论 -
链表OJ题目详解(2)--- 反转链表
题目描述。原创 2023-06-07 15:20:50 · 25 阅读 · 0 评论 -
链表OJ题目详解(1)--- 移除链表元素
1.移除链表元素。原创 2023-06-01 15:24:45 · 50 阅读 · 1 评论 -
带头双向循环链表
需要先给大家说明的是,在讲解单链表函数实现的时候,头插头删等等这些需要改变头节点的指针的函数,我们的形参都使用的是二级结构体指针,但是我们带头双向循环链表的所有函数形参使用一级指针即可,因为带哨兵位的头节点中存储了头节点地址,因此想要改变头节点,只需要改变哨兵位头节点这个结构体的成员变量(next)即可,不需要改变外部的plist,因此一级指针就行。思路:和单链表一样,需要遍历整个链表,但关键点就是循环结束的条件,单链表是尾节点的next指向空,而带头双向循环链表特点是尾节点的next是phead。原创 2023-05-31 16:53:12 · 188 阅读 · 1 评论 -
链表核心之单链表
头插,尾删等也是类似的道理。不同于数组,单链表并不是一块连续的存储空间,它是由一个个节点构成的,而每个节点的类型是结构体,其中包含了两个成员变量,第一个被称为数据域,就是用来存放数据的,第二部分被称为指针域,存放的是一个指针变量,指针变量存放的是下一个节点的地址。总结:涉及到对单链表的改变的时候经常需要考虑三种情况,链表为空,链表只有一个节点,链表有多个节点,有时这三种情况可以用同一份代码一样,但经常需要单独考虑链表为空或者一个节点的情况,总之要养成这样思考的习惯,代码写出bug的可能才会降低。原创 2023-05-29 11:27:10 · 39 阅读 · 1 评论