二叉树操作(2删除)

标签: 二叉树 删除
4人阅读 评论(0) 收藏 举报
分类:

上一篇主要整理了遍历。删除的时候是复杂的。因为考虑的情况比较多。

网上这篇例子写的很好,我就转过了。

https://blog.csdn.net/fengrunche/article/details/52305748

1)删除节点为叶子节点


     2)删除节点只有一个子节点:只有一个左子节点和只有一个右子节点


    3)删除节点有两个子节点:这种情况比较复杂,需要寻找后继节点,即比要删除的节点的关键值次高的节点是它的后继节点。说得简单一些,后继节点就是比要删除的节点的关键值要大的节点集合中的最小值。(右子节点的左后代)

            得到后继节点的代码如下:

 /** 
	         *  
	         * 得到后继节点,即删除节点的左后代 
	         */  
	        private Node getSuccessor(Node delNode) {  
	            Node successor = delNode;  
	            Node successorParent = null;  
	            Node current = delNode.rightChild;  
	              
	            while (current != null) {  
	                successorParent = successor;  
	                successor = current;  
	                current = current.leftChild;  
	            }  
	              
	            //如果后继节点不是删除节点的右子节点时,  
	            if (successor != delNode.rightChild) {  
	                //要将后继节点的右子节点指向后继结点父节点的左子节点,  
	                successorParent.leftChild = successor.rightChild;  
	                //并将删除节点的右子节点指向后继结点的右子节点  
	                successor.rightChild = delNode.rightChild;  
	            }  
	            //任何情况下,都需要将删除节点的左子节点指向后继节点的左子节点  
	            successor.leftChild = delNode.leftChild;  
	              
	            return successor;  
	        }  

       a)如果后继节点是刚好是要删除节点的右子节点


//删除的节点为父节点的左子节点时:  
parent.leftChild = successor;  
successor.leftChild = delNode.leftChild;  
       
//删除的节点为父节点的右子节点时:  
parent.rightChild = successor;  
successor.leftChild = delNode.leftChild  
  b)如果后继节点为要删除节点的右子节点的左后代:


上面图中50, 888 分别为successorparent,

//删除的节点为父节点的左子节点时:  
 successorParent.leftChild = successor.rightChild;  
 successor.rightChild = delNode.rightChild;  
  parent.leftChild = successor;  
  successor.leftChild = delNode.leftChild;  
        
  //删除的节点为父节点的右子节点时:  
  successorParent.leftChild = successor.rightChild;  
  successor.rightChild = delNode.rightChild;  
  parent.rightChild = successor;  
  successor.leftChild = delNode.leftChild;  

删除的代码如下,作者做了抽取公共流程。终点是复杂子节点的处理。结合着图比较好理解。

package com.daojia.collect;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

public class Btree {

	 private Node root = null;  
     
	 Btree(int value) {  
	        root = new Node(value);  
	        root.leftChild  = null;  
	        root.rightChild = null;  
	    }  
	//查找  
	    public Node findKey(int value) {
	    	Node current  = root ;
	    	while(true){
	    		if(current.value== value)
	    		{
	    			return current;
	    		}
	    		else if(current.value>value){
	    			
	    			 current = current.leftChild;
	    		}else if(current.value < value){
	    			current = current.rightChild;
	    		}
	    		if(current == null){
	    			return null;
	    		}
	    	}	    	
	
	    }   
	  //插入  
	        public Node insert(int value) {
	        	String error = null;  
	        	  
	        	Node node = new Node(value);  
	        	if (root == null) {  
	        	    root = node;  
	        	    root.leftChild  = null;  
	        	    root.rightChild = null;  
	        	} else {  
	        	    Node current = root;  
	        	    Node parent = null;  
	        	    while (true) {  
	        	        if (value < current.value) {  
	        	            parent = current;  
	        	            current = current.leftChild;  
	        	            if (current == null) {  
	        	                parent.leftChild = node;  
	        	                break;  
	        	            }  
	        	        } else if (value > current.value) {  
	        	            parent = current;  
	        	            current = current.rightChild;  
	        	            if (current == null) {  
	        	                parent.rightChild = node;  
	        	                break;  
	        	            }  
	        	        } else {  
	        	            System.out.println("exists");
	        	            break;
	        	        }     
	        	    } // end of while  
	        	}
	        	return node;
	        }  
	        //中序遍历递归操作  
	        public void inOrderTraverse() {
	            System.out.print("中序递归:");
	        	 inOrderTraverse(root);
	        	 System.out.println();
	        }
	        /**
	         * (递归)先遍历左子树,在跟节点,再遍历右子树
	         * @param node
	         */
	        private void inOrderTraverse(Node node) {  
	            if (node == null)   
	                return ;  
	        
	            inOrderTraverse(node.leftChild);  
	            node.display();  
	            inOrderTraverse(node.rightChild);  
	        }
	        /**
	         * 非递归遍历
	         * 1)对于任意节点current,若该节点不为空则将该节点压栈,并将左子树节点置为current,重复此操作,直到current为空。 
	         * 2)若左子树为空,栈顶节点出栈,访问节点后将该节点的右子树置为current 
	         * 3) 重复1、2步操作,直到current为空且栈内节点为空。 
	         */
	        public  ArrayList<Integer> inOrderByStack() {
	        	System.out.print("中序非递归:");
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	Stack<Node> stack = new Stack<Node>();
	        	Node current = root;
	        	
	        	while(current != null ||!stack.isEmpty())
	        	{
	        		while(current != null){
	        		stack.push(current);
	        		current = current.leftChild;
	        		}
	        		
	        		if(!stack.isEmpty())
	        		{
	        			current =stack.pop();
	        			list.add(current.value);
	        			current = current.rightChild;
	        		}
	        	}
	        	return list;
	        }
	        //前序遍历  
	        public void preOrderTraverse() {
	        	System.out.print("前序遍历:");  
	            preOrderTraverse(root);
	            System.out.println("");    
	        }  
	        private void preOrderTraverse(Node node) {
	        	  if (node == null)   
		                return ;  
	        	  node.display();  
	        	  preOrderTraverse(node.leftChild);           
	        	  preOrderTraverse(node.rightChild);  
	        }
	        //前序遍历非递归操作  
	        public ArrayList<Integer> preOrderByStack() {
	        	System.out.print("前序遍历 非递归:");  
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	Stack<Node> stack = new Stack<Node>();
	        	Node current = root;
	        	while(current != null || !stack.isEmpty())
	        	{
	        		while(current != null){
	        			stack.push(current);
	        			list.add(current.value);
	        			current = current.leftChild;
	        			
	        		}
	        		if( !stack.isEmpty()){
	        			current = stack.pop();
	        			current = current.rightChild;
	        		}
	        		
	        	}
	        	
	        	return list;
	        	
	        }  
	      //后序遍历  
	        public void postOrderTraverse() {
	        	System.out.print("后序遍历:");
	        	postOrderTraverse(root);
	        	System.out.println("");
	        }
	        private void postOrderTraverse(Node node){
	        	if(node == null){
	        		return;
	        	}
	        	postOrderTraverse(node.leftChild);
	        	postOrderTraverse(node.rightChild);
	        	node.display();
	        }
	        /**
	         * 1)对于任意节点current,若该节点不为空则访问该节点后再将节点压栈,并将左子树节点置为current,重复此操作,直到current为空。 
             * 2)若左子树为空,取栈顶节点的右子树,如果右子树为空或右子树刚访问过,则访问该节点,并将preNode置为该节点 
	         */
	        public ArrayList<Integer> postOrderByStack() {
	        	System.out.print("后序遍历 非递归:");  
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	Stack<Node> stack = new Stack<Node>();
	        	Node current = root;
	        	Node preNode = null;  
	        	while(current != null || !stack.isEmpty())
	        	{
	        		while(current != null){
	        			stack.push(current);	        		
	        			current = current.leftChild;
	        			
	        		}
	        		if( !stack.isEmpty()){
	        			 current = stack.peek().rightChild;  
	                     if (current == null || current == preNode) {  
	                         current = stack.pop();  
	                         list.add(current.value);  
	                         preNode = current;  
	                         current = null;  
	                     }  	        				        			
	        		}	        		
	        	}
	        	
	        	return list;
	        } 
	        //后序遍历非递归操作 
	        public ArrayList<Integer> postOrderByStack2() {
	        	System.out.print("后序遍历 非递归:");  
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	Stack<Node> stack = new Stack<Node>();
	        	Node current = null;
	        	Node preNode = null; 
	        	stack.push(root);
	        	while(!stack.isEmpty())
	        	{	        		
	        			 current = stack.peek();
	        			 //当前节点没有孩子节点或者左右孩子节点都被访问过
	                     if( (current.leftChild == null&¤t.rightChild== null) ||
	                    		 (current!= null&&(current.leftChild == preNode|| current.rightChild== preNode)) ) {  
	                         stack.pop();  
	                         list.add(current.value);  
	                         preNode = current;  
	                      
	                     }else{                    	 
	                  
	                    	 if(current.rightChild != null ){
	                    		 stack.push(current.rightChild);
	                    	 }
	                      	 if(current.leftChild != null ){
	                    		 stack.push(current.leftChild);
	                    	 }
	                     }
	        		       		
	        	}
	        	
	        	return list;
	        }
	        /**
	         * 广度优先遍历
	         * @return
	         */
	        public ArrayList<Integer> levelTraverse(){
	        	LinkedList<Node>  queue = new LinkedList<Node>();
	        	ArrayList<Integer> list = new ArrayList<Integer>();
	        	System.out.print("广度优先遍历 :");
	        	queue.add(root);
	        	while(!queue.isEmpty()){
	        		Node current = queue.poll();
	        		  list.add(current.value);
	        		  if(current.leftChild != null){
	        			  queue.add(current.leftChild);
	        		  }
	        		  if(current.rightChild != null){
	        			  queue.add(current.rightChild);
	        		  }
	        	}
				return list;
	        	
	        }
	        /**
	         * 得到最小值
	         * @return
	         */
	        public int getMinValue() {
	        	System.out.print("最小值:");
	        	Node current = root;
	        	while(true){
	        		
	        		if(current.leftChild == null)
	        		{
	        			return current.value;
	        		}
	        		current = current.leftChild;
	        	}
	        	
	        } 
	        //得到最大值
	        public int getMaxValue(){
	        	System.out.print("最大值:");
	        	Node current = root;
	        	while(true){
	        		
	        		if(current.rightChild == null)
	        		{
	        			return current.value;
	        		}
	        		current = current.rightChild;
	        	}
	        }
	        /** 
	         *  
	         * 得到后继节点,即删除节点的左后代 
	         */  
	        private Node getSuccessor(Node delNode) {  
	            Node successor = delNode;  
	            Node successorParent = null;  
	            Node current = delNode.rightChild;  
	              
	            while (current != null) {  
	                successorParent = successor;  
	                successor = current;  
	                current = current.leftChild;  
	            }  
	              
	            //如果后继节点不是删除节点的右子节点时,  
	            if (successor != delNode.rightChild) {  
	                //要将后继节点的右子节点指向后继结点父节点的左子节点,  
	                successorParent.leftChild = successor.rightChild;  
	                //并将删除节点的右子节点指向后继结点的右子节点  
	                successor.rightChild = delNode.rightChild;  
	            }  
	            //任何情况下,都需要将删除节点的左子节点指向后继节点的左子节点  
	            successor.leftChild = delNode.leftChild;  
	              
	            return successor;  
	        }  
	        //删除节点
	        public boolean delete(int value) {  
	            Node current = root;    //需要删除的节点  
	            Node parent = null;     //需要删除的节点的父节点  
	            boolean isLeftChild = true;   //需要删除的节点是否父节点的左子树  
	              
	            while (true) {  
	                if (value == current.value) {  
	                    break;  
	                } else if (value < current.value) {  
	                    isLeftChild = true;  
	                    parent = current;  
	                    current = current.leftChild;  
	                } else {  
	                    isLeftChild = false;  
	                    parent = current;  
	                    current = current.rightChild;  
	                }  
	                  
	                //找不到需要删除的节点,直接返回  
	                if (current == null)  
	                    return false;  
	            }  
	              
	            //分情况考虑  
	            //1、需要删除的节点为叶子节点  
	            if (current.leftChild == null && current.rightChild == null) {  
	                //如果该叶节点为根节点,将根节点置为null  
	                if (current == root) {  
	                    root = null;  
	                } else {  
	                    //如果该叶节点是父节点的左子节点,将父节点的左子节点置为null  
	                    if (isLeftChild) {  
	                        parent.leftChild  = null;  
	                    } else { //如果该叶节点是父节点的右子节点,将父节点的右子节点置为null  
	                        parent.rightChild = null;  
	                    }  
	                }  
	            }   
	            //2、需要删除的节点有一个子节点,且该子节点为左子节点  
	            else if (current.rightChild == null) {  
	                //如果该节点为根节点,将根节点的左子节点变为根节点  
	                if (current == root) {  
	                    root = current.leftChild;  
	                } else {  
	                    //如果该节点是父节点的左子节点,将该节点的左子节点变为父节点的左子节点  
	                    if (isLeftChild) {  
	                        parent.leftChild = current.leftChild;  
	                    } else {  //如果该节点是父节点的右子节点,将该节点的左子节点变为父节点的右子节点  
	                        parent.rightChild = current.leftChild;  
	                    }  
	                }  
	            }  
	            //2、需要删除的节点有一个子节点,且该子节点为右子节点  
	            else if (current.leftChild == null) {  
	                //如果该节点为根节点,将根节点的右子节点变为根节点  
	                if (current == root) {  
	                    root = current.rightChild;  
	                } else {  
	                    //如果该节点是父节点的左子节点,将该节点的右子节点变为父节点的左子节点  
	                    if (isLeftChild) {  
	                        parent.leftChild = current.rightChild;  
	                    } else {  //如果该节点是父节点的右子节点,将该节点的右子节点变为父节点的右子节点  
	                        parent.rightChild = current.rightChild;  
	                    }  
	                }  
	            }  
	            //3、需要删除的节点有两个子节点,需要寻找该节点的后续节点替代删除节点  
	            else {  
	                Node successor = getSuccessor(current);  
	                //如果该节点为根节点,将后继节点变为根节点,并将根节点的左子节点变为后继节点的左子节点  
	                if (current == root) {  
	                    root = successor;  
	                } else {  
	                    //如果该节点是父节点的左子节点,将该节点的后继节点变为父节点的左子节点  
	                    if (isLeftChild) {  
	                        parent.leftChild = successor;  
	                    } else {  //如果该节点是父节点的右子节点,将该节点的后继节点变为父节点的右子节点  
	                        parent.rightChild = successor;  
	                    }  
	                }  
	            }  
	            current = null;  
	            return true;  
	        }  
	        public static void main(String[] args){
	        	
	        	Btree bt = new Btree(52);
	  
	             bt.insert(580);  
	             bt.insert(12);  
	             bt.insert(50);  
	             bt.insert(58);  
	             bt.insert(9);  
	             bt.insert(888);  
	             bt.insert(248);  
	             bt.insert(32);  
	             bt.insert(666);  
	             bt.insert(455);  
	             bt.insert(777);  
	             bt.insert(999);  
	        	 bt.postOrderTraverse();
	        	 bt.inOrderTraverse();   
//	           bt.delete(32);      //删除叶子节点  
//	           bt.delete(50);      //删除只有一个左子节点的节点  
//	           bt.delete(248);      //删除只有一个右子节点的节点  
	           bt.delete(580);      //删除有两个子节点的节点,且后继节点为删除节点的右子节点的左后代  
//	           bt.delete(888);      //删除有两个子节点的节点,且后继节点为删除节点的右子节点  
//	             bt.delete(52);       //删除有两个子节点的节点,且删除节点为根节点  
	               
	             bt.inOrderTraverse();     
	        	
	        }
}
中序递归:9,12,32,50,52,58,248,455,580,666,777,888,999,
中序递归:9,12,32,50,52,58,248,455,666,777,888,999,

先对比图理解。

查看评论

二叉树遍历、插入、删除等常见操作

1.二叉查找树的创建 2.二叉查找树清空 3.二叉查找树查询 4.查找最大值、最小值 5.二叉查找树插入操作 6.二叉查找树的删除操作 7.分别使用非递归和递归方式(部分用多种方式)实现树的先序遍历、...
  • u013074465
  • u013074465
  • 2014-12-03 17:27:55
  • 7622

排序二叉树的插入和删除

http://liyiwen.iteye.com/blog/345801 void insert(node *& head, int z) { if (head == NULL) {...
  • sunmenggmail
  • sunmenggmail
  • 2012-09-30 22:59:34
  • 3017

二叉树的创建,遍历,查找,删除,插入,修改

二叉树的创建方法:递归,非递归。(创建方法不存在前中后序)
  • xlsernt_sina_com
  • xlsernt_sina_com
  • 2014-05-25 11:38:13
  • 517

二叉树实验报告

实验要求 1、 创建二叉树类。二叉树的存储结构使用链表。 2、 提供操作:前序遍历、中序遍历、后序遍历、层次遍历、计算二叉树结点数目、计算二叉树高度。 3、 对建立好的二叉树,执行上述各操作。 ...
  • Findxiaoxun
  • Findxiaoxun
  • 2014-02-28 13:54:09
  • 1556

10. 二叉树的建立与基本操作

10. 二叉树的建立与基本操作 成绩 10 开启时间 2014年11月14日 Friday 14:00 折扣 0.8 折扣时间 ...
  • liuyi005
  • liuyi005
  • 2014-12-10 23:29:47
  • 1220

c++使用二叉树进行查找 插入 删除

  • 2013年07月14日 20:55
  • 6KB
  • 下载

二叉查找树中节点的删除。

今天,在写数据结构的二叉查找树时,写到remove方法时,突然卡壳了。后来,打开书细看时,竟然耗费了不少时间才看懂。     现将思想记录下来,以免以后再次遗忘。     二叉查找树重要性质: ...
  • sb1ue
  • sb1ue
  • 2013-05-13 21:12:19
  • 24663

二叉树的各种概念以及代码操作

二叉树的各种概念以及代码操作一、基本概念 * 每个结点最多有两棵子树,左子树和右子树,次序不可以颠倒。 性质: 1. 非空二叉树的第n层上至多有2^(n-1)个元素。 2. 深...
  • wgyscsf
  • wgyscsf
  • 2017-03-18 12:26:44
  • 987

二叉树遍历与删除

前面写过二叉树的节点插入与查找关键数据项以及最值的数据项。二叉树的删除与遍历是另外一项重要的操作。特别是二叉树的人删除比较复杂,分为无子节点的节点删除,只有一个子节点的节点删除和有两个子节点的节点删除...
  • cai2016
  • cai2016
  • 2016-09-20 23:18:31
  • 3674

二叉树的操作建立删除

  • 2010年07月10日 15:20
  • 625KB
  • 下载
    个人资料
    持之以恒
    等级:
    访问量: 20万+
    积分: 3503
    排名: 1万+
    最新评论