一.二叉搜索树背景
对于动态数组来说,查找元素,从头向后遍历最好情况是O(1),最坏情况是O(n).平均下来复杂度是O(n) 如果维护一个有序的动态数组,使用二分搜索,最坏时间复杂度:O(logn) 但是添加、删除的平均时间复杂度是 O(n) 所以对于动态数组其实有进一步优化的空间
但是如果用二叉搜索树,由于根节点,左边都是比根节点小的元素,根节点右边都是比根节点大的元素。最坏的情况下也只是之前一半的执行次数。上一章我们提到了二叉树的高度为,floor(log2n)+1(2的n次取对数在向下取整加一)所以最坏复杂度才为O(log2n)–>无论是添加还是删除;
二.二叉搜索树的性质
? 二叉搜索树是二叉树的一种,是应用非常广泛的一种二叉树,英文简称为 BST 任意一个节点的值都大于其左子树所有节点的值 ?任意一个节点的值都小于其右子树所有节点的值 它的左右子树也是一棵二叉搜索树 ? 二叉搜索树可以大大提高搜索数据的效率 ? 二叉搜索树存储的元素必须具备可比较性 😅比如 int、double 等 🤡如果是自定义类型,需要指定比较方式(对于类型的比较 有两种方式---->(1)通过类实现Comparable接口,重写compareTo方法指定比较逻辑(或者直接利用Comparable自带的) (2)通过比较器重写比较逻辑 ) 🤡不允许为 null
三.二叉搜索树的接口设计
? int size() // 元素的数量 ? boolean isEmpty() // 是否为空 ? void clear() // 清空所有元素 ? void add(E element) // 添加元素 ? void remove(E element) // 删除元素 ? boolean contains(E element)// 是否包含某元素
四.添加元素
🌟🌟添加元素,肯定是添加到叶子节点,所以只要只要找到可以存放特定元素的位置,放置元素即可。但是设计并不是直接找到这个叶子节点,而是找到该位置节点的父节点位置,然后通过parent.left或parnet.right=new Node<>(element,null)
private void elementNullCheck(E element)
{
if(element==null){
throw new UnsupportedOperationException("element="+null+"不合法");
}
}
public void add(E element){
elementNullCheck(element);
if(this.root==null)
{
root=new Node<>(element,null);
size++;
return;
}
Node<E> parent1=this.root;
Node<E> node=this.root;
int ins=0;
while (node!=null)
{
ins=compare(element,node.element);
parent1=node;
if (ins>0){
node=node.right;
}else if(ins<0){
node=node.left;
}else {
return;
}
}
Node<E> newNode=new Node<>(element,parent1);
if (ins>0){
parent1.right=newNode;
}else {
parent1.left=newNode;
}
}
private int compare(E e1,E e2){
if(comparator!=null) {
return comparator.compare(e1, e2);
}
return ((java.lang.Comparable<E>)e1).compareTo(e2);
}
设计点: 比较器与Comparable接口的结合设计
private int compare(E e1,E e2){
if(comparator!=null) {
return comparator.compare(e1, e2);
}
return ((java.lang.Comparable<E>)e1).compareTo(e2);
}
五.删除元素
(1)删除度为2节点
将删除度为2的节点转化为删除度为1的叶子节点
删除的节点是度为二的节点 1.找到要删除的节点 2.找到该节点的前驱(后继),用前驱(后继)覆盖要删除的值 3.删除相应的前驱(后继) 4.如果一个节点的度为 2,那么 5.它的前驱、后继节点的度只可能是 1 和 0
(2)删除度为1节点
(2)删除的节点是度为一的节点 1.找到要删除的节点node 2.找到要删除的节点的下一个节点child 以node是左子节点为例 node.parent.left=child child.parent=node.parent;
(3)删除度为0节点
(1)删除的节点是叶子节点 1.找到叶子节点node 2.判断此叶子节点是它父节点的左树还是右树 3.直接删除
删除代码
public void remove(E element){
Node<E> s= node(element);
remove(s);
}
private void remove(Node<E> node){
if (node==null)return;
if(node.doubleChildren()){
Node<E> s=preTarget(node);
node.element=s.element;
node=s;
}
Node<E> child=node.left==null?node.right:node.left;
if(child!=null){
child.parent=node.parent;
if (node.parent==null){
root=child;
}else if(node==node.parent.left){
node.parent.left=child;
}else if(node==node.parent.right){
node.parent.right=child;
}
}else if(node.parent==null){
root=null;
} else {
if(node==node.parent.left){
node.parent.left=null;
}else {
node.parent.right=null;
}
}
}
private Node<E> node(E element){
Node<E> node=this.root;
while (node != null) {
int cmp=compare(element,node.element);
if (cmp == 0) {
return node;
} else if (cmp < 0) {
node = node.left;
} else {
node = node.right;
}
}
return null;
}
六.整体代码
package com.Domain;
import Util.printer.BinaryTreeInfo;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
@SuppressWarnings("unchecked")
public class BinarySearch<E> {
private int size;
private Node<E> root;
private Comparator<E> comparator;
public BinarySearch (){this(null);};
public BinarySearch(Comparator<E> comparator){
this.comparator=comparator;
}
public int size(){
return this.size;
}
public boolean isEmpty(){
return this.size==0;
}
public void clear(){
size=0;
}
private void elementNullCheck(E element)
{
if(element==null){
throw new UnsupportedOperationException("element="+null+"不合法");
}
}
public void add(E element){
elementNullCheck(element);
if(this.root==null)
{
root=new Node<>(element,null);
size++;
return;
}
Node<E> parent1=this.root;
Node<E> node=this.root;
int ins=0;
while (node!=null)
{
ins=compare(element,node.element);
parent1=node;
if (ins>0){
node=node.right;
}else if(ins<0){
node=node.left;
}else {
return;
}
}
Node<E> newNode=new Node<>(element,parent1);
if (ins>0){
parent1.right=newNode;
}else {
parent1.left=newNode;
}
}
private int compare(E e1,E e2){
if(comparator!=null) {
return comparator.compare(e1, e2);
}
return ((java.lang.Comparable<E>)e1).compareTo(e2);
}
public void remove(E element){
Node<E> s= node(element);
remove(s);
}
private void remove(Node<E> node){
if (node==null)return;
if(node.doubleChildren()){
Node<E> s=preTarget(node);
node.element=s.element;
node=s;
}
Node<E> child=node.left==null?node.right:node.left;
if(child!=null){
child.parent=node.parent;
if (node.parent==null){
root=child;
}else if(node==node.parent.left){
node.parent.left=child;
}else if(node==node.parent.right){
node.parent.right=child;
}
}else if(node.parent==null){
root=null;
} else {
if(node==node.parent.left){
node.parent.left=null;
}else {
node.parent.right=null;
}
}
}
private Node<E> node(E element){
Node<E> node=this.root;
while (node != null) {
int cmp=compare(element,node.element);
if (cmp == 0) {
return node;
} else if (cmp < 0) {
node = node.left;
} else {
node = node.right;
}
}
return null;
}
public boolean contains(E element){
return false;
}
@Override
public Object root() {
return root;
}
@Override
public Object left(Object node) {
return ((Node)node).left;
}
@Override
public Object right(Object node) {
return ((Node)node).right;
}
@Override
public Object string(Object node) {
Node<E> myNode=(Node<E>)node;
String parentString=(myNode.parent==null?null:myNode.parent.element.toString());
return myNode.element+"(p)"+parentString;
}
public abstract static class Visitor<E>{
abstract boolean visit(E element);
boolean stop;
}
public void preDisplay1(Visitor<E> visitor) {
if (visitor==null){
return;
}
preDisplay(this.root,visitor);
}
private void preDisplay(Node<E> node,Visitor<E> visitor) {
if(node==null||visitor.stop){
return;
}
visitor.stop=visitor.visit(node.element);
preDisplay(node.left,visitor);
preDisplay(node.right,visitor);
}
public void inOderDisplay(Visitor<E> visitor){
if(visitor==null)
{
return;
}
inOderDisplay1(this.root,visitor);
}
private void inOderDisplay1(Node<E> node,Visitor<E>visitor)
{
if (node==null||visitor.stop)
{
return;
}
inOderDisplay1(node.left,visitor);
visitor.stop=visitor.visit(node.element);
if(visitor.stop){
return;
}
inOderDisplay1(node.right,visitor);
}
public void postDisplay(Visitor<E> visitor){
if(visitor==null)
{
return;
}
postDisplay1(this.root,visitor);
}
private void postDisplay1(Node<E> node,Visitor<E> visitor) {
if (node==null||visitor.stop){
return;
}
postDisplay1(node.left,visitor);
postDisplay1(node.right,visitor);
if(visitor.stop)
{
return;
}
visitor.stop=visitor.visit(node.element);
}
public void levelDisplay(Visitor<E>visitor){
Queue<Node<E>> queue=new LinkedList<>();
if (this.root==null||visitor==null)
{
return;
}
queue.offer(root);
while (!queue.isEmpty()){
Node<E> node=queue.poll();
if(visitor.visit(node.element)){
return;
}
if (node.left!=null) {
queue.offer(node.left);
}
if (node.right!=null){
queue.offer(node.right);
}
}
}
public static class Node<E>{
E element;
Node<E> left;
Node<E> right;
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 doubleChildren(){
return left!=null&&right!=null;
}
}
public boolean isComplete(){
if(this.root==null){
return false;
}
Queue<Node<E>> queue=new LinkedList<>();
queue.offer(root);
boolean leaf=false;
while (!queue.isEmpty()){
Node<E> node=queue.poll();
if(!node.isLeaf()&&leaf){
return false;
}
if (node.left!=null){
queue.offer(node.left);
}else if(node.right!=null)
{
return false;
}
if (node.right!=null){
queue.offer(node.right);
}else{
leaf=true;
}
}
return true;
}
public int height(){
if(root==null){
return 0;
}
Queue<Node<E>> queue=new LinkedList<>();
queue.offer(root);
int height=0;
int levelSize=1;
while (!queue.isEmpty()){
Node<E> node=queue.poll();
levelSize--;
if(node.left!=null){
queue.offer(node.left);
}
if (node.right!=null){
queue.offer(node.right);
}
if (levelSize==0){
levelSize=queue.size();
height++;
}
}
return height;
}
public Node<E> preTarget(Node<E> node){
if (node==null){
return null;
}
Node<E> p=node.left;
if (p!=null) {
while (p.right != null) {
p = p.right;
}
return p;
}
while (node.parent!=null&&node==node.parent.left)
{
node=node.parent;
}
return node.parent;
}
}
|