
数据结构
文章平均质量分 88
ji_r
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
二叉搜索树和有序数组的转换
二叉搜索树的特点:中序遍历的序列是一个有序序列/数组。这里主要展示有序数组转换为二叉搜索树,但是这样的二叉搜索树为多个。所以这里可以参看leetcode 108.将有序数组转换为二叉搜索树,加上了“平衡的条件”,尽管此时二叉搜索树的个数还是多个,但是在构造BST时很方便。只需要“不断的折半”即可。参考代码:/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode原创 2020-07-17 00:06:13 · 904 阅读 · 0 评论 -
以1-N为节点的二叉搜索树的个数和生成对应的二叉搜索树
输入: 3输出: 5解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树:要满足是二叉搜索树,以i为root, 左子树的个数为i-1(比i小的数),右子树的个数为n-i(比i大的数)。此时如果出现个数为0,表示空树,记作1;只有一个节点,表示只有根的树,也记作1.f(i)=f(i-1)*f(n-i) (一一组合配对构成整个二叉搜索树)所以1-n为节点构成的二叉搜索树的个数为:参看代码:class Solution {public: int numTr原创 2020-07-16 23:44:07 · 1151 阅读 · 0 评论 -
数组中第K大(小)的元素
在未排序的数组中找到第k个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。这是一道排序问题?但是当数组元素N很大时,采用一般O(N^2)的排序算法(如冒泡排序)一定会超时。所以这里可以使用快排和堆排。这里快排和堆排的思想就不详细介绍了,有兴趣的可以去看我的其他文章或者直接baidu一下。1.直接快速排序,对整个数组进行排序lass Solution {public: int findKthLargest(vector<int..原创 2020-07-06 22:37:18 · 471 阅读 · 0 评论 -
拓扑排序
什么是拓扑排序?此处采用百度百科的解释:执行步骤:循环执行以下两步,直到不存在入度为0的顶点为止。(1) 选择一个入度为0的顶点并输出之;(2) 从网中删除此顶点及所有出边。循环结束后,若输出的顶点数小于网中的顶点数,则输出“有环路”信息,否则输出的顶点序列就是一种拓扑序列。一个简单的实例(过程):实现:利用邻接矩阵表示两者的关系。将上述示例中的图用邻接矩阵表示:参考代码:#include<iostream>#include<cs原创 2020-06-24 00:36:50 · 377 阅读 · 0 评论 -
链表中的双指针
链表中的双指针,一般是指初始时设置两个移动指针,它们可能以不同的初始状态或不同的移动方式进行移动。1.删除链表的倒数第N个节点题目描述:给定一个链表,删除链表的倒数第n个节点,并且返回链表的头结点。示例:给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链表变为 1->2->3->5.说明:给定的 n保证是有效的。进阶:你能尝试使用一趟扫描实现吗?思路:不同的初始状态,一个指针从头开始移动,一个...原创 2020-06-23 11:59:19 · 1293 阅读 · 0 评论 -
滑动窗口(一)
什么是滑动窗口?大致就是如下图:维护left和right两个指针,在整个区间内,通过改变左右指针的移动,找到满足条件的区间(很多时候是最佳区间)。所以窗口的大小是在移动过程中改变的。目的:常用于将嵌套的循环问题,转换为单循环问题,降低时间复杂度。常用于解决数组/字符串的子元素问题。问题1及解决思路:1.先计算出前K个元素的和(即arr[0] + ...+ arr[k-1])。2.从i=k to arr.size() - 1, sum += arr[i] - arr[i-k]; /原创 2020-06-18 21:37:11 · 396 阅读 · 0 评论 -
单调栈
什么是单调栈?这个概念是在leetcode做题时接触的,就是通过栈的push()和pop()操作,维护一个有序的序列(依次出栈的元素)。如:7 4 3 8 10 9 13下面则通过leetcode中的题目来说明它如何在问题中使用?739. 每日温度题目描述:请根据每日气温列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用0来代替。例如,给定一个列表temperatures = [73, 74, 75...原创 2020-06-12 21:06:25 · 260 阅读 · 0 评论 -
并查集(Union-find set)
它是一种维护集合的数据结构,它的名字"并" "查" "集" 。即 union / find / set。并查集产生的每个集合都是一棵树(tree) 。基本操作:1.合并两个集合union。2.判断两个元素是否在一个集合中find。实现:利用一个数组int father[N];其中父节点自身也在1-N之中用来记录父节点:即father[i]表示的i节点的父亲节点。当a和b的father[a]==father[b]时,a和b才是联通的。初始化:void init(int fa[], i..原创 2020-06-08 20:13:36 · 470 阅读 · 0 评论 -
LRU缓存机制
本文借助leetcode中的一道题目,来介绍LRU的相关知识,以及如何实现它。leetcode 146:问题:运用你所掌握的数据结构,设计和实现一个LRU(最近最少使用)缓存机制。它应该支持以下操作: 获取数据get和写入数据put。获取数据get(key):如果密钥(key)存在于缓存中,则获取密钥的值(总是正数), 否则返回-1。写入数据put(key, value):如果密钥不存...原创 2019-11-02 12:46:25 · 289 阅读 · 0 评论 -
前序序列和中序序列、中序序列和后序序列生成二叉树
今天分享的内容,也是结合leetcode中的两题,大家可以理清思路后可以去平台做一下题,检验一下成果。首先我们还是得理解三种遍历方式的特征:preorder: 先序遍历中,先遍历root,也就是说在先序序列中的第一个元素即原二叉树的root节点。同理,在postorder中,由于先遍历left & right 也就是说后序序列中的最后一个元素是二叉树的root节点。inor...原创 2019-10-27 16:06:14 · 3111 阅读 · 0 评论 -
图的基本概念及存储结构
图的基本概念:定义:图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V(vertex)是图G中顶点的集合,E(edge)是图G中边的集合。分类:1、按有无方向分类:有向图和无向图。无向图由顶点和边组成,有向图由顶点和弧组成, 弧有弧头(head)和弧尾(tail)两部分。2、如果任意的两个顶点之间都存在边,叫完全图;有向的图叫有向完全图。...原创 2018-05-22 16:42:17 · 1898 阅读 · 0 评论 -
线性表(一)--- 顺序存储结构
根据数据结构的逻辑结构来分:数据元素之间存在的关联关系被称为数据间的逻辑结构。分为一下4类:1.集合:数据元素之间只有“同属于一个集合”关系2.线性结构 : 数据元素间存在一对一的关系 ---- 线性表 非线性结构: 图和树3.树形结构 : 数据元素之间存在一对多的关系 4.图状或者网状结构 : 数据元素间存在多对多的关系而在计算机在物理磁盘上通常是2种物理存储结构: 顺序存储结构、链式存...原创 2018-04-02 20:40:30 · 365 阅读 · 0 评论 -
栈(Stack) --- 栈的链式结构
除了我之前一篇文章中介绍的栈的顺序存储,就是底层使用一个数组存储数据元素。其实也是可以使用单链表存储栈中的数据, 然后使用一个top引用来记录栈顶元素进栈:top指向新添加的元素, 新元素的引用指向原来的栈顶元素 size + 1。 出栈: top指向原栈顶元素的下一位元素, 使用原来的栈顶元素 size - 1。图示其过程(制作粗糙,请见谅): ...原创 2018-04-01 16:27:19 · 294 阅读 · 0 评论 -
栈Stack(一)--- 栈的顺序存储
在介绍双向队列接口(Deque)时,就拿栈(Stack)与它相比较,可以看出栈是只能在一头进行操作的一种数据结构。就栈而言 : 我们将进行插入和删除的一端叫做栈顶,相应地另一端也就是栈底。进栈与出栈: * 栈顶插入一个元素 --- 进栈 我们叫这个元素从栈顶被 “压入栈” -- push() * 栈顶删除一个元素 --- 出栈 我们叫这个元素从栈顶“弹出栈” -- pop()原则 ...原创 2018-03-30 20:44:26 · 3727 阅读 · 0 评论 -
队列(四)---java中的Queue接口和Deque接口
java中的队列利用的是java提供的Queue接口,该接口代表了一个队列。包含了三个标志性的方法: 插入:在队列的rear端插入数据。删除:在队列的front端删除数据。访问:访问front端的数据元素。方法对比:抛出异常版本返回特殊值版本插入add(element)offer(element)移除remove()poll()检查element()peek()参考代码:import java....原创 2018-03-28 21:43:39 · 590 阅读 · 0 评论 -
队列(三) --- 队列的链式存储
类似使用链式存储结构保存线性表, 这里也可以使用链式结构存储队列中的各元素,我们可以称置为链队列。主要就是插入队列和移除队列,可参看一下(制作粗糙,请见谅):(依次是原队列、插入元素、删除数据后的形式)参考代码:public class LinkQueue<T> { private class Node{ //保存节点的数据 private T data; //指向下一...原创 2018-03-28 20:26:00 · 355 阅读 · 0 评论 -
队列(二)-------循环队列
刚前一篇(点击打开链接)也说到顺序队列存储时的问题,所以引出循环队列的解决方案。 因为前一篇也说到了队列的基本概念,所以这里使用图示和代码直接理解。图示(制作简陋,请见谅):此时可以看出来rear当满了之后,就转头从0开始,继续往后。但是此时如何判断它是满的状态?只根据rear == front有局限性。这里我是加了一个判断front处的数据元素值是不是等于null.判断队列的长度:re...原创 2018-03-24 15:58:15 · 374 阅读 · 0 评论 -
队列(一)-------顺序队列
基本定义:一种特殊的线性表, 只允许在表的前端front进行删除操作, 只允许在后端rear 进行插入操作。进行插入的端叫做队尾,进行删除的一段叫做队头 。 ---- 先进先出的原则 FIFO 既然有固定的顺序操作 所以提供的大概有如下的操作: * init 初始化 :通常是一个构造器, 用于创建一个空队列 * length : 返回队列中元素的个数 * insert : 向队尾rear 插入...原创 2018-03-24 14:40:41 · 661 阅读 · 0 评论 -
红黑树(三)
删除操作1. 在纯函数式的环境下,纯函数式的数据结构决定了树不是真的被改变了,实际上是重建一棵树。(大多数函数式编程环境使用一种名叫Persistent的方法,可以复用树中没有改变的部分,从而减小重建的开销)。利用一个双重黑色的引入。将删除节点的颜色(黑色)保存在其父节点中,如果父节点红色,则染成黑色,如果父节点是黑色,就是双重黑色。删除的过程:1、如果删除的这个节点是根节点,root = nul...原创 2018-04-28 20:30:09 · 217 阅读 · 0 评论 -
红黑树(二)
红黑树的插入操作1. 以排序二叉树的方法插入新节点,并将它设置为红色。设置红色:如果设置黑色,会导致根节点到叶子节点的路径上多出一个额外的黑节点,这样会很难调整。但是设置为红色可能会导致出现两个连续的红色节点(违反了性质4),因此需要通过颜色转换和树旋转来进行调整。2. 颜色转换和树旋转新插入的节点N, N的父亲节点设置为P,P的兄弟节点设置为B,P的附近点设置为G。(可以理解为newnode,p...原创 2018-04-22 23:05:35 · 212 阅读 · 2 评论 -
红黑树(一)
之前一篇讲关于二叉搜索树的文章(参看:点击打开链接),但是存在一个问题,在最坏情况下,插入的节点本身就是有序的,要么是从大到小排列,要么是从小到大排列,那最后得到的排序二叉树将会变成链表。这样其检索效率特别差。如图:为了改进这种不足,Rudolf Bayer于1972年发明了另一种改进后的排序二叉树,他将这种树称为“对称二叉树”,红黑树后来被人提出命名。在二叉树的基础上增加了这些要求:1.每个节点...原创 2018-04-19 21:41:20 · 201 阅读 · 0 评论 -
基数排序
基数排序的总体思路就是将待排序的数据拆分成多个关键字进行排序,也就是说,基数排序的实质是多关键字排序。而多关键字排序的思路是将待排序的数据里的排序关键字拆分成多个排序关键字:第1个、第2个、第3个......然后,根据子关键字对 待排序数据进行排序。多关键字排序可分为:最高位优先法MSD 和 最低位优先法LSD。我在截图中会将每一次排序的结果显示出来,便于理解。参考代码:public clas...原创 2018-03-27 20:43:36 · 237 阅读 · 0 评论 -
桶排序
桶排序的原理和计数排序类似,可以说是计数排序的升级版。他利用了函数映射关系,将输入的值映射到对应的桶里面去。所以他的高效就在于这个映射函数的确定。所以需要做到如下两点:1.在额外空间充足的情况下,尽量增大桶的数量。2.使用映射函数能将输入的N个数据均匀的分配到K个桶中去。此外就是对于桶中的数据元素的排序时,使用哪种比较排序的算法比较好,对性能的影响至关重要。什么时候最快:当输入数据可以均匀分配到每...原创 2018-04-16 20:21:07 · 207 阅读 · 0 评论 -
计数排序
计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。 当然这是一种牺牲空间换取时间的做法,而且当O(k)>O(n*log(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是O(n*log(n)), 如归并...原创 2018-04-16 20:08:40 · 170 阅读 · 0 评论 -
线性表(三)--- 双向链表
就是给每个节点保留两个引用prev和next,其中prev指向前一个节点,next指向后一个节点。该链表既可以向后依次访问每个节点,也可以向前其次访问每个节点,以这种形式保存的节点称为双向链表。查找:既可以从header(头节点),也可以从tail(尾节点)开始寻找指定的节点。一般的是根据搜索的index值来判断跟接近于头节点还是尾节点。即比较index和size(链表的大小)/2的大小。若是in...原创 2018-04-11 20:08:40 · 303 阅读 · 0 评论 -
线性表(二)--- 单链表
链式存储结构的线性表 简称为链表。是采用一组地址任意的存储单元存放线性表中的元素数据。它需要在每一个数据元素里保存一个引用下一个数据元素的引用 --- 指针。单链表 --- 每个节点只保留一个引用, 该引用指向当前节点的下一个节点, 没有引用指向头节点, 尾节点的next引用为null。建立的方法 : 1.头插法 : 该方法从一个空表开始, 不断创建新节点,将数据元素存入节点的data域中, 然后...原创 2018-04-04 22:55:48 · 168 阅读 · 0 评论 -
希尔排序
希尔(shell)排序 是基于插入排序的快速的排序算法。对于大规模的乱序数组插入排序(参考:点击打开链接)比较慢, 因为它只交换相邻的元素,因此元素只能从数组的一端移到另一端。而希尔排序为了加快速度简单地改进插入排序,交换不相邻的元素以对数组的局部进行排序,用插入排序将局部有序的数组排序。思想 : 输入一个h, 使数组中任意时间间隔为h 的元素都是有序的。这样的数组被称为h有序数组。换句话说,就是...原创 2018-03-31 18:40:45 · 142 阅读 · 0 评论 -
快速排序
快速排序利用分治的思想:1.分解:数组A[p....r] 分为 A[p....q -1] 和A[q + 1....r](可能有空的),使得前者的每一个元素都小于A[q],后者的每一个元素都大于A[q]。2.解决:递归使用快速排序,对子数组A[p....q -1] 和A[q + 1....r]进行排序。3.合并:因为是原址排序,愿意无需合并,A[p....r]已经有序。参考代码:public cla...原创 2018-03-26 11:44:30 · 149 阅读 · 0 评论 -
二叉搜索树
二叉搜索树是以一棵二叉树来组织的,如下图所示。这样一棵树可以使用一个链表数据结构来表示,其中每个结点就是一个对象。除了key和卫星数据之外,每个结点还饮食属性left, right 和 p, 它们分别指向结点的左孩子,右孩子和双新。如果某个孩子结点和父结点不存在,则相应属性的值为NIL。根结点是树中唯一父指针为NIL的结点 。二叉搜索树中的关键字总是以满足二叉搜索树性质的方式来存储: 设x是二叉搜...原创 2018-03-25 17:36:23 · 320 阅读 · 0 评论 -
二叉树(二)---二叉树的遍历
对于二叉树的遍历是指按某种规律依次访问二叉树的每个节点,其过程就是将非线性结构的二叉树节点排列成一个线性序列的一个过程。遍历二叉树(对于以链表形式来存储的): 1.深度优先遍历 : 先访问书中最深层次的节点。分为前序 后序 中序排序三种方式。前(先)序:根,左子树, 右子树。中序:左子树, 根, 右子树。 后序:左子树,右子树, 根。注意:对于一个节点来说,在子树中,它可能就是根节点,但是他又是其...原创 2018-03-21 15:01:31 · 259 阅读 · 0 评论 -
二叉树(一)---二叉树的三种创建方法
一、顺序存储利用满二叉树的性质,每层的节点数1,2,4,8......,所以一颗深度为i的二叉树最多只能包含2 (i) - 1 (i是以指数的形式求出来的,此处利用等比数列求和),因此需要设置一个相同长度的数组来存储这个二叉树,若是空出来的节点,则数组元素留空即可。参考代码:public class ArrayBinaryTree<T> { //使用数组来存储它的所有节点 pri...原创 2018-03-20 21:28:50 · 5217 阅读 · 0 评论 -
优先队列
接着上一篇,是利用堆这种数据结构去实现优先队列。优先队列(priority queue)是一种用来维护一组元素组成的集合S的数据结构,其中每一个元素都有一个相关的的值,称为关键字(key)。最大优先队列支持以下操作:insert(S, x):将元素x插入到S中;maximum(S):返回S中具有最大key的元素;extractMax(S):去掉并返回S中具有最大key的元素;increaseKey...原创 2018-03-14 15:31:11 · 268 阅读 · 0 评论 -
堆排序
堆1614108793241这样看是不是就是一个数组?是的,(二叉)堆就是一个数组,可以被看作近似的完全二叉树。对于表示堆的数组array[0…n-1],我们以array[0]为根,给定某个节点下标 i,其父节点和左右后代节点的下标分别为:parent(i) = (i-1)/2;left(i) = 2*i+1;right(i) = 2*i+2;实际操作是可以根据您的设置而改变。所以看作完全二叉树:...原创 2018-03-14 14:43:57 · 180 阅读 · 0 评论 -
归并排序
分治法:将原问题分解成几个规模较小的类似于原问题的子问题,递归的解决子问题,然后再合并这些问题的解来表示原问题的解。分治模式基本步骤:分解 – 解决 – 合并。归并排序就是遵循分治模式的。归并排序是按照基本步骤可分为:分解:分解n个数的序列成各具n / 2个元素的两个序列解决:使用归并排序递归地排序两个子序列合并:合并两个已排序的子序列以产生已排序的答案。理解:进行辅助过程merge()时,实际上...原创 2018-03-12 20:39:39 · 165 阅读 · 0 评论 -
排序
为何会想到写排序呢?是因为上课的时候老师半开玩笑的说到,现在面试很多人排序算法都写不出来的。又问了我们能有多少人在不查阅资料的情况下可以写呢?确实,懂和动手还是有点区别的。所以我们在学习中还是不要眼高手低,踏踏实实的做大概是最好的。一、冒泡排序说的简单点,就是从前往后比较相邻的两个数,大的往下沉,小的往上漂。参考代码:private static void bubbleSort(int[] a) ...原创 2018-03-07 21:43:24 · 193 阅读 · 0 评论 -
树的三种遍历方式的实现(递归&非递归&C++)
本篇文章结合结合leetcode(94、144、145 二叉树的中序、前序、后序遍历方式)中的三道题,介绍树的前序、中序、后序遍历的递归和非递归实现。先简单介绍一下,三种方式遍历时的特征:preorder: root left right.inorder: left root rightpostorder: left right root描述一个二叉树:/*** Defi...原创 2019-10-27 15:33:04 · 552 阅读 · 0 评论