数据结构之二分搜索树
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
什么是二分搜索树?二分搜索树是一种特殊的二叉树,当一个二叉树满足所有左儿子的值小于自己,所有右儿子的值大于自己,这样一个树就被称为二分搜索树。
注意!!
二分搜索树的节点一定要具备可比性!!
一、节点、属性的设置
节点的定义,首先有值,还有左右孩子
private class Node{
private E e;
private Node left,right;
public Node(E e){
this.e = e;
left = null;
right = null;
}
@Override
public String toString() {
return e.toString();
}
}
属性,及构造函数
private Node root;
private int size;
public BinarySearchTree(){
root = null ;
size = 0;
}
二、二分搜索树的添加
在一个数据结构中首先要实现的就是怎样在其中添加元素。
因为我们的添加元素的操作要基于二分搜索树的性质来处理,所以一般从根节点开始,往下遍历。
如果当前节点的值大于要添加节点,就继续调用添加函数,但是把当前根节点的左孩子当成根节点,小于则反之。直到遍历到node为空时,就在当前的位置添加节点。
private Node add(Node node ,E 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 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(){
MyStack<Node> stack = new MyStack1<>();
stack.push(root);
while (!stack.isEmpty()){
Node node = (Node)stack.pop();
System.out.println(node.e);
if (node.right!=null){
stack.push(node.right);
}if (node.left!=null){
stack.push(node.left);
}
}
}
//中序遍历 递归
public void inOrder(){
inOrder(root);
}
private void inOrder(Node node){
if(node == null){
return;
}
List list = new ArrayList();
inOrder(node.left);
System.out.println(node.e);
inOrder(node.right);
}
//中序遍历 迭代
public void inOrderNR(){
MyStack<Node> stack = new MyStack1<>();
Node p = root;
while (p!=null){
stack.push(p);
p = p.left;
}
while (!stack.isEmpty()){
Node cur = stack.pop();
System.out.println(cur.e);
if(cur.right!=null){
p = cur.right;
while (p!=null){
stack.push(p);
p = p.left;
}
}
}
}
//后序遍历递归
public void pastOrder(){
pastOrder(root);
}
private void pastOrder(Node node){
if(node == null){
return;
}
pastOrder(node.left);
System.out.println(node.e);
pastOrder(node.right);
}
三、删除
删除也是我们二分搜索树的最难的一部分,分为几种情况,
1,删除最大值
2,删除最小值
3三删除中间值
最大值和最小值的删除只需要找到最边上的节点即可,依次递归,但节点没有左孩子时,当前节点为最小值,如果有就以左孩子以根节点向下去获取,最大值也是同理。
删除中间值的操作就是把要删除节点的左孩子为根的最大值拿上去,或者右孩子为根节点的最小值,也是值最接近被删除节点的节点,去成为新的节点
private Node removeMin(Node node){
if(node.left == null){
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
public E removeMax(){
E ret = searchMax();
root = removeMax(root);
return ret;
}
private Node removeMax(Node node){
if (node.right == null){
Node leftNode = node.left;
node.left = null;
size--;
return leftNode;
}
node.right = removeMax(node.right);
return node;
}
public void remove(E e){
root = remove(root,e);
}
private Node remove(Node node,E 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;
}else{
Node ret = searchMax(node.left);
ret.left = removeMax(node.left);
ret.right = node.right;
node.left = node.right = null;
return ret;
}
}
}
完整代码如下:
public class BinarySearchTree<E extends Comparable<E>> implements Iterable<E>{
private class Node{
private E e;
private Node left,right;
public Node(E e){
this.e = e;
left = null;
right = null;
}
@Override
public String toString() {
return e.toString();
}
}
private Node root;
private int size;
public BinarySearchTree(){
root = null ;
size = 0;
}
public void add(E e){
root=add(root,e);
}
private Node add(Node node ,E 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 int size(){
return size;
}
public boolean isEmpty(){
return size == 0 && root!= null;
}
public boolean contains(E e){
return contains(root,e);
}
private boolean contains(Node node,E e){
if (node == null){
return false;
}
if (e.compareTo(node.e)<0){
return contains(node.left,e);
}else if (e.compareTo(node.e)>0){
return contains(node.right,e);
}else {
return true;
}
}
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(){
MyStack<Node> stack = new MyStack1<>();
stack.push(root);
while (!stack.isEmpty()){
Node node = (Node)stack.pop();
System.out.println(node.e);
if (node.right!=null){
stack.push(node.right);
}if (node.left!=null){
stack.push(node.left);
}
}
}
//中序遍历 递归
public void inOrder(){
inOrder(root);
}
private void inOrder(Node node){
if(node == null){
return;
}
List list = new ArrayList();
inOrder(node.left);
System.out.println(node.e);
inOrder(node.right);
}
//中序遍历 迭代
public void inOrderNR(){
MyStack<Node> stack = new MyStack1<>();
Node p = root;
while (p!=null){
stack.push(p);
p = p.left;
}
while (!stack.isEmpty()){
Node cur = stack.pop();
System.out.println(cur.e);
if(cur.right!=null){
p = cur.right;
while (p!=null){
stack.push(p);
p = p.left;
}
}
}
}
//后序遍历递归
public void pastOrder(){
pastOrder(root);
}
private void pastOrder(Node node){
if(node == null){
return;
}
pastOrder(node.left);
System.out.println(node.e);
pastOrder(node.right);
}
//后序遍历迭代
public E searchMin(){
if (size == 0) {
throw new IllegalArgumentException("BST is empty");
}
E ret = searchMin(root).e;
return ret;
}
private Node searchMin(Node node){
if (node.left==null){
return node;
}
return searchMin(node.left);
}
public E searchMax(){
if (size == 0) {
throw new IllegalArgumentException("BST is empty");
}
return searchMax(root).e;
}
private Node searchMax(Node node){
if (node.right == null){
return node;
}
return searchMax(node.right);
}
public E removeMin(){
E ret = searchMin();
root = removeMin(root);
return ret;
}
private Node removeMin(Node node){
if(node.left == null){
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
public E removeMax(){
E ret = searchMax();
root = removeMax(root);
return ret;
}
private Node removeMax(Node node){
if (node.right == null){
Node leftNode = node.left;
node.left = null;
size--;
return leftNode;
}
node.right = removeMax(node.right);
return node;
}
public void remove(E e){
root = remove(root,e);
}
private Node remove(Node node,E 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;
}else{
Node ret = searchMax(node.left);
ret.left = removeMax(node.left);
ret.right = node.right;
node.left = node.right = null;
return ret;
}
}
}
@Override
public boolean equals(Object obj) {
if (obj == null){
return false;
}
if (obj == this){
return true;
}
if (obj instanceof BinarySearchTree) {
BinarySearchTree other = (BinarySearchTree) obj;
if (this.size == other.size) {
return isSameData(other.root, this.root);
} else {
return false;
}
}else {
return false;
}
}
private boolean isSameData(Node node1, Node node2) {
if (node1 == null && node2==null){
return true;
}
if (!node1.e.equals(node2.e)){
return false;
}
boolean flag =isSameData(node1.left,node2.left);
boolean flag1 = isSameData(node1.right,node2.right);
return flag && flag1;
}
public void clear(){
root = null ;
size = 0;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
generateBST(root,0,sb);
return sb.toString();
}
private void generateBST(Node node, int length, StringBuffer sb) {
if (node ==null){
sb.append(generateDepth(length) + "null\n");
return;
}
generateBST(node.left,length+1,sb);
sb.append(generateDepth(length) + node.e+"\n");
generateBST(node.left,length+1,sb);
}
private String generateDepth(int depth){
StringBuffer sb = new StringBuffer();
for (int i = 0;i<depth;i++){
sb.append("==");
}
return sb.toString();
}
@Override
public Iterator iterator() {
return new BinarySearchTreeIterator();
}
private class BinarySearchTreeIterator<E> implements Iterator<E>{
LinkedList list;
@Override
public boolean hasNext() {
return false;
}
@Override
public E next() {
return null;
}
}
}
总结
是一颗二叉树
二分搜索树的每个节点的值:
每个节点的值都大于其左子树的所有节点的值
每个节点的值都小于其右子树的所有节点的值
每一颗子树也是二分搜索树
存储的元素必须有可比较性, Java中的话就要求二分搜索树保存的数据类型要实现Comparable接口, 或者使用额外的比较器实现
一般二分搜索树不包含重复元素, 当然也可以定义包含重复元素的二分搜索树