![](https://img-blog.csdnimg.cn/51051baab1054cc2a7d2027740442910.jpeg?x-oss-process=image/resize,m_fixed,h_224,w_224)
数据结构(C/C++)
文章平均质量分 89
由浅入深,分析数据结构的组成方式。前期以c语言数据结构为主,后面以c++为主,会持续不断地更新。
桜キャンドル淵
凑个整,就1024吧
展开
-
C++【跳表】
skiplist本质上也是一种查找结构,用于解决算法中的查找问题,跟平衡搜索树和哈希表的价值是一样的,可以作为key或者key/value的查找模型。skiplist是由William Pugh发明的,最早出现于他在1990年发表的论文《Skip Lists: A对细节感兴趣的同学可以下载论文原文来阅读。skiplist,顾名思义,首先它是一个list。实际上,它是在有序链表的基础上发展起来的。如果是一个有序的链表,查找数据的时间复杂度是O(N)。假如我们每相邻两个节点升高一层,增加一个指针。原创 2022-12-29 18:00:06 · 1201 阅读 · 0 评论 -
C++【B树】【B+树】
相比于我们别的数据结构,我们的B树更加适合进行外查找B树也可以进行内查找,但是有一点浪费空间。原创 2022-12-28 15:32:56 · 931 阅读 · 0 评论 -
C++【LRU】
因为我们的磁盘->内存->高速缓存->cpu之间的速度不同,所以我们设置了缓存缓存空间满了之后,更新数据,我要进入,谁出去呢?LRU是Least Recently Used的缩写,意思是最近最少使用,它是一种Cache替换算法。,将最近最少被使用的算法替换出去。(包括读和写)原创 2022-12-23 09:33:38 · 720 阅读 · 0 评论 -
C++【图】
顶点集合V= {x|x属于某个数据对象集}是有穷非空集合;E = {(x,y)|x,y属于V}或者E = {|x,y属于V && Path(x, y)}是顶点间关系的有穷集合,也叫做边的集合。(x, y)表示x到y的一条双向通路,即(x, y)是无方向的;Path(x, y)表示从x到y的一条单向通路,即Path(x, y)是有方向的。顶点和边:图中结点称为顶点,第i个顶点记作vi。原创 2022-12-22 23:48:53 · 587 阅读 · 0 评论 -
C++【并查集】
比如:某公司今年校招全国总共招生10人,西安招4人,成都招3人,武汉招3人,10个人来自不同的学校,起先互不相识,每个学生都是一个独立的小团体,现给这些学生进行编号:{0, 1, 2, 3,4, 5, 6, 7, 8, 9};这时,我们就需要将1和8合并起来,但是8并不是父节点,所以我们查找8的父节点,我们发现是0号节点,所以我们将将1 中存储大的内容变成0,也就是其父节点是0号节点,然后我们的0号节点减去原本1号节点UN出的-3,也就是变成了-7。有 n 个城市,其中一些彼此相连,另一些没有相连。原创 2022-12-17 22:14:45 · 1577 阅读 · 0 评论 -
C++【IO流】
想要让自定义类型能够进行转换,我们需要将其进行强制类型转换,但是一般用于类型转换的()被占用了,所以我们就用operator bool,将我们的类型转化成一个bool值,并将这个bool值进行返回。2.可以使用这部分的内容实现“行”读取的行为,对于计算机而言是没有“行”这个概念,有了这部分,就可以定义“行”的概念,然后解析缓冲区的内容,返回一个“行”。一般是整型指针,比较运算符表达式道德结果可以做逻辑条件判断,0就是假,非0就是真,自定义类型一般是不能做while的条件类型判断的,这里存在隐式类型转换。原创 2022-11-28 21:49:57 · 1126 阅读 · 0 评论 -
C++【类型转换】
1.兼容C隐式类型转换和强制类型转换2.期望不要用了,期望你通用规范的C++显式的强制类型转换3.static_cast对应隐式类型转换reinterpret_cast、const_cast对应的是强制类型转换。原创 2022-11-28 20:21:59 · 468 阅读 · 0 评论 -
C++【特殊类的设计】【单例设计模式】
比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。(比方说A先创建,然后B在创建,这样是没有办法做到的,因为它们都是静态成员,我们是没有办法确定的。,那么我们的上面代码中的hp1,hp2都会报错,而我们的ptr因为没有调用析构函数,所以可以正常编译通过。3、有些特殊的场景需要释放,比如单例对象析构时,要进行一些持久化(往文件,数据库写)操作。原创 2022-11-26 12:58:14 · 581 阅读 · 0 评论 -
C++【智能指针】
if(b == 0) throw invalid_argument("除0错误");// 1、如果p1这里new 抛异常会如何?// 2、如果p2这里new 抛异常会如何?// 3、如果div调用这里又会抛异常会如何?// 如果出了异常,会直接跳转到捕获的地方去了。//如果是p1 抛异常需要释放p2和div //如果是p2 抛异常需要释放p1和div //如果是div抛异常,需要释放p1和p2 delete p1;}原创 2022-11-23 21:52:42 · 616 阅读 · 0 评论 -
C++【异常】
这里无论是Func中的还是main函数中的捕获异常都是捕获一个int类型的异常值,但是我们抛出异常是抛出一个string,那么都匹配补上的话,我们的程序就会报错。有多个捕获的话,走离捕获更近的那一个,也就是我们这里的func函数中的捕获,不走main函数中的那一个,但是这里要求类型必须要是匹配的!异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的直接或间接的调用者处理这个错误。(抛出一个对象出来)2、捕获的时候不同的类型需要有不同的捕获方式,然后进行不同的处理。原创 2022-11-19 12:34:15 · 87 阅读 · 0 评论 -
C++【STL】【STL容器的使用与实现】
STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。istream/ostream……->标准库STL是标准库std的子集。原创 2022-11-18 20:30:32 · 737 阅读 · 0 评论 -
C++【C++11】
如果我们这里使用auto的话,我们上面代码中的迭代器的类型等等,我们都不用自己手写,就非常方便,但是我们如果使用了auto进行自动类型推断,我们。< forward_list >是一个单链表,我们的< list >是双向链表,在使用的时候其实< forward_list >插入的是在我们当。typename可以推导对象的类型,但是我们不能通过这个推导出来的类型来定义我们的对象,只是单纯地拿到这个类型的字符串。(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,原创 2022-11-16 22:47:18 · 381 阅读 · 0 评论 -
C++【哈希】
假如从底层实现上去取名字的话,map和set的实现可以分为hash实现和tree的实现最大的区别是unordered系列提供的是单向的迭代器。原创 2022-11-14 17:05:06 · 1303 阅读 · 0 评论 -
C++【红黑树】
AVLTree:要求左右高度差不超过1红黑树:AVLTree过分严格,可能会导致过分的旋转,那能不能不要那么严格呢?需要达到的目的,最长路径不超过最短路径的二倍。也就是说,我们的AVLTree是严格平衡,我们的红黑树是不严格平衡,而是近似平衡结果:相对而言,插入同样的数据,AVL树的旋转更多,红黑树的旋转次数更少假设N是100w,AVL树为logN的高度,也就是大概20左右但是我们的红黑树的话,最短的高度大概是logN也就是20左右,最深的应该为2*logN,为40次左右。原创 2022-11-05 16:34:52 · 932 阅读 · 0 评论 -
C++【AVL树】
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。一棵AVL树或者是空树,或者是具有以下性质的二叉搜索树:它的左右子树都是AVL树。原创 2022-10-29 19:15:19 · 326 阅读 · 0 评论 -
C++【STL】【map和set】
map和set是关联性容器在我们的STL中分为两类序列式容器:vector list deque关联式容器:map set。原创 2022-10-29 00:23:42 · 1296 阅读 · 0 评论 -
【C++】【LeetCode】【二叉树的前序、中序、后序遍历】【递归+非递归】
默认情况下,一个线程的栈空间大小为8MB,当递归的深度太深,我们的程序就容易崩溃如果递归的深度太深,栈空间不大,那么程序容易崩溃改成非递归1.改成循环(比方说斐波那契)2.通过栈改成循环为什么递归会空间溢出,非递归不会空间溢出?1.如果是循环的话,形成迭代,消耗的空间很可能是0(1)2.如果使用的是通过栈来改成循环的话,我们栈的开辟的空间在内存的堆区(内存中栈的空间不大,但是堆的空间很大,几乎不存在空间溢出的问题)所以这里我们将递归的遍历改成非递归。原创 2022-10-28 22:41:12 · 738 阅读 · 0 评论 -
C++【算法】【KMP算法】
对于传统的暴力匹配算法,我们是在匹配主字符串和子串的时候,一旦匹配不上,子串就回退到最初位置,主串也回退到与子串开始比较的位置。这样的算法的时间复杂度会到达O(M*N),也就是主串的长度乘以子串的长度这里我们可以尝试让我们的主串中的指针不再回退,同时我们子串的指针在匹配的时候也回退到指定的位置,而不是开头的位置。这里我们就需要用到我们的KMP算法KMP算法的时间复杂度O(m+n)原创 2022-10-26 22:55:02 · 2183 阅读 · 0 评论 -
C++【搜索二叉树】
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:若它的左子树不为空,则左子树上所有节点的值都小于根节点的值若它的右子树不为空,则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉搜索树(每一棵子树都满足上面的特征)(这样我们的搜索二叉树就非常利于我们的搜索)比方说我们查找8,8比6大,找右子树,8比9小,找9的左子树,7比8小,找7的右子树,找到了。最多的查找次数是树的高度!这样就不是暴力查找了,而是利用了二叉树的特性。原创 2022-10-23 11:47:16 · 1290 阅读 · 1 评论 -
C++【多态】
多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。比方说去买票:普通成年人买普通的票,学生买半价的学生票,军人不需要排队买票这里的普通人,学生和军人就是三个不同类型的对象。①正常卖票 ②半价买票 ③优先买票还有比方说红包新用户要鼓励使用 所以红包多给一点 rand()%99老用户并且经常使用 rand()%2。原创 2022-10-15 18:00:47 · 563 阅读 · 10 评论 -
C++【算法】【贪心算法】
贪心选择是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素。原创 2022-10-02 16:28:12 · 7629 阅读 · 0 评论 -
C++【算法】【动态规划问题】
动态规划是在将大问题转化为小问题的分治过程中,保存对这些小问题已经处理好的结果,并提供给后面处理更大的问题来使用这些结果1.把原来的问题分解成了几个相似的子问题2.所有的子问题都只需要解决一次3.存储子问题的解动态规划的本质,是对问题状态的定义和状态转移方程的定义(状态以及状态之间的递推关系)1.状态定义2.状态间的转移方程定义(从题目中找线索)3.状态的初始化4.返回结果状态定义的要求:定义的状态一定要形成递推关系难点:状态比较难以定义,转移方程不好找。原创 2022-10-01 21:14:39 · 1078 阅读 · 0 评论 -
C++【继承】
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用比方说学校人员管理系统学生有name,tel,id,address属性,和宿舍号,专业和班级属性老师有name,tel,id,address属性,和职称,院系属性。原创 2022-09-30 23:31:13 · 568 阅读 · 6 评论 -
C++【STL】【模板进阶】
而我们的c语言中的数组仅仅是将数组的首地址加上N,再解引用来得到我们的结果。非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。除了array是支持使用迭代器去访问的,其两者的区别还在于其迭代器的的越界检查。比方说我们设置T==Date*类型,进行单独比较,C++是不支持的!如果我们将上面的特化的代码处理掉,我们观察到我们的地址是按照从大到小排的。模板参数和函数参数是非常像的,我们还可以给我们的模板参数一个缺省值。这是有特化的结果,也就是按照从大到小排。原创 2022-09-28 22:37:13 · 444 阅读 · 0 评论 -
C++【STL】【反向迭代器】
12345如果是正向迭代器就是从1->2->3->4->5,也就是正向迭代器的++是向右边走但是我们的反向迭代器的++是向左边走,也就是5->4->3->2->1{//正向迭代器{++it;}//反向迭代器{++rit;}}原创 2022-09-28 21:32:39 · 1388 阅读 · 1 评论 -
C++【STL】【queue的使用和模拟实现】【priority_queue的使用和模拟实现】
1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:empty:检测队列是否为空size:返回队列中有效元素的个数front:返回队头元素的引用。原创 2022-09-24 21:44:49 · 550 阅读 · 0 评论 -
C++【STL】【stack类的使用】【stack类的模拟实现】
1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:empty:判空操作back:获取尾部元素操作。原创 2022-09-24 21:12:52 · 1287 阅读 · 0 评论 -
C++【STL】【list类的使用】【list类的模拟实现】
1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。原创 2022-09-17 22:57:23 · 495 阅读 · 1 评论 -
C++【STL】【vector类的模拟实现】【迭代器失效问题】
迭代器失效就是当我们尾插数据的时候,如果发生了扩容,原来的地址空间可能就被转换到了一块更大的空间,所以我们迭代器的指针就失效了。我们同样可以仿照erase中的写法,将我们insert函数中当前的扩容之后的对应位置的迭代器返回,然后及时同步迭代器,从而解决这个问题。迭代器失效就是当我们尾插数据的时候,如果发生了扩容,原来的地址空间可能就被转换到了一块更大的空间,所以我们迭代器的指针就失效了。由于编译器在将v传过来的时候会拷贝构造一个v,将这个v与我们当前的容器中的内容交换一下,我们的当前容器就完成拷贝了。..原创 2022-08-15 12:16:25 · 569 阅读 · 0 评论 -
C++【STL】【vector类的使用】
构造函数声明接口说明vector()(重点)无参构造vector()构造并初始化n个val(重点)拷贝构造使用迭代器进行初始化构造//如果想要使用find就需要使用这个algorithm库//因为都是使用迭代器来find其中的元素,所以STL中的find封装在这个库里面}......原创 2022-08-13 21:47:14 · 615 阅读 · 0 评论 -
C++【STL】【string类的模拟实现】【string类的深浅拷贝】
为了防止调用库中的string,我们自定义了烛渊的命名空间{{public://析构函数的定义~string(){//分别将字符串中的字符串数组销毁,并且将指向字符串数组的指针置空//这里的_size指的是当前存储的字符个数//这里的_capacity指的是开辟的空间最大存储的空间大小_size=0;}private://c++的特例,const静态可以在类里面直接声明和定义。//语法特殊处理,直接可以当成初始化。};//当然也可以放在类外面初始化。......原创 2022-08-13 00:14:41 · 574 阅读 · 0 评论 -
C++【STL】【string类的使用】
C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。1. 字符串是表示字符序列的类。.....................原创 2022-08-09 18:30:36 · 572 阅读 · 0 评论 -
C++【模板】
上面的交换两个数据的代码都非常相似,我们有没有可能写一个模板,只写一个模板就能满足上面不同的要求呢?就好比是活字印刷术,只要模具制作好了,涂上墨,直接印刷就是一份新的文稿。...原创 2022-08-08 17:16:50 · 467 阅读 · 0 评论 -
C++【内存管理】
;int main(){// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间//还会调用构造函数和析构函数//这里在堆上开辟空间的时候还会调用构造函数对我们的对象进行初始化。free(p1);delete p2;// 内置类型是几乎是一样的// C//free仅仅是释放空间free(p3);......原创 2022-08-06 18:20:07 · 289 阅读 · 0 评论 -
C++【类和对象】【三】
第三行的W() 本来应该是由我们的f3()生成一个w类的对象,然后再return的时候将这个生成的w类的对象以拷贝的形式返回,然后再将我们的返回值以拷贝的形式赋给w1,所以我们一共是一次构造,两次拷贝,但是我们的clion编译器在这里优化了,直接将我们生成的ret给了w1,期间并没有拷贝构造。然后这个对象的销毁是在最后一行的。f1(w())原本应该是先构造一个w再拷贝构造给我们的f1的,但是由于我们的编译器的优化,这里就直接将拷贝的值传递给我们的f1了,所以在w()构建之后紧接着就是~W()的销毁。...原创 2022-08-05 23:20:58 · 160 阅读 · 0 评论 -
C++【面向对象】【如何手动实现日期类】
利用赋值运算符的重载,我们可以实现日期类的运算。本博文先分块实现每一个功能,最后汇总给出代码。原创 2022-07-23 15:44:15 · 273 阅读 · 0 评论 -
C++【类和对象】【二】
2.s2对象使用s1拷贝构造,而Stack类没有显式定义拷贝构造函数,则编译器会给Stack类生成一份默认的拷贝构造函数,默认拷贝构造函数是按照值拷贝的,即将s1中内容原封不动的拷贝到s2中。s2先销毁,s2销毁时调用析构函数,已经将0x11223344的空间释放了,但是s1并不知道,到s1销毁时,会将0x11223344的空间再释放一次,一块内存空间多次释放,肯定会造成程序崩溃。构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象。..原创 2022-07-17 12:35:36 · 181 阅读 · 0 评论 -
C++【类和对象】【一】
//类体由成员函数和成员变量组成};//一定要注意后面的分号class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分号。类中的元素称为类的成员类中的数据称为类的属性或者成员变量;类中的函数称为类的方法或者成员函数。1.声明和定义全部放在类体中,需要注意成员函数如果在类中定义,编译器如果符合inline的条件(代码比较短),会将其当成内联函数处理。2.声明放在.h文件中,类的定义放在.cpp文件中一般情况下,更期望采用第二种方式。.........原创 2022-07-16 12:39:42 · 82 阅读 · 0 评论 -
C++语法入门
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。一个命名空间就创建了一个新的作用域,其中的函数和变量只有在该命名空间中才会生效。namespacehello//N1为命名空间的名称{//命名空间中的内容,既可以定义变量,也可以定义函数inta;{}}intmain(){//当我们需要使用我们指定的命名空间的函数或者变量的时候,我们可以用命名空间加上两个冒号来指定。stdendl;{...原创 2022-07-11 11:22:05 · 218 阅读 · 5 评论 -
八大排序算法比较【c语言数据结构】
八大排序算法。原创 2022-07-09 14:57:08 · 333 阅读 · 0 评论