树的建立
首先,先建立起二叉树的类:
public abstract class BinaryTree {
public class TreeNode{
int data;
TreeNode left;
TreeNode right;
public TreeNode(int data){
this.data = data;
}
}
protected TreeNode root;
public BinaryTree() {
root = null;
}
public boolean empty() {
return root == null;
}
abstract public boolean insert(int data);
public int height() {
return height(root);
}
public static int height(TreeNode root) {
if(root == null) return 0;
return Math.max(height(root.left), height(root.right)) + 1;
}
}
然后是二叉搜索树的类,继承自BinaryTree ,实现了insert方法,新增了搜索的方法:
public class SearchTree extends BinaryTree {
public SearchTree() {
super();
}
@Override
public boolean insert(int data) {
if (root == null) {
root = new TreeNode(data);
return true;
}
TreeNode root = this.root;
TreeNode temp = root;
while(root != null) {
temp = root;
if(root.data < data) root = root.right;
else if(root.data > data) root = root.left;
else return false;
}
if(temp.data < data) temp.right = new TreeNode(data);
if(temp.data > data) temp.left = new TreeNode(data);
return true;
}
public TreeNode treeSearch(int target) {
return searchForNode1(root, target);
// return searchForNode2(root, target);
}
public TreeNode searchForNode1(TreeNode root, int target) {
if (root == null || root.data == target) {
return root;
} else if (root.data < target) {
return searchForNode1(root.right, target);
} else {
return searchForNode1(root.left, target);
}
}
public TreeNode searchForNode2(TreeNode root, int target) {
while(root != null && root.data != target) {
if(root.data < target) root = root.right;
else root = root.left;
}
return root;
}
}
前序遍历
接下来,在BinaryTree类中增加几个遍历的方法。
首先是前序遍历。
方法一:递归
这比较容易实现,逻辑也比较清晰。
方法二:使用栈
(1) 先把根节点入栈(如果不为空的话);
(2) 访问栈顶,将栈顶弹出,并将其右、左子节点(如果有的话)依次放进栈中;
(3) 重复(2)直到栈为空。
方法三:使用栈
先访问根节点,再访问所有左孩子,直到左孩子为空,反过来访问其右孩子。这个思路比较不好理解,但是却比较通用,下面中序、后序遍历都可以使用这个思路,只需要把访问节点的代码换个位置就可以。
前序遍历代码如下:
public void preOrder() {
// 方法一:递归
preOrderTraverseRecursive(root);
System.out.println();
// 方法二:
Stack<TreeNode> stack = new Stack<>();
if (root != null) {
stack.push(root);
}
while(!stack.empty()) {
TreeNode top = stack.pop();
System.out.print(top.data + ",");
if (top.right != null) {
stack.push(top.right);
}
if (top.left != null) {
stack.push(top.left);
}
}
System.out.println();
// 方法三:
// Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
while(node != null || !stack.empty()) {
if(node != null) {
System.out.print(node.data + ",");
stack.push(node);
node = node.left;
} else {
node = stack.pop();
node = node.right;
}
}
}
public static void preOrderTraverseRecursive(TreeNode root) {
if (root != null) {
System.out.print(root.data + ",");
preOrderTraverseRecursive(root.left);
preOrderTraverseRecursive(root.right);
}
}
中序遍历
方法跟前序遍历的方法一、三类似,只不过在方法三中,这里改为在出栈时才访问节点。
public void inOrder() {
// 方法一:递归
inOrderTraverseRecursive(root);
System.out.println();
// 方法二:
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
while(node != null || !stack.empty()) {
if(node != null) {
stack.push(node);
node = node.left;
} else {
node = stack.pop();
System.out.print(node.data + ",");
node = node.right;
}
}
}
public static void inOrderTraverseRecursive(TreeNode root) {
if (root != null) {
inOrderTraverseRecursive(root.left);
System.out.print(root.data + ",");
inOrderTraverseRecursive(root.right);
}
}
后序遍历
与中序遍历的两个方法类似。不过这里比较特殊,多用一个栈来存储数据。其实看这段代码,跟前序遍历很像,不同的是这里先访问右子节点再访问左子节点,而且多了一个栈用来存储逆后序遍历的结果,即反过来输出之后,就是后序遍历的结果。
public void postOrder() {
// 方法一:递归
postOrderTraverseRecursive(root);
System.out.println();
// 方法二:
Stack<TreeNode> stack = new Stack<>();
Stack<TreeNode> out = new Stack<>(); // 存储逆后序遍历的结果
TreeNode node = root;
while(node != null || !stack.empty()) {
if(node != null) {
stack.push(node);
out.push(node);
node = node.right;
} else {
node = stack.pop();
node = node.left;
}
}
while(!out.empty()) {
System.out.print(out.pop().data + ",");
}
}
public static void postOrderTraverseRecursive(TreeNode root) {
if (root != null) {
postOrderTraverseRecursive(root.left);
postOrderTraverseRecursive(root.right);
System.out.print(root.data + ",");
}
}
层次遍历
层次遍历就是在树的每一层(从上到下)从左到右访问。使用到了队列,步骤如下:
(1) 先把根节点入队列(如果不为的话);
(2) 访问队首,将其弹出,并将其左、右子节点(如果有的话)依次进入队列;
(3) 重复(2)直到队列为空。
public void levelTraverse() {
LinkedList<TreeNode> queue = new LinkedList<>();
if (root != null) {
queue.offer(root);
}
while(!queue.isEmpty()) {
TreeNode top = queue.poll();
System.out.print(top.data + ",");
if (top.left != null) {
queue.offer(top.left);
}
if (top.right != null) {
queue.offer(top.right);
}
}
}
以上的前序、中序、后序遍历其实就是树的深度优先搜索;
层次遍历就是树的宽度(广度)优先搜索。
相关阅读:
根据前序和中序(后序和中序)遍历构造树