二叉搜索树的特点:
二叉搜索树的左节点小于它的父节点,右节点大于父节点
二叉搜索树中的结点:
1 private static class Node<E>{ 2 3 private E element; 4 private Node<E> parent; 5 private Node<E> left; 6 private Node<E> right; 7 8 public Node(E element, Node<E> parent){ 9 this.element = element; 10 this.parent = parent; 11 } 12 13 }
二叉搜索树的添加方法:
public void add(E element){ if(size == 0){ root = new Node<E>(element,null);//创建一个头节点 } Node<E> parent = root; Node<E> node = root; int cmp = 0; while(node != null){ cmp = compare(element,node.element);//比较两个节点的大小 parent = node; if(cmp > 0){ node = node.right; }else if(cmp < 0){ node = node.left; }else{ return; } } if(cmp > 0 ){ parent.right = new Node<E>(element,parent); }else if(cmp < 0 ){ parent.left = new Node<E>(element,parent); }else{ parent.element = element; } size++; }
二叉搜索树中的元素的比较
1.插入的元素中实现Comparable接口,重写compare方法.
2.如果插入的元素不想实现接口,
在创建二叉搜索树的时候new 一个Comparator的匿名内部类,重写compare方法.
二叉树的遍历(所有二叉树)
前序遍历:
先访问该节点,在访问该节点的左子树,然后访问该节点的右子树.
public void preOrderTree(){ preOrderTree(root); } private void preOrderTree(Node<E> node){ if(node == null) return; System.out.println(node.element); preOrderTree(node.left); preOrderTree(node.right); }
中序遍历:
中序遍历根节点的左子树,访问根节点,中序遍历根节点的右子树
public void inOrderTree(){ inOrderTree(root); } private void inOrderTree(Node<E> node){ if(node == null) return; inOrderTree(node.left); System.out.println(node.element); inOrderTree(node.right); }
后序遍历
后序遍历根节点的左子树,后序遍历根节点的右子树,访问根节点.
public void lastOrderTree(){ inOrderTree(root); } private void lastOrderTree(Node<E> node){ if(node == null) return; System.out.println(node.element); inOrderTree(node.left); inOrderTree(node.right); }
层序遍历
从根节点开始一层一层的访问节点
public void levelOrderTree(Node<E> root){ Queue<Node<E>> queue = (Queue<Node<E>>) new LinkedList<E>(); queue.offer(root); while(!queue.isEmpty()){ Node<E> node = queue.poll(); System.out.println(node.element); if(node.left != null){ queue.offer(node.left); } if(node.right != null){ queue.offer(node.right); } } }
利用队列先进先出的特点,每次弹出一个,就把他的左右节点添加进来.
前驱结点:对一棵二叉树进行中序遍历,遍历后的顺序,当前节点的前一个节点为该节点的前驱节点;
后继节点:对一棵二叉树进行中序遍历,遍历后的顺序,当前节点的后一个节点为该节点的后继节点;
前驱结点的实现:
public Node<E> predecessor(Node<E> node){ if(node == null) return null;
//如果该结点有左子节点,那么该节点的前驱结点就是左子节点的最后一个右子节点 if(node.left != null){ node = node.left; while(node.right != null){ node = node.right; } return node; }
//如果该节点没有左子节点,那么分两种情况,如果这个节点在父节点的右边,那么这个父节点就是前驱结点
//吐过这个节点在父节点的左边,那么就要找父节点的父节点,知道父节点在前一个父节点的右边.
while(node.parent != null && node.parent.right != node){ node = node.parent; } return node.parent; }
二叉搜索树的删除方法:
public void remove(Node<E> node){ if(node == null) return; //当删除的节点有两个子节点时 if(node.left != null && node.right != null){ Node<E> s = predecessor(node);//前序节点只可能有一个左子点或者没有子节点 node.element = s.element; s = node; //把前序节点的值赋给要删除的节点,然后把node指向这个前序节点,那么就只需要删除前序节点就可. } //我觉得replacement只可能是node.left或者为null;不用加node.right Node<E> replacement = node.left != null ? node.left : node.right; if(replacement != null){ replacement.parent = node.parent;//如果node有一个子节点的话,把node的父节点赋给子节点 if(node.parent == null){ root = replacement;//如果node没有父节点的话,那么他就是根节点 }else if(node.parent.left == node){ node.parent.left = replacement; }else if(node.parent.right == node){ node.parent.right = replacement; } //根据node节点在父节点的左边还是右边赋给node的子节点.这样,node就被删除了 }else if(node.parent == null){ root = null; }else{ if(node == node.parent.left){ node.parent.left = null; }else if(node == node.parent.right){ //如果node没有子节点的话,那么就直接删除 node.parent.right = null; } } }