二叉搜索树
代码实现:
package com.cdcas.day10;
public class BinaryTree <Key extends Comparable<Key>,Value>{
//记录根结点
private Node<Key,Value> root;
//记录树中元素的个数
private int N;
private static class Node<Key,Value>{
//存储键
public Key key;
//存键值
private Value value;
//记录左子结点
public Node<Key,Value> left;
//记录右子结点
public Node<Key,Value> right;
public Node(Key key, Value value, Node<Key,Value> left, Node<Key,Value> right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
}
//获取树中元素的个数
public int size(){
return N;
}
//向树中元素Key,Value
public void put(Key key,Value value){
root=put(root,key,value);
}
//向指定的树node中添加Key-Value,并返回添加元素后新的树
private Node<Key,Value> put(Node<Key,Value> node,Key key,Value value){
//如果node子树为空
if (node==null){
N++;
return new Node<>(key,value,null,null);
}
//如果不为空
//比较node结点的键和key的大小
int cmp= key.compareTo(node.key);
if (cmp>0){
//如果key大于node结点的键,则继续找node结点的右子树
node.right=put(node.right,key,value);
}else if (cmp<0){
//如果key小于node结点的键,则继续找node结点的左子树
node.left=put(node.left,key,value);
}else {
//如果key等于node结点的键,则替换x结点的值为value即可
node.value=value;
}
return node;
}
//查询树中指定key对应的value
public Value get(Key key){
return get(root,key);
}
//指定的树node中,查找key对应的值
public Value get(Node<Key,Value> node,Key key){
//node树为null
if (node==null){
return null;
}
//node树不为null
//比较key和node结点的键的大小
int cmp= key.compareTo(node.key);
if (cmp>0){
//如果key大于node结点的键,则继续找x结点的右子树
return get(node.right,key);
}else if (cmp<0){
//如果key小于node结点的键,则继续找x结点的左子树
return get(node.left,key);
}else {
//如果key等于node结点的键,就找到了键为Key的结点,只需要返回node结点的值即可
return node.value;
}
}
//删除树中key对应的value
public void delete(Key key){
delete(root,key);
}
//删除指定树node中的key对应的value,并返回删除后的新树
public Node<Key,Value> delete(Node<Key,Value> node,Key key){
//node树为null
if (node==null){
return null;
}
//node树不为null
int cmp= key.compareTo(node.key);
if (cmp>0){
//如果key大于node结点的键,则继续找node结点的右子树
node.right=delete(node.right,key);
}else if (cmp<0){
//如果key小于node结点的键,则继续找node结点的左子树
node.left=delete(node.left,key);
}else {
N--;
//如果key等于node结点的键,完成真正的删除结点动作,要删除的结点就是node
//找到右子树中最小的结点
if (node.right==null){
return node.left;
}
if (node.left==null) {
return node.right;
}
Node<Key,Value> minNode=node.right;
while (minNode.left!=null){
minNode=minNode.left;
}
//删除右子树中最小对的结点
Node<Key,Value> n=node.right;
while (n.left!=null){
if (n.left.left==null){
n.left=null;
}else {
n=n.left;
}
}
//让node结点左子树成为minNode的左子树
minNode.left=node.left;
//让node结点右子树成为minNode的右子树
minNode.right=node.right;
//让node结点的父结点指向minNode
node=minNode;
}
return node;
}
//查找二叉树中最小的键
public Key min(){
Node<Key,Value> node=root;
while (node.left!=null){
node=node.left;
}
return node.key;
}
//查找二叉树中最大的键
public Key max(){
Node<Key,Value> node=root;
while (node.right!=null){
node=node.right;
}
return node.key;
}
}
二叉树的基础遍历
很多情况下,我们可能需要像遍历数组一样,遍历树,从而拿出树中存储的每一个元素,由于树状结构和线性结构不一样,它没有办法从头开始依次向后遍历,所以存在如何遍历,也就是按照什么样的搜索路径进行遍历的问题。
可以把二叉树的遍历分为以下三种方式:
-
前序遍历:
先访问根结点,然后再访问左子树,最后访问右子树
-
中序遍历:
先访问左子树,中间访问根节点,最后访问右子树
3.后序遍历:
先访问左子树,再访问右子树,最后访问根结点
前序遍历的实现:
//获取整个树中所有的键
public Queue<Key> preErgodic(){
Queue<Key> queue = new Queue<>();
preErgodic(root,queue);
return queue;
}
//获取指定树node的所有键并放到队列中
private void preErgodic(Node<Key,Value> node,Queue<Key> queue){
if (node==null){
return;
}
//把node结点的Key放入到Keys中
queue.enqueue(node.key);
//递归遍历node结点的左子树
if (node.left!=null){
preErgodic(node.left,queue);
}
//递归遍历node结点的右子树
if (node.right!=null){
preErgodic(node.right,queue);
}
}
中序遍历的代码实现:
//使用中序遍历,获取整个树中的所有键
public Queue<Key> midErgodic(){
Queue<Key> queue=new Queue<>();
//先遍历左子树
midErgodic(root,queue);
return queue;
}
//获取指定树node的所有键并放到队列中
private void midErgodic(Node<Key,Value> node,Queue<Key> queue){
if (node==null){
return ;
}
//先把node结点的左子树key存放到queue中
if (node.left!=null){
midErgodic(node.left,queue);
}
//把当前结点node的键放到queue中
queue.enqueue(node.key);
//在递归,把右子树中的键放到queue中
if (node.right!=null){
midErgodic(node.right,queue);
}
}
后序遍历的代码实现
//使用后序遍历,获取整个树中的所有键
public Queue<Key> afterErgodic(){
Queue<Key> queue=new Queue<>();
afterErgodic(root,queue);
return queue;
}
public void afterErgodic(Node<Key,Value> node,Queue<Key> queue){
if (node==null){
return;
}
//1.找到当前结点的左子树,如果不为空,遍历左子树
if (node.left!=null){
afterErgodic(node.left,queue);
}
//
if (node.right!=null){
afterErgodic(node.right,queue);
}
queue.enqueue(node.key);
}
层序遍历代码实现
//使用层序遍历,获取整个树中所有的键
public Queue<Key> layerErgodic(){
//定义两个队列,分别存储树中的键和树中的结点
Queue<Key> queue=new Queue<>();
Queue<Node<Key,Value>> queueHelp=new Queue<>();
//初始化辅助队列
queueHelp.enqueue(root);
while (!queueHelp.isEmpty()){
//从队列中弹出一个结点,把Key放到queue中
Node<Key,Value> node=queueHelp.dequeue();
queue.enqueue(node.key);
//判断当前结点还有没有左子树,如果有,放入到queueHelp中
if (node.left!=null){
queueHelp.enqueue(node.left);
}
//判断当前结点还有没有右子树,如果有,放入到queueHelp中
if (node.right!=null){
queueHelp.enqueue(node.right);
}
}
return queue;
}