数据结构与算法——二叉树建立、递归遍历、非递归遍历(栈回溯)
二叉树的建立与遍历
定义节点 Tree Node
public class TreeNode {
Integer data;
TreeNode leftNode;
TreeNode rightNode;
public TreeNode(Integer data) {
this.data = data;
}
}
二叉树的建立与遍历
/**
* 构建二叉树
*/
public class BinaryTree {
/**
* 利用递归的思路前序构造二叉树
* List没有removeFirst removeLast
* LinkedList具有
*/
public static TreeNode createBinaryTree(LinkedList<Integer> treeList){
//需要构建的列表不为空
if (treeList.isEmpty()||treeList==null){
return null;
}
//声明一个节点
TreeNode node = null;
//从列表依次取出元素
Integer data = treeList.removeFirst();
if (data!=null){
//构造一个节点的值
node = new TreeNode(data);
//构造一个节点的左节点,creatBinaryTree方法本身为取值并构造TreeNode,因而这里实现了自身的调用,实现了递归
node.leftNode = createBinaryTree(treeList);
node.rightNode = createBinaryTree(treeList);
}
return node;
}
/**
* 实现前序遍历
*/
public static void prefixOut(TreeNode node){
if (node == null){
return;
}
System.out.print(node.data);
prefixOut(node.leftNode);
prefixOut(node.rightNode);
}
/**
* 实现中序遍历
*/
public static void infixOut(TreeNode node){
if (node == null){
return;
}
infixOut(node.leftNode);
System.out.print(node.data);
infixOut(node.rightNode);
}
/**
* 实现后续遍历
*/
public static void suffixOut(TreeNode node){
if (node == null){
return;
}
suffixOut(node.leftNode);
suffixOut(node.rightNode);
System.out.print(node.data);
}
/**
* 二叉树非递归实现前序遍历
* 利用栈回溯的性质,从根节点开始入栈,左节点元素依次入栈,
* 当左节点某个元素没有子节点时候出栈,这样可以访问其父节点的右子节点,
* 因为父节点在能访问了左右节点已经无用,所以出栈,右子节点继续按之前步骤进行,
* 直到栈空,遍历完所有的元素
*/
public static void stackPrefixOut(TreeNode node){
Stack<TreeNode> stack = new Stack<>();
TreeNode treeNode = node;
while (treeNode != null || !stack.empty()){
//遍历访问左节点,入栈
while (treeNode!=null){
System.out.print(treeNode.data);
stack.push(treeNode);
treeNode = treeNode.leftNode;
}
//如果没有左节点,则弹出栈顶节点,访问其右节点
if (!stack.empty()){
treeNode = stack.pop();
treeNode = treeNode.rightNode;
}
}
}
/**
* 非递归中序遍历
*
*/
public static void stackInfixOut(TreeNode node){
Stack<TreeNode> stack = new Stack<>();
TreeNode treeNode = node;
while (treeNode != null || !stack.empty()){
//遍历访问左节点,入栈
while (treeNode!=null){
stack.push(treeNode);
treeNode = treeNode.leftNode;
}
//如果左节点为空,则出栈,访问节点数据,向右节点继续访问
//如果右节点为空就会出栈,访问的即是上一个节点
if (!stack.empty()){
treeNode = stack.pop();
System.out.print(treeNode.data);
treeNode = treeNode.rightNode;
}
}
}
/**
* 非递归后序遍历:
* 不同前两种情况,后序遍历需要保留上一次访问的节点,
* 同时对当前节点右子节点做出判断
* 视频讲解:
* https://www.bilibili.com/video/BV18i4y1Z7am?spm_id_from=333.880.my_history.page.click&vd_source=c14320ad01bf4cf70bfe310257773013
*/
public static void stackSuffixOut(TreeNode node){
Stack<TreeNode> stack = new Stack<>();
TreeNode curNode = node;//定义当前节点
TreeNode preNode = node;//保留上一个访问的节点
while (curNode != null || !stack.empty()){
//遍历访问左节点,入栈
while (curNode!=null){
stack.push(curNode);
curNode = curNode.leftNode;
}
//当左节点为空时,取栈顶元素(此时栈顶元素为当前)
curNode = stack.peek();
//访问右节点如果不为null,继续访问右节点
if (curNode.rightNode != null && curNode.rightNode != preNode){ //(1)
curNode = curNode.rightNode;
}else{
//右节点为空 访问当前节点数据
System.out.print(curNode.data);
preNode = curNode; //记录当前访问的节点,防止在回溯的过程中即(1)中出现判断失误导致回溯失败
curNode = null; //当前节点设置为null防止重复访问
stack.pop();
}
}
}
}