二叉树说明
二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的。对于二叉树,有深度遍历和广度遍历,深度遍历有前序、中序以及后序三种遍历方法, 广度遍历即我们平常所说的层次遍历。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁,而对于广度遍历来说, 需要其他数据结构的支撑,比如堆了。
前序遍历
遍历方式:根结点 —> 左子树 —> 右子树
下面展示 代码片
.
// 二叉树结构实体
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
public TreeNode() {
}
TreeNode(int x) { val = x; }
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
/**
* 前序遍历(递归)
* @param root
* @param endList
* @return
*/
public static List<Integer> inorderTraversal5(TreeNode root,List<Integer> endList) {
if(null != root){
endList.add(root.val);
inorderTraversal(root.left,endList);
inorderTraversal(root.right,endList);
}
return endList;
}
/**
* 二叉树前序遍历(迭代)
* @param root
* @param endList
* @return
*/
public static List<Integer> inorderTraversal2(TreeNode root,List<Integer> endList) {
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode pNode = root;
while (null != pNode || !stack.isEmpty()){
if(pNode != null){
endList.add(pNode.val);
stack.push(pNode);
pNode = pNode.left;
}else {
TreeNode node = stack.pop();
pNode = node.right;
}
}
return endList;
}
中序遍历
遍历方式:左子树—> 根结点 —> 右子树
下面展示 代码片
.
/**
* 中序遍历(递归)
* @param root
* @param endList
* @return
*/
public static List<Integer> inorderTraversal(TreeNode root,List<Integer> endList) {
if(null != root){
inorderTraversal(root.left,endList);
endList.add(root.val);
inorderTraversal(root.right,endList);
}
return endList;
}
/**
* 二叉树中序遍历(迭代)
* @param root
* @param endList
* @return
*/
public static List<Integer> inorderTraversal1(TreeNode root,List<Integer> endList) {
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode pNode = root;
while (null != pNode || !stack.isEmpty()){
if(pNode != null){
stack.push(pNode);
pNode = pNode.left;
}else {
TreeNode node = stack.pop();
endList.add(node.val);
pNode = node.right;
}
}
return endList;
}
后序遍历
遍历方式:左子树 —> 右子树 —> 根结点
下面展示 代码片
.
/**
* 后序遍历
* @param root
* @param endList
* @return
*/
public static List<Integer> inorderTraversal4(TreeNode root,List<Integer> endList) {
if(null != root){
inorderTraversal(root.left,endList);
inorderTraversal(root.right,endList);
endList.add(root.val);
}
return endList;
}
/**
* 二叉树后序遍历
* @param root
* @param endList
* @return
*/
public static List<Integer> inorderTraversal3(TreeNode root,List<Integer> endList) {
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode pNode = root;
TreeNode pre = null;
while (null != pNode || !stack.isEmpty()){
while (null != pNode){
stack.push(pNode);
pNode = pNode.left;
}
if(!stack.isEmpty()){
pNode = stack.pop();
if(pNode.right == null || pre == pNode.right){
endList.add(pNode.val);
pre = pNode;
pNode = null;
}else {
stack.push(pNode);
pNode = pNode.right;
}
}
}
return endList;
}
总结
1.递归的缺点:
操作耗时,因为牵涉到大量的入栈出栈操作;
有可能导致线程栈溢出,因为递归调用占用了线程栈很大的空间。
2.递归转非递归
首先,我们要自己模拟一个栈;
然后,找到边界条件;
最后,朝着边界条件的方向缩小问题规模;