参考学习视频:
2020 王道考研 数据结构
线性结构
特点
- 线性结构作为最常用的数据结构,其特点是数据元素之间存在一对一的线性关系。
- 线性结构有两种不同的存储结构,既顺序存储结构(数组)和链式存储结构(链表)。顺序存储的线性表称为顺序表,顺序表中的存储元素是连续的。
- 链式存储的线性表称为链表,链表中的存储元素不一定是连续的,元素中存放数据元素以及相邻元素的地址信息(指针)。
数组与链表
数组
将多个元素存放在连续的地址中,从下标0开始标记每个元素的顺序。数组是需要提前声明空间的,在Java中用如下方式定义数组,都是声明了数组的空间,当访问的下标超出后就会出现ArrayIndexOutOfBoundsException异常。
int[] nums1 = new int[3];
int[] nums2 = new int[]{1,2,3};
链表
链表会使用指针将多个元素之间连接起来,既上一个元素中的指针指向下一个元素,这些元素在内存中不一定是连续的。链表的最后一个元素的指针通常指向null,表示链表结束。
链表中还分有单向链表、双向链表、循环链表:
单向链表:每一个元素都只有一个指向下一元素的指针。如果遍历这个链表就只能往一个方向进行遍历。
双向链表:每个元素都有两个指针,它们分别指向上一个元素和下一个元素,这样就可以实现两个方向的遍历。
循环链表:一般单向链表最后一个元素的指向下一个元素的指针设为null,表示这个链表的结束和开始。而循环链表中最后一个元素的下一元素指向第一个元素,这样就将链表形成了一个环。同理双向链表也可以形成循环链表。
数组与链表的优缺点
- 数组可以直接通过下标访问,而链表必须需要通过指针来访问到上一个元素或者下一个元素。因此在大量查询时数组要更适用一点。
- 在大量插入、删除、添加操作时,数组需要不断移动大量的其他元素来保证顺序,而链表只需要修改指针即可,链表就更适合。
- 数组由于需要提前声明空间大小,而链表只需要修改指针就可以添加元素,所以在未知数据量的情况下使用链表或者使用可变的数组(Java中的ArrayList)。
队列
队列可以使用数组或者链表来实现,主要特征就是先进先出,后进后出。
元素出队列只能从头部出,进队列只能从尾部进。这样每次出队列肯定是先进入队列的元素。
栈
只能在栈顶操作的一种线性表。将向栈里添加元素叫做入栈、压栈,旧元素会被新元素压在下面。删除元素又叫出栈。
栈的规则常用于出入栈顺序的选择题,这种题只需要把握入栈的顺序和注意在入栈中可能会穿插着出栈操作的可能,出入栈的顺序不一定是对应的,但是想获得一个元素就一定保证它是栈顶。
Hash
散列函数或者Hash函数,其将任意长度的输入通过散列算法变成固定长度的输出既散列值。按散列存储方式构造的存储结构称为散列表,散列表中每一个位置又叫做一个槽(slot)。
Hash通过Key-Value来存储,Key对应散列表中的某一个槽,Key是根据存储数据并按照一定的算法(如散列函数)计算出的,而Value就是存储数据的值。这样就可以根据Key进行快速查找。
Hash冲突
既两个不同Vlaue的数据,它们的Key值是相等的,既它们对应的地址是同一地址,这种情况就叫做Hash冲突。
常见的处理冲突方法:开放地址法、再散列、拉链法。
拉链法
线性探测法
将散列表假想成一个循环表,发送冲突时,从冲突地址的下一单元顺寻寻找空单元,如果到最后一个位置也没有找到空单元,则回到表头开始继续查找,直到找到一个空位,就把此元素放入空位,如果找不到,说明散列表已经满了,需要进行溢出处理。
非线性结构
非线性结构中包含树、广义表、图等,这里只分析树。
树
除了根节点以外的节点,它们都有唯一一个前驱节点,同时它们还有一个或者多个后驱节点。
结论:n个节点的树中只有n-1条边。每一个节点都有一个前驱节点,n个就有n条,但是根节点没有,所以为n-1。
树基本概念
节点的度:结点拥有的子节点数目。
树的度:树中最大度数。
节点深度:从根节点开始向下数,每层累加,d高度为2。
节点高度:从叶子节点开始向上数,每层累加,b的高度就为3。
树的高度:书中最大的深度或者高度。
路径长度:路径上经历过的边的个数。
树性质
- 树中节点数等于所有节点度数+1。
e的度数为2,b为2,c为1,d为3,a为3 ==11,然后加上根节点+1,12。
- 度为m的树中第i层至多有m^(i-1)个节点。
二叉树定义
满二叉树
一颗高度为h,含有2^h - 1个节点的二叉树。既除了最后一层,其他层都有两个子节点。
可以推导出:i节点的左孩子为2i,右孩子为2i+1。
完全二叉树
从上到下,从左到右依次排列节点的序号和满二叉树依次排列节点的序号,两者对应的节点的序号是一样的。
也就是完全二叉树的每个节点都不能只存在右孩子,要么只有左孩子,要么就是叶子节点。
- 有n个节点的完全二叉树的深度为 (log2n)+1。
- 叶子节点只会出现在最后两层。
二叉排序树
一个节点的左子树上所有的节点小于该节点,右子树上的节点都大于该节点。
平衡二叉树
任意节点上的左子树和右子树的深度差不超过1。
二叉树性质
- 在二叉树的第i层上最多有2^(i-1) 个节点 。
- n0=n2+1,n0表示度数为0的节点数,n2表示度数为2的节点数。
- 深度为h的二叉树,最多有2^h-1个节点,最少有h个节点。
- 有n个节点的二叉树,根据卡特兰公式有f(n)种结构。
- 右n个节点的完全二叉树的高度为logn +1或者log(n+1)
- 第i个节点在logi +1 层。
二叉树的存储结构
顺序存储
二叉树的顺序存储结构就是使用一维数组存储二叉树中的结点,并且结点的存储位置,就是数组的下标索引。如果使用0号位,那么就位2i+1 2i+2。
二叉链表
根据树的结构可以定义节点为:
二叉树遍历
前,中 和 中,后 确定一颗二叉树。
查找树
平衡二分查找树
二分查找树:左右子树为也为平衡二分查找树,且左节点小于根节点,右节点大于根节点。
这样对树做中序遍历就是一从小到大的有序集合。
这样的树进行查找类似于二分法:
AVL树
平衡二叉查找树(Self-balancing binary search tree),在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
红黑树
红黑树(Red Black Tree) 是一种自平衡二叉查找树,红黑树是一种特殊的平二叉树,对于只读操作与普通二叉查找树相同。
红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。
- 节点是红色或黑色。
- 根节点是黑色。
- 所有叶子都是黑色。
- 每个红色节点的两个子节点都是黑色。
- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
与avl区别:红黑树不追求"完全平衡",即不像AVL那样要求节点,它只要求部分达到平衡,任何不平衡都会在三次旋转之内解决,而AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多。
多路查找树
B 树
Balance Tree
B+树
B VS B+
- B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;
- B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;
- B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
- B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。
- B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。