(一)二叉树的基本实现
1.二叉树的定义:
import java.util.*;
//BST支持泛型,因为每个节点都大于它的左孩子,小于它的右孩子,所以保存的元素得要是可比较的
public class BST<T extends Comparable> {
//定义内部节点类
private class Node{
public T e;
public Node left;
public Node right;
//节点类的构造函数
public Node(T e){
this.e=e;
left=null;
right=null;
}
}
//定义根节点和二叉树中节点个数
private Node root;
private int size;
//二叉树的构造函数
public BST(){
root = null;
size = 0;
}
//取得二叉树中节点个数
public int size(){
return size;
}
//判断二叉树是否为空
public boolean isEmpty(){
return size == 0;
}
//向二叉树中添加元素,调用重载的add,返回添加元素后的根节点
public void add(T e){
root = add(root,e);
}
//运用递归,添加新元素
private Node add(Node node,T e){
//递归终止条件:找到了对应的空节点就把新元素放在此空节点处
if(node == null){
size ++;
return new Node(e);
}
if(e.compareTo(node.e) < 0)
node.left = add(node.left,e);
else if(e.compareTo(node.e) > 0)
node.right = add(node.right,e);
return node;
}
//判断二叉树中是否含有指定元素
public boolean contains(T e){
return contains(root,e);
}
//运用递归,判断是否有节点的值与给定元素相等
private boolean contains(Node node,T e){
if(node == null)
return false;
if(e.compareTo(node.e) == 0)
return true;
else if(e.compareTo(node.e) < 0)
return contains(node.left,e);
else
return contains(node.right,e);
}
//前序遍历:中、左、右
public void preOrder(){
preOrder(root);
}
private void preOrder(Node node){
if(node == null)
return ;
System.out.println(node.e);
preOrder(node.left);
preOrder(node.right);
}
//不使用递归的前序遍历
public void preOrderNR(){
Stack<Node> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
Node cur = stack.pop();
System.out.println(cur.e);
if(cur.right !=null)
stack.push(cur.right);
if(cur.left !=null)
stack.push(cur.left);
}
}
//中序遍历
public void inOrder(){
inOrder(root);
}
private void inOrder(Node node){
if(node == null)
return;
inOrder(node.left);
System.out.println(node.e);
inOrder(node.right);
}
//后序遍历
public void postOrder(){
postOrder(root);
}
private void postOrder(Node node){
if(node == null)
return ;
postOrder(node.left);
postOrder(node.right);
System.out.println(node.e);
}
//广度优先遍历
public void levelOrder(){
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
Node cur = queue.remove();
System.out.println(cur.e);
if(cur.left != null)
queue.add(cur.left);
if(cur.right != null)
queue.add(cur.right);
}
}
//找到二叉树中的最小元素
public T minimum(){
if(size == 0)
throw new IllegalArgumentException("BST is empty");
return minimum(root).e;
}
private Node minimum(Node node){
if(node.left == null)
return node;
return minimum(node.left);
}
//找到二叉树中最大的元素
public T maximum(){
if(size == 0)
throw new IllegalArgumentException("BST is empty");
return maximum(root).e;
}
private Node maximum(Node node){
if(node.right == null)
return node;
return maximum(node.right);
}
//删除最小节点
public T removeMin(){
T ret = minimum();
root = removeMin(root);
return ret;
}
private Node removeMin(Node node){
if(node.left == null){
Node retNode = node.right;
node.right = null;
size --;
return retNode;
}
node.left = removeMin(node.left);
return node;
}
//删除最大节点
public T removeMax(){
T ret = maximum();
root = removeMax(root);
return ret;
}
private Node removeMax(Node node){
if(node.right == null){
Node retNode = node.left;
node.left = null;
size --;
return retNode;
}
node.right = removeMax(node.right);
return node;
}
//删除指定元素的节点
public void remove(T e){
root = remove(root,e);
}
private Node remove(Node node, T e){
if(node == null)
return null;
if(e.compareTo(node.e) < 0){
node.left = remove(node.left,e);
return node;
}
else if(e.compareTo(node.e) > 0){
node.right = remove(node.right,e);
return node;
}
else{
if(node.left == null){
Node rightNode = node.right;
node.right = null;
size --;
return rightNode;
}
if(node.right == null){
Node leftNode = node.left;
node.left = null;
size --;
return leftNode;
}
//当要删除的节点有左右孩子时,找到它的右子树中比它大的最小元素,用这个后继元素替代删除的元素
Node successor = minimum(node.right);
successor.right = removeMin(node.right);
successor.left = node.left;
node.left = node.right = null;
return successor;
}
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
generateBSTString(root,0,res);
return res.toString();
}
private void generateBSTString(Node node,int depth,StringBuilder res){
if(node == null){
res.append(generateDepthString(depth) + "null\n");
return ;
}
res.append(generateDepthString(depth) + node.e +"\n");
generateBSTString(node.left,depth + 1,res);
generateBSTString(node.right,depth + 1,res);
}
private String generateDepthString(int depth){
StringBuilder res = new StringBuilder();
for(int i=0;i < depth;i ++){
res.append("--");
}
return res.toString();
}
}
2.二叉树的特点:
(1)二叉树的每个节点都有两个孩子,一个父亲
(2)二叉树具有天然的递归结构
(3)二叉树每个节点的左、右子树也是二叉树
(4)一个节点也是二叉树,一个空也是二叉树
(5)每个节点的值都大于其左子树所有节点的值,小于其右子树所有节点的值
(6)存储的元素必须有可比较性
3.二叉树的几种遍历方式:
(1)前序遍历:最自然,最常用的遍历方式
先访问根节点,再访问左子树,最后访问右子树
(2)中序遍历:遍历的结果是对二叉树中元素排序的形式
先左再中再右
(3)后序遍历:应用:释放内存
先左再右再中
(4)非递归的前序遍历:
节点自身先入栈,右孩子再入栈,左孩子最后入栈
(5)非递归的层序遍历:
节点自身先入队,左孩子再入队,右孩子最后入队
4.广度优先遍历的优点:
(1)更快找到解
(2)帮助解决算法设计中最短路径问题
5.扩展内容:
(1)floor:小于给定元素的最大元素;celi:大于给定元素的最小元素
(2)rank:元素的名次;select:名次对应的元素
(3)维护size:每个节点都保存它子树中节点个数
(4)维护depth:每个节点都保存它所处的深度
(5)支持重复元素:
要么左子树所有元素小于等于根节点,右子树所有元素大于根节点
要么左子树所有元素小于根节点,右子树所有元素大于等于根节点