复杂度由低到高是:O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3)
Java提供的一个用来定义排序规则的接口。
参考链接: 常见七种排序算法对比(超全!!!)
插入排序——数据少或基本有序;选择排序——数据少(或优于插入);希尔排序——数据中等;堆排序——数据多;归并排序——数据多且排序稳定。
排序原理: 将数组分为两部分(有序和无序),将后部分元素逐一插入前部分有序元素的适当位置。
适用场景: 待排序 记录较少或基本有序 的情况。
排序原理: 希尔排序(Shell Sort)是插入排序的一种,针对直接插入排序算法进行改进。先选定一个 整数增量,把待排序文件中所有记录分成个组 ,所有距离为增量的记录分在同一组内,并对每一组内的记录进行排序。然后减小增量,重复上述分组和排序的工作。当增量减至1时,所有记录排序完毕。
适用场景: 中等规模的数据量,对规模很大的数据量不是最佳选择。
排序原理: 每次遍历一趟,找出最小的数,放到最前端,直到全部待排序的数据元素排完。 (这里说的是最前,是指无序的队列中的最前)
适用场景: 数据量较小的情况,比直接插入排序稍快。
排序原理: 将待排序记录看作完全二叉树,可以建立大根堆或小根堆,大根堆中每个节点的值都不小于它的子节点值,小根堆中每个节点的值都不大于它的子节点值。
适用场景: 数据量较大的情况。
排序原理: 比较相邻的元素,如果第一个比第二个大就进行交换 ,对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对,每一轮排序后末尾元素都是有序的,针对n个元素重复以上步骤n-1次排序完毕。
排序原理: 首先选择一个 基准元素 ,通过一趟排序将要排序的数据分割成独立的两部分,一部分全部小于等于基准元素,一部分全部大于等于基准元素,采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度等于1,代表已经有序,或者小区间的长度等于0,代表没有数据。
排序原理: 应用分治法将待排序序列分成两部分,然后对两部分分别递归排序,最后进行合并,使用一个辅助空间并设定两个指针分别指向两个有序序列的起始元素,将指针对应的较小元素添加到 辅助空间 ,重复该步骤到某一序列到达末尾,然后将另一序列剩余元素合并到辅助空间末尾。
适用场景: 数据量大且对稳定性有要求的情况。
对于一个有序的升序列表,将目标值与表中间的值进行对比:
① 如果目标值与表中间的值相等,则直接返回表中间的值即可。
② 如果目标值与表中间的值不相等,则将两者进行大小比较,从而分成两个表:
算法思路:
① 首先确定有序的升序列表的中间值是多少,即:mid = (left+right)/2 //中间值的下标
② 将目标值target与表中间的值arr[mid]进行比较:
① 找到目标值就结束。
② 查找完整个数组,如果依然没有找到目标值,也需要结束。
③ 当left > right,则直接退出。
线性表是最基本、最简单、也是最常用的一种数据结构。一个线性表是n个具有相同特性的数据元素的有限序列。
前驱元素: 若A元素在B元素的前面,则称A为B的前驱元素。
后继元素: 若B元素在A元素的后面,则称B为A的后继元素。
线性表的特征: 数据元素之间具有一种"—对一"的逻辑关系。
①第一个数据元素没有前驱,这个数据元素被称为头结点。
②最后一个数据元素没有后继,这个数据元素被称为尾结点。
③除了第一个和最后一个数据元素外,其他数据元素有且仅有一个前驱和一个后继。
线性表的分类
线性表中数据存储的方式可以是顺序存储,也可以是链式存储,按照数据的存储方式不同,可以把线性表分为顺序表和链表。
顺序表在计算机内存中以 数组 的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元,依次存储线性表中的各个元素、使得线性表中 在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,如ArrayList。
链表是一种 物理存储单元上非连续、非顺序的存储结构,其物理结构不能直观的表示数据元素的逻辑顺序,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列的结点(链表中的每一个元素称为结点)组成,结点可以在运行时动态生成,如LinkedList。
单向链表
单向链表是链表的一种,它由多个结点组成,每个结点都由一个数据域和一个指针域组成,数据域用来存储数据,指针域用来指向其后继结点。链表的头结点的数据域不存储数据,指针域指向第一个真正存储数据的结点。
双向链表
双向键表也叫双向表,是链表的一种,它由多个结点组成,每个结点都由一个数据域和两个指针域组成,数据域用来存储数据,其中一个指针域用来指向其后继结点,另一个指针域用来指向前驱结点。链表的头结点的数据域不存储数据,指向前驱结点的指针域值为null,指向后继结点的指针域指向第一个真正存储数据的结点。
常见笔试题:链表反转
循环链表
循环链表,顾名思义,链表整体要形成一个圆环状。在单向链表中,最后一个节点的指针为null,不指向任何结点,因为没有下一个元素了。要实现循环链表,我们只需要让单向链表的最后一个节点的指针指向头结点即可。
循环链表的应用: 约瑟夫问题(一群人围在一起报数)
栈是一种基于 先进后出(FILO) 的数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
我们称数据进入到栈的动作为 压栈 ,数据从栈中出去的动作为 弹栈 。
栈的核心操作:入栈,出栈,取栈顶元素。
对于栈的形象理解:子弹的弹夹我们一定见过,子弹在被压入的时候就相当于是一个个元素,而弹夹就相当于是栈。先被压入的子弹是最后被打出的,先压入的元素是最后出来的,也就是先进后出。
栈的应用: 括号匹配问题、逆波兰表达式求值。
队列是一种先进先出(FIFO)的数据结构,是一种只能在一端进行插入,另一端进行删除的特殊线性表,按照先入先出的原则存储数据。队列里边有队首,队尾,队首元素。其遵循的原则是先进先出。
队列的核心操作:入队列,出队列,取队首元素。
对于队列的形象理解:火车穿越隧道,火车的头相当于是队列的首,火车的尾相当于是队列的尾部。火车在穿越隧道的时候,头部先进入隧道头部也先出隧道,尾部后进入尾部后出隧道。队列也就是先入的元素先出队列,后进入的元素后出队列。
栈和队列的出入方式不同:栈是先进后出、队列是先进先出。
栈和队列在具体实现的时候操作的位置不同:因为栈是先进后出,它在一端进行操作;而队列是先进先出,实现的时候在两端进行。在Java标准库中实现队列时是按照链表实现的。
二叉树就是 度不超过2的树(每个结点最多有两个子节点)。
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。
为了保证查找树的平衡性,我们需要一些灵活性,因此在这里我们允许树中的一个结点保存多个键。确切的说,我们将一棵标准的二叉查找树中的结点称为2-结点(含有一个键和两条链),而现在我们引入3-结点,它含有两个键和三条链。2-结点和3-结点中的每条链都对应着其中保存的键所分割产生的一个区间。
2-3树满足的条件
2-结点:含有一个键(及其对应的值)和两条链,左链接指向2-3树中的键都小于该结点,右链接指向的2-3树中的键都大于该结点。
3-结点:含有两个键(及其对应的值)和三条链,左链接指向的2-3树中的键都小于该结点,中链接指向的2-3树中的键都位于该结点的两个键之间,右链接指向的2-3树中的键都大于该结点。
2-3树的性质
通过对2-3树插入操作的分析,我们发现在插入的时候,2-3树需要做一些局部的变换来保持2-3树的平衡。
—棵完全平衡的2-3树具有以下性质:
①任意空链接到根结点的路径长度都是相等的。
②4-结点变换为3-结点时,树的高度不会发生变化,只有当根结点是临时的4-结点,分解根结点时,树高+1。
③2-3树与普通二叉查找树最大的区别在于,普通的二叉查找树是自顶向下生长,而2-3树是自底向上生长。
红黑树主要是对2-3树进行编码,红黑树背后的基本思想是用标准的二叉查找树(完全由2-结点构成)和一些额外的信息(替换3-结点)来表示2-3树。我们将树中的链接分为两种类型:
红链接:将两个2-结点连接起来构成一个3-结点。
黑链接:则是2-3树中的普通链接。
确切的说,我们将3-结点表示为由由一条左斜的红色链接(两个2-结点其中之一是另一个的左子结点)相连的两个2-结点。
一种自平衡的 二叉查找树(左中右↑),除了满足二叉查找树的性质外,还需要满足如下五个条件:
① 每个节点非黑即红;
② 根节点总是黑色的;
③ 每个 叶子 节点都是黑色的 空节点(NIL节点);
④ 如果 节点是红色的,则它的子节点必须是黑色的(反之不一定);
⑤ 从 根节点到叶节点 或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)。
应用: TreeMap、TreeSet以及JDK1.8的HashMap底层都用到了红黑树。
为什么要用? 是为了解决二叉查找树在某些情况下会退化成一个线性结构的问题(如:形成二叉查找树的时候插入的元素是有序时,查找性能变成线性)。
B树是一种树状数据结构,它能够存储数据、对其进行排序并允许以O(logn)的时间复杂度进行查找、顺序读取、插入和删除等操作。
B树中允许一个结点中包含多个key。M阶的B树,具有如下特点:
①每个结点 最多有M-1个key,并且以升序排列。
②每个结点最多能有M个子结点。
③根结点至少有两个子结点。
B+树是对B树的一种变形树,它与B树的差异在于:
①非叶结点仅具有索引作用,也就是说,非叶子结点只存储key,不存储value。
②树的所有叶结点构成一个有序链表,可以按照key排序的次序遍历全部数据。
B+树的优点在于:
①由于B+树在非叶子结点上不包含真正的数据,只当做索引使用,因此在内存相同的情况下,能够存放更多的key。
②B+树的叶子结点都是相连的,因此对整棵树的遍历只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。
B树的优点在于:
由于B树的每一个节点都包含key和value,因此我们根据key查找value时,只需要找到key所在的位置,就能找到value,但B+树只有叶子结点存储数据,索引每一次查找,都必须一次一次,一直找到树的最大深度处,也就是叶子结点的深度,才能找到value。
堆是计算机科学中一类特殊的数据结构的统称,堆通常可以被看做是 一棵完全二叉树的数组对象。
最大优先队列: 可以获取并删除队列中最大的值。
最小优先队列: 可以获取并删除队列中最小的值。
图是由一组顶点和一组能够将两个顶点相连的边组成的。
自环:即一条连接一个顶点和其自身的边。
平行边:连接同一对顶点的两条边。
按照连接两个顶点的边的不同,可以把图分为以下两种:
无向图: 边仅仅连接两个顶点,没有其他含义。
有向图: 边不仅连接两个顶点,并且具有方向。
相邻顶点:当两个顶点通过—条边相连时,我们称这两个顶点是相邻的,并且称这条边依附于这两个顶点。
度:某个顶点的度就是依附于该顶点的边的个数。
子图:是一幅图的所有边的子集(包含这些边依附的顶点)组成的图。
路径:是由边顺序连接的一系列的顶点组成。
环:是—条至少含有一条边且终点和起点相同的路径。
连通图:如果图中任意一个顶点都存在一条路径到达另外一个顶点,那么这幅图就称之为连通图。
连通子图:一个非连通图由若干连通的部分组成,每一个连通的部分都可以称为该图的连通子图。
深度优先搜索和广度优先搜索。
定义:有向图是一副具有方向性的图,是由一组顶点和一组有方向的边组成的,每条方向的边都连着一对有序的顶点。
出度:由 某个顶点指出的边的个数 称为该顶点的出度。
入度:指向某个顶点的边的个数 称为该顶点的入度。
有向路径:由—系列顶点组成,对于其中的每个顶点都存在一条有向边,从它指向序列中的下一个顶点。
有向环:—条至少含有一条边,且起点和终点相同的有向路径。