俺一直觉得二叉树是一个天然适合用递归处理的结构,只能从顶开始,面前只有两条路,不断将问题细化直到最底,然后再倒回去选择另一种路。
而二叉搜索树的结构就是在二叉树的基础上,多了一个规则,某结点的左子树的结点总是小于它,右子树的结点总是大于它,且结点唯一 [1]。
写一个二叉搜索树的结构,最核心的地方就是查找,如果会查找了,俺感觉其他都差不多。
二叉树
static class TreeNode<T extends Comparable<? super T>> {
T val;
TreeNode<T> left;
TreeNode<T> right;
TreeNode(T t){
val = t;
}
}
根据那条规则[1],我们知道,如果要找一个值在树中是否存在,小了就找左树,大了就找右树,而且不用回溯的,找不到就是找不到,倒回去也找不到。
private TreeNode serch(T val){
if(isEmploy()||val==root.val){
//Empty,emmm拼错了,懒得改也
return root;
}
return serch(root,val);
}
private TreeNode serch(TreeNode<T> t,T val){
if(t==null){
return null;
}
if(t.val.compareTo(val)==0){
return t;
}
if(t.val.compareTo(val)>0){
return serch(t.left,val);
}else {
return serch(t.right,val);
}
}
跟查找类似,如果存在于树中,就不用插了,如果不存在,那就找到合适的地方,找到属于它的那个空结点。
public void insert(T val){
if(exist(val)){//如果存在于子树
return;
}else if(isEmploy()){
root = new TreeNode<>(val);
}else{
insert(val,root);
}
size++;
}
private void insert(T val,TreeNode<T> root){
if(root.val.compareTo(val)<0){
if(root.right==null){
root.right = new TreeNode<>(val);
return;
}
insert(val,root.right);
}else {
if(root.left==null){
root.left = new TreeNode<>(val);
return;
}
insert(val,root.left);
}
}
注意删除和前两个操作略有差异,由于删除后我们需要调整结点。有三种情况(当然也阔能树中根本没那个结点)
public void delete(T val){
root = delete(root,val);
size--;
}
private TreeNode delete(TreeNode<T> root, T val) {
if(root==null){
return null;
}
if(root.val.compareTo(val)>0){
root.left = delete(root.left,val);
}else if(root.val.compareTo(val)<0){
root.right = delete(root.right,val);
}else{
if(root.left!=null||root.right!=null){
TreeNode<T> temp = root.left;
//找到最右结点
while(temp.right!=null){
temp = temp.right;
}
root.val = temp.val;
//为了将树连起来,如果有指针的话倒是阔以直接赋值为null
root.left = linked(root.left);
}else if(root.left!=null){
root = root.left;
}else if(root.right!=null){
root = root.right;
}else {
root = null;
}
}
return root;
}
private TreeNode<T> linked(TreeNode treeNode){
if(treeNode.right==null){
return treeNode.left;
}
treeNode.right = linked(treeNode.right);
return treeNode;
}
有四种遍历方式:
private enum ModeEnum {
pre("pre"),mid("mid"),after("after"),levelOrder("levelOrder");
private String mode;
ModeEnum(String mode){
this.mode = mode;
}
}
public List<T> toList(String s){
if(isEmploy()){
return null;
}
ModeEnum mode = ModeEnum.valueOf(s);
List<T> list = new ArrayList<>();
switch (mode){
case mid:
mid(root,list);
break;
case pre:
pre(root,list);
break;
case after:
after(root,list);
break;
case levelOrder:
levelOrder(root,list);
break;
default:
mid(root,list);
}
return list;
}
前中后遍历很简单,用递归的方式写的话,都是基于深搜+回溯的思想,每个结点都是父节点 ,不过它的儿子阔能是null而已。
private void after(TreeNode<T> root, List<T> list) {
if(root==null){
return;
}
after(root.left,list);
after(root.right,list);
list.add(root.val);
}
private void pre(TreeNode<T> root, List<T> list) {
if(root==null){
return;
}
list.add(root.val);
pre(root.left,list);
pre(root.right,list);
}
private void mid(TreeNode<T> node,List<T> list){
if(node==null){
return;
}
mid(node.left,list);
list.add(node.val);
mid(node.right,list);
}
层次遍历,比较自然的想法就是广度优先了。要尊老嘛(不是),父辈的儿子结点肯定优先于子辈的儿子,要实现这种操作使用队列呀。
private void levelOrder(TreeNode<T> root, List<T> list) {
Queue<TreeNode<T>> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode<T> t = queue.poll();
if(t.left!=null){
queue.offer(t.left);
}
if(t.right!=null){
queue.offer(t.right);
}
list.add(t.val);
}
}
也是深搜+回溯的思想,一条一条的路线找,找到更长的路线就更新。
(广搜也阔以呀,不过需要给记录下存入队列的结点所属的层数,加入它的子节点时就要在当前基础上+1了,从上到下的数,深搜就是从下往上的数)
public int depth(){
return depth(root);
}
private int depth(TreeNode<T> node){
if(node==null){
return 0;
}
return Math.max(depth(node.left),depth(node.right))+1;
}
import java.util.*;
public class SerchTree <T extends Comparable<? super T>> {
private TreeNode root;
private int size;
private enum ModeEnum {
pre("pre"),mid("mid"),after("after"),levelOrder("levelOrder");
private String mode;
ModeEnum(String mode){
this.mode = mode;
}
}
public int depth(){
return depth(root);
}
private int depth(TreeNode<T> node){
if(node==null){
return 0;
}
return Math.max(depth(node.left),depth(node.right))+1;
}
public List<T> toList(String s){
if(isEmploy()){
return null;
}
ModeEnum mode = ModeEnum.valueOf(s);
List<T> list = new ArrayList<>();
switch (mode){
case mid:
mid(root,list);
break;
case pre:
pre(root,list);
break;
case after:
after(root,list);
break;
case levelOrder:
levelOrder(root,list);
break;
default:
mid(root,list);
}
return list;
}
private void levelOrder(TreeNode<T> root, List<T> list) {
Queue<TreeNode<T>> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode<T> t = queue.poll();
if(t.left!=null){
queue.offer(t.left);
}
if(t.right!=null){
queue.offer(t.right);
}
list.add(t.val);
}
}
private void after(TreeNode<T> root, List<T> list) {
if(root==null){
return;
}
after(root.left,list);
after(root.right,list);
list.add(root.val);
}
private void pre(TreeNode<T> root, List<T> list) {
if(root==null){
return;
}
list.add(root.val);
pre(root.left,list);
pre(root.right,list);
}
private void mid(TreeNode<T> node,List<T> list){
if(node==null){
return;
}
mid(node.left,list);
list.add(node.val);
mid(node.right,list);
}
static class TreeNode<T extends Comparable<? super T>> {
T val;
TreeNode<T> left;
TreeNode<T> right;
TreeNode(T t){
val = t;
}
}
public SerchTree(){
}
public int size() {
return size;
}
public SerchTree(T val){
root = new TreeNode(val);
}
public boolean isEmploy(){
return root==null;
}
public void insert(T val){
if(exist(val)){
System.out.println("已存在");
return;
}else if(isEmploy()){
root = new TreeNode<>(val);
}else{
insert(val,root);
}
size++;
}
public void delete(T val){
root = delete(root,val);
size--;
}
private TreeNode delete(TreeNode<T> root, T val) {
if(root==null){
return null;
}
if(root.val.compareTo(val)>0){
root.left = delete(root.left,val);
}else if(root.val.compareTo(val)<0){
root.right = delete(root.right,val);
}else{
if(root.left!=null||root.right!=null){
TreeNode<T> temp = root.left;
while(temp.right!=null){
temp = temp.right;
}
root.val = temp.val;
root.left = linked(root.left);
}else if(root.left!=null){
root = root.left;
}else if(root.right!=null){
root = root.right;
}else {
root = null;
}
}
return root;
}
private TreeNode<T> linked(TreeNode treeNode){
if(treeNode.right==null){
return treeNode.left;
}
treeNode.right = linked(treeNode.right);
return treeNode;
}
private void insert(T val,TreeNode<T> root){
if(root.val.compareTo(val)<0){
if(root.right==null){
root.right = new TreeNode<>(val);
return;
}
insert(val,root.right);
}else {
if(root.left==null){
root.left = new TreeNode<>(val);
return;
}
insert(val,root.left);
}
}
private boolean exist(T val){
return serch(val)!=null;
}
private TreeNode serch(T val){
if(isEmploy()||val==root.val){
return root;
}
return serch(root,val);
}
private TreeNode serch(TreeNode<T> t,T val){
if(t==null){
return null;
}
if(t.val.compareTo(val)==0){
return t;
}
if(t.val.compareTo(val)>0){
return serch(t.left,val);
}else {
return serch(t.right,val);
}
}
public static void main(String[] args){
SerchTree<Integer> serchTree = new SerchTree<>();
serchTree.insert(10);
serchTree.insert(5);
serchTree.insert(2);
serchTree.insert(1);
serchTree.insert(3);
serchTree.insert(4);
serchTree.insert(8);
serchTree.insert(9);
serchTree.insert(6);
serchTree.insert(15);
serchTree.insert(13);
serchTree.insert(11);
serchTree.delete(5);
serchTree.insert(25);
serchTree.insert(18);
serchTree.insert(16);
serchTree.insert(26);
serchTree.delete(25);
List<Integer> list = serchTree.toList("mid");
for(int i:list){
System.out.print(i+" ");
}
System.out.println();
list = serchTree.toList("pre");
for(int i:list){
System.out.print(i+" ");
}
System.out.println();
list = serchTree.toList("after");
for(int i:list){
System.out.print(i+" ");
}
System.out.println();
list = serchTree.toList("levelOrder");
for(int i:list){
System.out.print(i+" ");
}
System.out.println();
System.out.println(serchTree.depth());
System.out.println(serchTree.size());
}
}
//1 2 3 4 6 8 9 10 11 13 15 16 18 26
// 10 4 2 1 3 8 6 9 15 13 11 18 16 26
// 1 3 2 6 9 8 4 11 13 16 26 18 15 10
// 10 4 15 2 8 13 18 1 3 6 9 11 16 26
// 4
// 14