二叉树:
二叉树:每个父节点都只有两个子节点(左子节点和右子节点);二叉树可以快速的查询、插入、删除元素;
1)满二叉树:所有的分支要么左右分支节点都有,要么没有子节点,且所有叶子节点都在同一层上;
满二叉树的特点:
非叶子结点的度为2;
所有的叶子节点都在同一层上;
2)完全二叉树:满二叉树一定是完全二叉树,但是完全二叉树不一定是满二叉树;
完全二叉树的特点:
叶子节点只能出现在最下面两层;
最下层的叶子节点一定集中在最左边并且连续;
若节点度为1,则该节点只能是左子节点;
3)二叉搜索树(二叉排序树,二叉查找树、二叉检索树):
二叉搜索树的定义:
(1)每一个节点有一个唯一的key值,且所有节点互不相同;
(2)左子树所有key值小于根的key值;
(3)右子树所有key值大于根的key值;
(4)左右子树都是二叉搜索树。
二叉搜索树的性能分析:二叉搜索树的查找、插入和删除的时间复杂度为O(log n),其中,n为节点个数;
二叉搜索树的查找操作:
(1)与根节点的key值比较,相等则查找成功;
(2)小于则查找左子树;
(3)大于则查找右子树。
二叉搜索树的插入操作:
(1)先用查找操作找到要插入元素要插入后的父亲节点(具体:与当前节点比较,如果相同则表示已经存在且不能重复插入);
(2)和父亲节点比较后,决定作为右孩子还是左孩子插入(具体:小于则在左子树中寻找,如果左子树为空则当前节点为要找的父节点,新节点插入到当前节点的左子树。反之,大于则在右子树中寻找,如果有字数为空则当前节点为要找的父节点,新节点插入到当前节点的右子树);
(3)若树空,则作为根节点插入。
二叉搜索树的删除操作:
(1)先用查找操作找到被删除元素的位置;
(2)若被删除元素没有孩子节点,则可以直接删除;
(3)若被删除元素只有左孩子或者右孩子(左孩子或者右孩子可能是一个节点,也有可能是一个子树),则直接删除,然后把左孩子或者右孩子加到它的父亲节点上;
(4)若被删除元素两个孩子都有,选取“替身”取代被删除节点,然后删除“替身”节点;
如何选择“替身”?
左子树最大的节点(即从被删除的左子树中找到最右边的那个节点),或者右子树最小的节点(即从被删除右子树中找到最左边的那个节点),这两个都可以作为“替身”节点;找到后,将“替身”节点的数据和被删除节点的数据交换。
接下来的问题就是删除“替身”节点,如果“替身”节点只有一个孩子,就回到了上面的第(3)点
二叉查找树的缺点:
基于二叉查找树的这种特点,我们在查找某个节点的时候,可以采取类似于二分查找的思想。快速找到某个节点。正常情况下,n个节点的二叉查找树,它的查找时间复杂度为O(log n),但是二叉搜索树的高度和插入顺序有关,在极端情况下,二叉查找树可以近似退化为一条链表,它的查找时间复杂度就变成了O(n).为了避免这种情况的发生,引申出了如下的二叉平衡树。
4)二叉平衡树(AVL Tree):是为了解决二叉查找树退化成一条链表而诞生的。
二叉平衡树有如下特征:
(1)具有二叉查找树的全部特性;
(2)每个节点的左子树和右子树的高度差至多等于1。
平衡二叉树的缺点(为什么有的平衡树还需要红黑树?)
虽然平衡二叉树能够把查找时间控制在O(log n),不过却不是最佳的。因为二叉平衡树要求每一个节点的左子树和右子树的高度差至多等于1,这个要求实在是太严了,导致每次进行插入、删除节点的时候,几乎都会破坏平衡树的第二条规则,进而我们需要通过左旋和右旋来进行调整,使之再次成为一颗符合要求的平衡树。为了解决这种问题,于是有了如下的红黑树。
5)红黑树(R-B-Tree):是为了解决平衡树在插入、删除等操作需要频繁调整的情况,是一种特殊的二叉查找树,红黑树的每个节点上都有存储位表示节点的颜色,可以是红或者黑;
红黑树的特性:
(1)具有二叉查找树的特性;
(2)根节点是黑色的;
(3)每个叶子节点都是黑色的空节点,也就是说,叶子节点不存在数据;
(4)任何相连的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的;
(5)每一个节点,从该节点到达其可达的叶子节点的所有路径,都包含了相同数目的黑色节点。
由于红黑树的这些特性,使得在最坏的情况下,也能在O(log n)的时间复杂度下查找到某个节点。红黑树在插入、删除等操作,不会像平衡树那样,频繁破坏红黑树的规则,所以不需要频繁调整。这就是我们在大多数情况下使用红黑树的原因。
单单在查找方面的效率,平衡二叉树比红黑树快。
红黑树是一种不大严格的平衡树(一个折中方案)。
6)B-Tree(平衡多路查找树,并不是二叉树):是为磁盘等外存储设备设计的一种平衡查找树。B-Tree结构可以让系统高效地找到数据所在的磁盘块。
下面先了解磁盘的相关知识:
系统从磁盘读取数据到内存中时,是以磁盘块(block)为基本单位的,位于同一个磁盘块的数据会被一次性读取出来,而不是需要什么读取什么。
InnoDB存储引擎中有页(Page)的概念,页是其磁盘管理的最小单位。InnoDB存储引擎中默认的每个页的大小为16KB,可通过参数innodb_page_size将页的大小设置为4KB/8KB/16KB,在MYSQL中可以通过如下命令查看页的大小:
mysql> show variables like ‘innodb_page_size’;
然而,系统中一个磁盘块的存储空间往往没有那么大,因此,InnoDB每次申请磁盘空间时,都会以连续磁盘块来达到页的大小16KB.InnoDB在把磁盘数据读入到磁盘时,会以页为基本单位,在查询数据时,如果一个页中的每条数据都能有助于定位数据记录的位置,这将会减少磁盘I/O次数,提高查询效率。
一棵m阶的B-Tree有如下特性:
(1)每个节点最多有m个孩子;
(2)除了根节点和叶子节点外,其它每个节点至少有Ceil(m/2)个孩子;
(3)若根节点不是叶子节点,则至少有2个孩子;
(4)所有的叶子节点都出现在同一层,且不包含其它关键字信息;
(5)每个非终端节点中包含n个关键字信息(P0,K1,P1,K2,P2,…,Kn,Pn);
(6)关键字的个数n满足:ceil(m/2)-1<=n<=m-1;
(7)Ki(i=1,…,n)为关键字,且关键字升序排序;
(8)Pi(i=0,…,n)为指向子树根节点的指针,P(i-1)所指向子树的所有节点关键字均小于Ki,但都大于K(i-1);
正如上面的例子,模拟查找关键字29的过程:
(1)根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】
(2)比较关键字29在区间(17,25)之间,找到磁盘块1的P2指针.
(3)根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】
(4)比较关键字29在区间(26,30)之间,找到磁盘块3的P2指针。
(5)根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】
(6)在磁盘块8中的关键字列表中找到关键字29.
分析上面的过程,进行了3次I/O操作,和3次内存查找操作。
由于内存中的关键字是一个有序表结构,可以利用二分查找提高效率。
3次磁盘I/O操作是影响整个B-tree查找效率的决定原因。
B-tree的优势(相对于平衡树AVL Tree):
B-Tree缩减了节点的个数,使得每次的磁盘I/O读取内存中的数据都发挥了作用,从而提高了查询效率。
B-Tree的缺点:
由于每个页的存储空间有限,对于B-Tree而言,如果data数据较大时,将会导致每个节点(即一个页)能存储的key的数量较小;当存储的数据量很大时,会导致B-Tree的深度较大,这就使得查询时磁盘I/O的次数增大,进而影响查询效率。
7)B+Tree:是在B-tree基础上的优化,使其更加适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。
B+Tree相对于B-Tree有几点不同:
(1)B-Tree的每个节点中不仅包含数据的key值,还有data值;但是在B+Tree的非叶子节点只存储key值信息,所有的数据记录(data)都是按照key值大小顺序存放在同一层的叶子节点上;
(2)B+Tree的所有的叶子节点之间都有一个链指针,而B-Tree没有。
B+Tree的优势:
针对于B-Tree的缺点而言,在B+Tree中,所有的数据信息都按照键值大小顺序存放在叶子节点上,而非叶子节点上只存储key值,这样可以大大的增加每个非叶子节点的key值数量,降低B+Tree的高度,从而使得查询时磁盘I/O的次数减少,进而提高查询效率。