二叉树
public interface BTree<E> {
/**
* 树中的节点个数
* @return
*/
int size();
/**
* 树是否为空
* @return
*/
boolean isEmpty();
/**
* 前序遍历
* 中左右
*/
void preOrder();
/**
* 中序遍历
* 左中右
*/
void inOrder();
/**
* 后续遍历
* 左右中
*/
void postOrder();
/**
* 层序遍历
*/
void levelOrder();
/**
* A
* / \
* B C
* / \ / \
* D E F G
*
* 前序遍历结果:A-B-D-E-C-F-G
* 中序遍历结果:D-B-E-A-F-C-G
* 后序遍历结果:D-E-B-F-G-C-A
* 层序遍历结果:A-B-C-D-E-F-G
*/
}
基于数组:顺序二叉树
基于链表:链式二叉树
顺序二叉树
- 根节点存储在
index = 1
- 某节点存储在
index = i
,那么其左子节点将存储在index = 2*i
,其右子节点将存储在index = 2*i + 1
,其父节点将存储在index = i/2
import java.util.LinkedList;
import java.util.Queue;
public class ArrayBTree<E> implements BTree<E> {
private E[] array;
/**
* 暂时不考虑扩展性,这里基于数组的二叉树是配角
* 等它成主角了再改
*/
public ArrayBTree() {
array = (E[]) new Object[10];
}
public ArrayBTree<String> testBTree() {
/**
* A
* B C
* D E F G
*/
ArrayBTree<String> btree = new ArrayBTree<>();
String[] arr = {"A", "B", "C", "D", "E", "F", "G"};
for (int i = 0; i < arr.length; i++) {
Object[] array = btree.array;
array[i + 1] = arr[i];
}
return btree;
}
@Override
public int size() {
return array.length - 1;
}
@Override
public boolean isEmpty() {
return size() == 0;
}
private int parentIndex(int sonIndex) {
return sonIndex >> 1;
}
private int leftIndex(int parentIndex) {
return parentIndex << 1;
}
private int rightIndex(int parentIndex) {
return leftIndex(parentIndex) + 1;
}
@Override
public void preOrder() {
preOrder(1);
}
private void preOrder(int index) {
if (index > size() || array[index] == null) {
return;
}
int left = leftIndex(index);
int right = rightIndex(index);
System.out.println(array[index]);
preOrder(left);
preOrder(right);
}
@Override
public void inOrder() {
inOrder(1);
}
private void inOrder(int index) {
if (index > size() || array[index] == null) {
return;
}
int left = leftIndex(index);
int right = rightIndex(index);
inOrder(left);
System.out.println(array[index]);
inOrder(right);
}
@Override
public void postOrder() {
postOrder(1);
}
private void postOrder(int index) {
if (index > size() || array[index] == null) {
return;
}
int left = leftIndex(index);
int right = rightIndex(index);
postOrder(left);
postOrder(right);
System.out.println(array[index]);
}
/**
* 层序遍历
*/
@Override
public void levelOrder() {
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
while (!queue.isEmpty()) {
Integer poll = queue.poll();
System.out.println(array[poll]);
int left = leftIndex(poll);
if (left < array.length && array[left] != null) {
queue.add(left);
}
int right = rightIndex(poll);
if (right < array.length && array[right] != null) {
queue.add(right);
}
}
}
public static void main(String[] args) {
ArrayBTree<String> bTree = new ArrayBTree<>();
bTree = bTree.testBTree();
System.out.println("preOrder");
bTree.preOrder();
System.out.println("inOrder");
bTree.inOrder();
System.out.println("postOrder");
bTree.postOrder();
System.out.println("levelOrder");
bTree.levelOrder();
}
}
链式二叉树
import java.util.LinkedList;
import java.util.Queue;
public class LinkedBTree<E> implements BTree<E> {
private class Node<E> {
public E val;
public Node<E> left, right;
public Node(E e) {
val = e;
left = right = null;
}
}
private Node<E> root;
private int size;
public LinkedBTree() {
root = null;
size = 0;
}
public LinkedBTree<String> testBTree() {
/**
* A
* B C
* D E F G
*/
LinkedBTree<String> btree = new LinkedBTree<>();
btree.root = btree.new Node<String>("A");
btree.root.left = btree.new Node<String>("B");
btree.root.right = btree.new Node<String>("C");
btree.root.left.left = btree.new Node<String>("D");
btree.root.left.right = btree.new Node<String>("E");
btree.root.right.left = btree.new Node<String>("F");
btree.root.right.right = btree.new Node<String>("G");
btree.size = 7;
return btree;
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public void preOrder() {
preOrder(root);
}
private void preOrder(Node<E> node) {
if (node == null) {
return;
}
System.out.println(node.val);
preOrder(node.left);
preOrder(node.right);
}
@Override
public void inOrder() {
inOrder(root);
}
private void inOrder(Node<E> node) {
if (node == null) {
return;
}
inOrder(node.left);
System.out.println(node.val);
inOrder(node.right);
}
@Override
public void postOrder() {
postOrder(root);
}
private void postOrder(Node<E> node) {
if (node == null) {
return;
}
postOrder(node.left);
postOrder(node.right);
System.out.println(node.val);
}
/**
* 层序遍历
*/
@Override
public void levelOrder() {
Queue<Node<E>> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
Node<E> poll = queue.poll();
System.out.println(poll.val);
if (poll.left != null) {
queue.add(poll.left);
}
if (poll.right != null) {
queue.add(poll.right);
}
}
}
public static void main(String[] args) {
LinkedBTree<String> bTree = new LinkedBTree<>();
bTree = bTree.testBTree();
System.out.println("preOrder");
bTree.preOrder();
System.out.println("inOrder");
bTree.inOrder();
System.out.println("postOrder");
bTree.postOrder();
System.out.println("levelOrder");
bTree.levelOrder();
}
}
前序遍历、中序遍历、后续遍历中的前中后是针对当前节点而言的,当前节点先输出就是前序遍历(中左右),当前节点后输出就是后续遍历(左右中)
前序、中序、后序遍历的非递归实现
这里的非递归实现针对底层是链表的二叉树
前序遍历
/**
* 前序遍历非递归实现
*/
public void preOrderNonRecursive() {
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
Node cur = stack.pop();
System.out.println(cur.val);
if (cur.right != null) {
stack.push(cur.right);
}
if (cur.left != null) {
stack.push(cur.left);
}
}
}
中序遍历
/**
* 中序遍历非递归实现
*/
public void inOrderNonRecursive() {
Stack<Node> stack = new Stack<>();
Node cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
if (!stack.isEmpty()) {
Node pop = stack.pop();
System.out.println(pop.val);
cur = pop.right;
}
}
}
上述代码等价于
/**
* 中序遍历非递归实现
*/
public void inOrderNonRecursive() {
Stack<Node> stack = new Stack<>();
Node cur = root;
while (cur != null || !stack.isEmpty()) {
if (cur != null) {
stack.push(cur);
cur = cur.left;
} else {
Node pop = stack.pop();
System.out.println(pop.val);
cur = pop.right;
}
}
}
后序遍历
/**
* 后序遍历非递归实现
*/
public void postOrderNonRecursive() {
Stack<Node> stack = new Stack<>();
Set<Node> rightFlags = new HashSet<>();
Node cur = root;
while (cur != null || !stack.isEmpty()) {
while (cur != null) {
stack.push(cur);
cur = cur.left;
}
if (!stack.isEmpty()) {
Node pop = stack.peek();
if (rightFlags.contains(pop)) {
// 如果访问过当前节点的右子树,直接打印
stack.pop();
System.out.println(pop.val);
rightFlags.remove(pop);
} else {
// 如果没访问过当前节点的右子树,将cur赋值给右子树
rightFlags.add(pop);
cur = pop.right;
}
}
}
}
双栈法
/**
* 后序遍历非递归实现
*/
public void postOrderNonRecursive() {
Stack<Node> stack1 = new Stack<>();
Stack<Node> stack2 = new Stack<>();
stack1.push(root);
while (!stack1.isEmpty()) {
Node pop = stack1.pop();
// 入stack2
stack2.push(pop);
// 先左
if (pop.left != null) {
stack1.push(pop.left);
}
// 再右
if (pop.right != null) {
stack1.push(pop.right);
}
// 这样等到左右入stack2时,就成了“中-右-左”
// 最终出stack2时就成了“左-右-中”,即后序遍历
}
while (!stack2.isEmpty()) {
System.out.println(stack2.pop().val);
}
}
令我眼前一亮的前中后序非递归遍历的实现
定义一个指令类
class Msg {
static final boolean GO = false;
static final boolean PRINT = true;
boolean go; // false表示访问,true表示打印
Node node;
Msg(boolean go, Node node) {
this.go = go;
this.node = node;
}
}
前序
public void preOrderNonRecursive2() {
LinkedList<Msg> stack = new LinkedList<>();
stack.push(new Msg(Msg.GO, root));
while (!stack.isEmpty()) {
Msg pop = stack.pop();
if (Msg.PRINT == pop.go) {
System.out.println(pop.node.val);
} else {
// 以右左中入栈
if (pop.node.right != null) {
stack.push(new Msg(Msg.GO, pop.node.right));
}
if (pop.node.left != null) {
stack.push(new Msg(Msg.GO, pop.node.left));
}
stack.push(new Msg(Msg.PRINT, pop.node));
}
}
}
中序
public void inOrderNonRecursive2() {
LinkedList<Msg> stack = new LinkedList<>();
stack.push(new Msg(Msg.GO, root));
while (!stack.isEmpty()) {
Msg pop = stack.pop();
if (Msg.PRINT == pop.go) {
System.out.println(pop.node.val);
} else {
// 以右中左入栈
if (pop.node.right != null) {
stack.push(new Msg(Msg.GO, pop.node.right));
}
stack.push(new Msg(Msg.PRINT, pop.node));
if (pop.node.left != null) {
stack.push(new Msg(Msg.GO, pop.node.left));
}
}
}
}
后序
public void postOrderNonRecursive2() {
LinkedList<Msg> stack = new LinkedList<>();
stack.push(new Msg(Msg.GO, root));
while (!stack.isEmpty()) {
Msg pop = stack.pop();
if (Msg.PRINT == pop.go) {
System.out.println(pop.node.val);
} else {
// 以中右左入栈
stack.push(new Msg(Msg.PRINT, pop.node));
if (pop.node.right != null) {
stack.push(new Msg(Msg.GO, pop.node.right));
}
if (pop.node.left != null) {
stack.push(new Msg(Msg.GO, pop.node.left));
}
}
}
}