前文传送门:
「一本正经的聊数据结构(1):时间复杂度」
「一本正经的聊数据结构(2):数组与向量」
「一本正经的聊数据结构(3):栈和队列」
在前面的文章中,我们已经陆陆续续的介绍了一些数据结构。
根据这些数据结构的实现方式,大体上可以分成两类:基于数组的实现和基于链表的实现。
这两种实现方式各有优缺点,说不上谁一定好谁一定不好,需要根据具体的使用场景进行选型。
基于数组的实现方式,这种方式允许我们通过下标在常数的时间内找到目标对象,但是如果需要对这种结构进行修改,无论是插入还是删除,都需要耗费线性的时间。
基于链表的实现方式,这种实现方式允许我们借助位置对象,在常数的时间内插入或者删除元素,但是如果想要找到某个元素,那么不得不耗费线性的时间。
基于上面这两点,我们可以知道,如果当前的场景是修改远大于查询,那么选择链表的数据结构会比较好。
反过来如果是查询远大于修改,那么选择数组的数据结构会比较好。
上面这段没看懂的,可以翻翻前面的文章然后去面壁思过了。
前面这些数据结构,元素之间都有一个自然的线型的关系,所以他们都都被称为线型结构。
而我们从本篇开始介绍的树就不一样了,树的元素之间并不会有直接的直接前驱或者直接后继这种关系,但是,只要是加上某种约束条件,也是可以在树的元素之间确定某种线型次序,所以树这种结构被称为半线型结构。
先来看下树结构长啥样:
树这种结构非常像一个树倒过来,所以因此而得名。
一些基础概念:
二叉树是树结构的一种树,也是我们接触最多使用最为广泛的一种树结构。
简单地理解,满足以下两个条件的树就是二叉树:
结果就是长这样的:
简单来讲就是每个节点下面最多只能有两个分叉,超过两个就不叫二叉树了,比如右边这个或许可以叫三叉树(这个没人定义过啊,我就这么一瞎说)?
二叉树的几个特性:
这两个特性的推导过程就不拆开讲了,基本上有初中数学基础的应该都能看得懂。
二叉树还可以接着分类,进而衍生出了满二叉树和完全二叉树。
满二叉树就是除了叶子结点,每个结点的度都为 2 。
简单来讲就是所有的节点都插满了,比如下面这样的:
满二叉树除了具有二叉树的特性外,还有一些单独的特性:
如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树。
这个意思就是完全二叉树是满二叉树的不完全体,只要最后一层满足了从左至右排布以及其余层次都是满二叉树,那么这个就叫做完全二叉树,比如下面这样的:
图 b 不是完全二叉树的原因就是因为它的最后一层并不是从左至右排布的,这个要清楚。
完全二叉树也有一些自己独特的性质,如:
⌊log2n⌋+1
。i>1
时,父亲结点为结点 [i/2]
。(i=1
时,表示的是根结点,无父亲结点)2*i>n
(总结点的个数) ,则结点 i 肯定没有左孩子(为叶子结点);否则其左孩子是结点 2*i
。2*i+1>n
,则结点 i 肯定没有右孩子;否则右孩子是结点 2*i+1
。本篇的内容就先到这里了,通过本篇的内容,应该对数和二叉树有一个初步的认知,能够清楚的了解树和二叉树的结构以及一些二叉树的基础的特性。
从下篇内容开始,我们介绍二叉树的一个关键知识点:实现与遍历。