二叉树

  • 实现一个二叉查找树,并且支持插入、删除、查找操作
    二叉查找树(Binary Search Tree),或者是一颗空树,或者是具有下列性质的二叉树:
    1、若它的左子树不空,则其左子树上的所有结点的值均小于它根结点的值;
    2、若它的右子树不空,则其右子树上的所有结点的值均大于它根结点的值;
    3、它的左、右子树也分别为二叉查找树。
    查找操作
    在二叉查找树中查找x的过程如下:
    1、若二叉树是空树,则查找失败。
    2、若x等于根结点的数据,则查找成功,否则。
    3、若x小于根结点的数据,则递归查找其左子树,否则。
    4、递归查找其右子树。
    插入操作
    二叉树查找树b插入操作x的过程如下:
    1、若b是空树,则直接将插入的结点作为根结点插入。
    2、x等于b的根结点的数据的值,则直接返回,否则。
    3、若x小于b的根结点的数据的值,则将x要插入的结点的位置改变为b的左子树,否则。
    4、将x要出入的结点的位置改变为b的右子树。
    删除操作
    对于二叉查找树的删除操作(这里根据值删除,而非结点)分三种情况:
    不过在此之前,我们应该确保根据给定的值找到了要删除的结点,如若没找到该结点
    不会执行删除操作!
    下面三种情况假设已经找到了要删除的结点。
    1、如果结点为叶子结点(没有左、右子树),此时删除该结点不会玻化树的结构直接删除即可,并修改其父结点指向它的引用为null.
    2、如果其结点只包含左子树,或者右子树的话,此时直接删除该结点,并将其左子树 或者右子树设置为其父结点的左子树或者右子树即可,此操作不会破坏树结构。
    3、 当结点的左右子树都不空的时候,一般的删除策略是用其右子树的最小数据(容易找到)代替要删除的结点数据并递归删除该结点(此时为null),因为右子树的最小结点不可能有左孩子,所以第二次删除较为容易。
    z的左子树和右子树均不空。找到z的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替z的值
static class BinaryNode  {  
    T data;  
    BinaryNode left;  
    BinaryNode right;  
    public BinaryNode(T data) {  
        this(data,null,null);  
    }  
    public BinaryNode( T data, BinaryNode left, BinaryNode right) {  
        this.data =data;  
        this.left = left;  
        this.right =right;  
    }  
    public BinaryNode()  
    {  
        data =null;  
        this.left = left;  
        this.right =right;  
    }  
}  
public boolean contains(T t)  {  
      return contains(t, rootTree);      
 }  
public boolean contains(T t, BinaryNode node)  {  
    if(node==null)  
        return false;//结点为空,查找失败  
    int result = t.compareTo(node.data);  
    if(result>0)  
         return contains(t,node.right);//递归查询右子树  
    else if(result<</SPAN>0)  
         return contains(t, node.left);//递归查询左子树    
    else  
         return true;  
  }  
public T findMin()  {  
  if(isEmpty())  {  
      System.out.println("二叉树为空");  
      return null;  
   }
   else  
       return findMin(rootTree).data;        
} 
public T findMax()   {  
   if(isEmpty())  {  
      System.out.println("二叉树为空");  
      return null;  
   }
   else  
      return findMax(rootTree).data;  
}  
   public BinaryNode findMin(BinaryNode node)  {  
       if(node==null)  
           return null;  
       else if(node.left==null)  
           return node;  
       return findMin(node.left);//递归查找  
   }  
public BinaryNode findMax(BinaryNode node)  {  
    if(node!=null) {  
        while(node.right!=null)  
            node=node.right;  
     }  
    return node;         
} 

public void insert(T t)  {  
      rootTree = insert(t, rootTree);  
}  
public BinaryNode insert(T t,BinaryNode node)  {  
    if(node==null)   {  
        //新构造一个二叉查找树  
        return new BinaryNode(t, null, null);  
   }  
    int result = t.compareTo(node.data);  
    if(result<</SPAN>0)  
          node.left= insert(t,node.left);  
    else if(result>0)  
          node.right= insert(t,node.right);  
    else  
          ;//doNothing  
    return node;  
}  

public void remove(T t)  {  
     rootTree = remove(t,rootTree);  
}   
public BinaryNode remove(T t,BinaryNode node)  {  
    if(node == null)  
         return node;//没有找到,doNothing  
    int result = t.compareTo(node.data);  
    if(result>0)  
         node.right = remove(t,node.right);  
    else if(result<</SPAN>0)  
         node.left = remove(t,node.left);  
    else if(node.left!=null&&node.right!=null)  {  
         node.data = findMin(node.right).data;  
          node.right = remove(node.data,node.right);  
    }  
    else  
       node = (node.left!=null)?node.left:node.right;  
   return node;  
}     
  • 实现查找二叉查找树中某个节点的后继、前驱节点

  • 实现二叉树前、中、后序以及按层遍历
    递归版本

#递归版本
public class PreInPosTraversal {
	public class Node{
		int val;
		Node left;
		Node right;
		public Node(int data) {
			this.val = data;
		}
	}
	#前序遍历
	public static void PreTraversal(Node head) {
		if(head == null) {
			return;
		}
		System.out.print(head.val + " ");
		PreTraversal(head.left);
		PreTraversal(head.right);
	}
	#中序遍历
	public static void InTraversal(Node head) {
		if(head == null) {
			return;
		}
		InTraversal(head.left);
		System.out.print(head.val + " ");
		InTraversal(head.right);
	}
	#后序遍历
	public static void PosTraversal(Node head) {
		if(head == null) {
			return;
		}
		PosTraversal(head.left);
		PosTraversal(head.right);
		System.out.print(head.val + " ");
	}

非递归版本
使用栈结构的原因:当前节点走向左孩子,走向右孩子,只有从上到下,从左到右,而没有逆序的方式。而栈具有天然的“先进后出”的特性,因此选择它。

1)先序遍历:
先序遍历是:根–左--右
如果一开始头结点不为空:首先新建一个栈,把根节点入栈;当栈不为空时,每次都使栈顶元素弹出,打印该元素的值。并访问该元素,如果该元素的右子树存在,就先将右元素入栈;如果该元素的左子树存在,就将该元素入栈。这样弹出的时候,就是先弹左再弹右。
2)中序遍历:
中序遍历是:左–根--右
如果一开始头结点不为空: 新建一个栈,如果栈不为空,且当前节点不为空,就继续循环:
(1)当前节点不为空,则当前节点入栈;当前节点往它的左子节点移动;
(2)当前节点为空,则弹出栈顶元素作为当前的头结点,打印该结点的值,并将当前节点往其右子节点移动。

3)后序遍历:
后序遍历是:左–右--根
前序(根–左--右)遍历入栈的顺序是先右再左。此时我们想到的是,可以反过来,先左再右。这样就可以做到中–左--右。这样把这个存到栈里,再一一弹出,就可以得到我们后序遍历所需的“左–右--根”。每次先不打印,而是先把要打印的数,存到一个栈里,然后依次弹出并打印栈中元素。
如果一开始头结点不为空:准备两个栈:栈1,头结点先存入栈1。只要栈1不为空时,弹出栈中元素,并将该元素存入栈2。左不为空先压左,右不为空再压右,直到结束循环。当栈2不为空时,逐个弹出栈内元素。

#非递归版本
import java.util.Stack;
public class PreInPosTraversal2 {
	public class Node{
		int val;
		Node left;
		Node right;
		public Node(int data) {
			this.val = data;
		}
	}
	private static void PreTraversal(Node head) {
		System.out.println("PosTraversal:");
		if (head != null) {
			Stack<Node> stack = new Stack<Node>();
			stack.push(head);
			while (!stack.isEmpty()) {
				head = stack.pop();
				System.out.print(head.val);
				if (head.right != null) {
					stack.push(head.right);
				}
 
				if (head.left != null) {
					stack.push(head.left);
				}
			}
		}
 
		System.out.println();
	}
 
	private static void InTraversal(Node head) {
		System.out.println("InTraversal:");
		if(head != null) {
			Stack<Node> stack = new Stack<Node>();
			while(!stack.isEmpty() || head != null) {
				if(head != null) {
					stack.push(head);
					head = head.left;
				}else {
					head= stack.pop();
					System.out.print(head.val);
					head = head.right;
				}
			}
			System.out.println();
		}
		
	}
 
	private static void PosTraversal(Node head) {
		System.out.println("PosTraversal:");
		if(head != null) {
			Stack<Node> stack1 = new Stack<>();
			Stack<Node> stack2 = new Stack<>();
			stack1.push(head);
			while(!stack1.isEmpty()) {
				head = stack1.pop();
				stack2.push(head);
				if(head.left != null) {
					stack1.push(head.left);
				}
				if(head.right != null) {
					stack1.push(head.right);
				}
			}
			
			while(!stack2.isEmpty()) {
				System.out.print(stack2.pop().val);
			}
		}
		System.out.println();
	}
}

层次遍历
用BFS思想

import java.util.LinkedList;
import java.util.Queue;
public class levelTraversal {
	public static class Node{
		int val;
		Node left;
		Node right;		
		public Node(int data) {
			this.val = data;
		}
	}
	
	public static void levelTraversal(Node node) {
		Queue<Node> queue = new LinkedList<Node>();
		if(node != null) {
			queue.add(node);
			while(!queue.isEmpty()) {
				Node now = queue.poll();
				System.out.print(now.val + " ");
				if(now.left != null) {
					queue.add(now.left);
				}
				if(now.right != null) {
					queue.add(now.right);
				}
			}
		}
	}
}
  • 完成leetcode上的验证二叉搜索树(98)及二叉树 层次遍历(102,107)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值