这些基础总是学了,长时间不看又忘了,这次写一篇文章记录下来,供日后回顾复习。
基本性质
首先是一个二叉树,数据结构:
|
|
作为搜索树的性质:左子树节点的值 <= 根节点的值 <= 右子树节点的值
遍历
中序遍历
对于二叉搜索树来说,中序遍历输出的就是从小到大的顺序。
|
|
CPP实现:
|
|
遍历的话,用递归的方式都很直观,但如果用迭代的方式,就稍微有些麻烦,借助栈可以记录之前遍历的状态,进而实现中序遍历:
|
|
CPP的实现,这里LeetCode上的题94. Binary Tree Inorder Traversal正好可以用以验证,就直接复制自己的答案了:
|
|
前序遍历
先输出根的值,再输出左右的值。
|
|
非递归可以用中序同样的方式来遍历,但是输出的时机不同应该就可以了。
144. Binary Tree Preorder Traversal
|
|
其实在遍历过程中时使用迭代时,同样有递归的思想在里边,将root调整到右节点上,便相当于把右子树当做一个新的二叉树来进行处理,这种思想在构造迭代的时候还是很有用的。
后序遍历
先输出孩子的值,再输出根的值。
|
|
非递归的算法自己还的确没有想出来,不过看了LeetCode上的Discussion:Preorder, Inorder, and Postorder Iteratively Summarization. 哇,的确没有注意到这一个性质。
前序遍历的时候,最先输出的是从根节点一直到最左叶节点的一列;而后序遍历的时候,最后输出的,就是从最右叶节点到根节点的最后一列!如图所示:
左为前序遍历,右为后序遍历,可以清楚的看到这个遍历顺序的性质!!
这样在实现的时候,便可以参照前序遍历,相反对称操作下,可以得到后序遍历的结果!
CPP的实现:LeetCode 145. Binary Tree Postorder Traversal
|
|
层级遍历
层级遍历的话,用一个队列来存储每个节点,当出队列时,把它的两个孩子入队列,直到队列为空。
|
|
CPP实现,LeetCode 102. Binary Tree Level Order Traversal
由于这道题要求区分每一层,所以用了两个不同的queue来记录每一层的节点,不过思想大致相同。
|
|
深度遍历
深度遍历是最普通最直观的二叉树遍历,其一般都结合具体的需求使用,比如查找,确定高度等等。
查找
利用搜索树的性质,查找很直观:
|
|
非递归的方式也很直观,因为上述的递归是尾递归:
|
|
插入
二叉搜索树的插入只是在查找的基础上做一点微小的改动。因为查找已经找到了对应的位置,只要在找到的位置上放上新的值即可。
删除
BST的删除需要考虑几个情况:
- 叶节点:直接删掉
- 只有一个子节点:删掉,子节点顶替删除的节点的位置
- 有两个孩子:删掉,用左子树的最大节点或右子树的最小节点顶替
描述起来很清楚,但是真正写起来,需要考虑具体的一些细节,比如根节点的情况,比如如何去做“顶替”这一操作
|
|
CPP实现,LeetCode 450. Delete Node in a BST
|
|
关于迭代的方式去实现删除的话,可能要比递归考虑更多的东西,但是想法的话还是很直观的,遍历查找要删除的节点时,始终记得记录其父节点。具体的删除过程与上述的大同小异,可能会有好多边界需要考虑。
建立
从数组
给定结构
确定一个二叉树,有两个要素,一个是二叉树的结构,另一个是各个节点的值,给定的数组确定了BST的值,但结构是未定的,根据给定的结构,可以构建一个确定的BST。
PAT 1099. Build A Binary Search Tree
根据二叉树的性质:中序遍历的输出顺序为升序。
先建立了二叉树结构之后,再进行中序遍历填入值就可以了。
以下为自己的代码,但是部分正确,有段错误!!!自己还没有找到错误所在。
|
|
平衡二叉树
如果限定是生成一个平衡二叉树的话,需要保证两边的相对均衡,将数组排序之后,每次取中点就可以做到:
LeetCode 108. Convert Sorted Array to Binary Search Tree
|
|
完全二叉树
完全二叉树的结构是确定的,所以仍然可以采用从给定结构构建二叉树的方法:
PAT 1064. Complete Binary Search Tree
我在PAT上的解答,部分正确!!有内存超限的错误!!!唔,怎么在PAT上做的这两道题,都有各种各样奇怪的错误,唉,有时间再看吧。
|
|
参考了网上某篇博文的这道题的答案,发现自己这样写有点傻,利用性质完全二叉树的相关性质,可以更加简便和巧妙的完成这道题。
因为最后要求层级遍历,而完全二叉树的层级遍历有个性质可以利用:
按层遍历的输出顺序,就是用表示完全二叉树的数组中的顺序
这看起来并没有什么,但和我们知道的一个完全二叉树非常熟悉的性质:
leftIndex = 2 x rootIndex, rightIndex = 2 x rootIndex + 1
这样一来,便可以用下表来定位某个元素,而用数组的数据结构存储二叉树,其实遍历的行为更加简单,比如本题中用到的中序遍历:
|
|
完整解答:
|
|
从序列
从前序中序构建
前序中找到第一个节点,即为根节点,在中序中找到,中序的左侧就是左子树,右侧为右子树;得到左右子树的节点数量之后,可以将前序数组剩下的元素分成左右子树,进而递归的做下去。
LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal
(发现自己之前CPP和Python都AC过,python似乎看起来更简洁,要不以后做OJ都用PY?)
|
|
从后序中序构建
与从前中构建很类似,做一个镜像即可:
|
|
前中转后与后中转前
有的时候,只要求通过前中序列写出后序,或者后中序列,写出前序,而不要求构建BST,这个时候可以更简便的完成而不用做多余的工作:
|
|
output:
|
|
参考:
http://blog.csdn.net/simple_the_best/article/details/52713491
http://www.cnblogs.com/jackwang822/p/4749965.html