二叉树
1 描述
二叉树一个节点有两个后继,称为左右孩子,左右孩子有序不能相互跌倒。二叉树又衍生出多种不同的形态,如红黑树、二叉排序树、B-树、AVL树等。(本节主要提供二叉树的算法实现,没有提供其原理和操作流程的讲解)
2 算法实现
2.1 节点设计
protected static class Node<E>{
public E element;
public Node<E> left;
public Node<E> right;
public Node<E> parent;
public Node(E element,Node<E> parent){
this.element = element;
this.parent = parent;
}
public boolean isLeaf(){
return left == null && right == null;
}
public boolean hasTwoChildren(){
if(left != null && right != null){
return true;
}
return false;
}
public boolean isLeftChild(){
return parent != null && this == parent.left;
}
public boolean isRightChild(){
return parent != null && this == parent.right;
}
/**
* 获取兄弟节点
* @return
*/
public Node<E> sibling(){
if(parent == null) return null;
if(isLeftChild()){
return parent.right;
}else{
return parent.left;
}
}
}
2.2 类设计
public class BinaryTree<E> implements TreePrinter<E> {
protected int size;
protected Node<E> root;
public BinaryTree(){
this.size = 0;
}
//获取二叉树大小(节点个数)
public int size() {
return size;
}
//二叉树是否为空
public boolean isEmpty() {
return root == null;
}
//清空二叉树
public void clear() {
root = null;
size = 0;
}
//构造一个二叉树节点
protected Node<E> createNode(E element,Node<E> parent){
return new Node<>(element,parent);
}
2.3 TreePrinter接口设计(遍历)
public interface TreePrinter<E> {
//先序
void preTraver(Visitor<E> visitor);
//中序
void inTraver(Visitor<E> visitor);
//后序
void postTraver(Visitor<E> visitor);
//层序
void levelTraver(Visitor<E> visitor);
//用栈先序
void preTraverWithStack(Visitor<E> visitor);
//用栈中序
void inTraverWithStack(Visitor<E> visitor);
//用栈后序
void postTraverWithStack(Visitor<E> visitor);
}
2.4 Visitor抽象类
public abstract class Visitor<E> {
boolean stop = false;
public abstract boolean visit(E e); //访问后是否停止遍历
}
2.5 TreePrinter接口的实现(遍历)
- 先序遍历
@Override
public void preTraver(Visitor<E> visitor) {
if(visitor == null){
return;
}
preTraver(root,visitor);
}
public void preTraver(Node<E> root,Visitor<E> visitor){
if(root == null || visitor.stop){
return;
}
//每次需要更新stop的状态,因为在某次visit访问后可能需要停止访问
visitor.stop = visitor.visit(root.element);
preTraver(root.left,visitor);
preTraver(root.right,visitor);
}
- 中序遍历
@Override
public void inTraver(Visitor<E> visitor) {
if(visitor == null){
return;
}
inTraver(root,visitor);
}
public void inTraver(Node<E> root,Visitor<E> visitor){
if(root == null || visitor.stop){
return;
}
inTraver(root.left,visitor);
visitor.stop = visitor.visit(root.element);
if(visitor.stop) return;
inTraver(root.right,visitor);
}
- 后序遍历
@Override
public void postTraver(Visitor<E> visitor) {
if(visitor == null){
return;
}
postTraver(root,visitor);
}
public void postTraver(Node<E> root,Visitor<E> visitor){
if(root == null || visitor.stop){
return;
}
postTraver(root.left,visitor);
postTraver(root.right,visitor);
visitor.stop = visitor.visit(root.element);
if(visitor.stop) return;
}
- 层序遍历
@Override
public void levelTraver(Visitor<E> visitor) {
if(root == null || visitor == null){
return;
}
Queue<Node<E>> que = new LinkedList<Node<E>>();
que.offer(root);
while(!que.isEmpty()){
Node<E> node = que.poll();
if(node == null){
break;
}
visitor.stop = visitor.visit(node.element);
if(visitor.stop){
return;
}
if(node.left != null) que.offer(node.left);
if(node.right != null) que.offer(node.right);
}
}
- 用栈先序遍历(利用栈的先进后出的思想,先遍历右子树后遍历左子树)
@Override
public void preTraverWithStack(Visitor<E> visitor) {
if(visitor == null || root == null){
return;
}
Stack<Node<E>> stack = new Stack<Node<E>>();
stack.push(root);
while(!stack.isEmpty()){
Node<E> node = stack.pop();
visitor.stop = visitor.visit(node.element);
if(visitor.stop){
return;
}
if(node.right != null) stack.push(node.right);
if(node.left != null) stack.push(node.left);
}
}
- 用栈中序遍历(如果左子树结点存在则一直压栈,然后访问自身,最后如果右子树结点存在则继续入栈,重复上述操作)
@Override
public void inTraverWithStack(Visitor<E> visitor) {
if(visitor == null || root == null){
return;
}
Stack<Node<E>> stack = new Stack<Node<E>>();
stack.push(root);
Node<E> p = root;
while(!stack.isEmpty()){
while(p.left != null){
stack.push(p.left);
p = p.left;
}
while(!stack.isEmpty()){
Node<E> node = stack.pop();
if(visitor.stop = visitor.visit(node.element)){
return;
}
if(node.right != null){
stack.push(node.right);
p = node.right;
break;
}
}
}
}
- 用栈后续遍历(后续遍历的结果逆序,发现其为先遍历右子树后遍历左子树的结果,因此只需要将4中的方法返回来,最后用栈逆序即可)
@Override
public void postTraverWithStack(Visitor<E> visitor) {
if(visitor == null || root == null){
return;
}
Stack<Node<E>> stack1 = new Stack<Node<E>>();
Stack<Node<E>> stack2 = new Stack<Node<E>>();
stack1.push(root);
while(!stack1.isEmpty()){
Node<E> node = stack1.pop();
stack2.push(node);
if(node.left != null)stack1.push(node.left);
if(node.right != null)stack1.push(node.right);
}
while(!stack2.isEmpty()){
if(visitor.stop = visitor.visit(stack2.pop().element)){
return;
}
}
}
2.6 其他常用的一些函数
- 将儿叉树翻转,左子树变又子树,右子树变左子树
public void reverse(){
reverse(root);
}
private void reverse(Node<E> root){
if(root == null){
return;
}
Node<E> tmp = root.left;
root.left = root.right;
root.right = tmp;
reverse(root.left);
reverse(root.right);
}
- 判定是否为完全二叉树
public boolean isComplite() {
if(root == null) return false;
Queue<Node<E>> que = new LinkedList<Node<E>>();
que.offer(root);
boolean leaf = false;
while(!que.isEmpty()){
Node<E> node = que.poll();
if(leaf & !node.isLeaf()){
return false;
}
if(node.left != null){
que.offer(node.left);
}else if(node.right != null){
return false;
}
if(node.right != null){
que.offer(node.right);
}else{
//left==null&&right==null或者 left!=null&&right==null的情况,后面的结点一定都是叶子结点
leaf = true;
}
}
return true;
}
- 递归法获取树的高度
public int hight(){
int hight = 0;
if(root == null){
return hight;
}
int levelSize = 1;
Queue<Node<E>> que = new LinkedList<Node<E>>();
que.offer(root);
while(!que.isEmpty()){
Node<E> node = que.poll();
levelSize --;
if(node.left != null) que.offer(node.left);
if(node.right != null) que.offer(node.right);
if(levelSize == 0){ //0表示已经访问完毕
levelSize = que.size();
hight ++;
}
}
return hight;
}