算法学习----二叉树的查找、 删除、插入、遍历

算法学习----二叉树的查找、 删除、插入 、遍历

为什么要使用二叉树呢?

       为什么要用到树呢?因为它通常结合了另外两种数据结构的优点:一种是有序数组,另一种是链表。在树中查找数据项的速度和在有序数组中查找一样快,并且插入数据项和删除数据项的速度也和链表一样。

这里开始程序之前先创建一个节点类,程序如下:

<span style="font-size:18px;">public class Node {
	public int iData; // id
	public double dData; // ElemData
	public Node leftChild;
	public Node rightChild;
	
	public void display(){
		System.out.print("{"+iData+","+dData+"}");	
	}
}</span>



A  查找
根据关键值key 查找节点比较简单,直接上代码。

<span style="font-size:18px;">public Node find (int key){
		Node current = root;
		while(key != current.iData){
			if (key < current.iData){
				current = current.leftChild;
			}
			else
				current = current.rightChild;
			if(current == null){
				return null;
			}
		}
		return current;
	}</span>


B 插入
插入思想:插入一个元素,与根节点比较,如果为空,直接插入,如果相等,不插入  
          如果小于节点,则看左节点,左节点空则插入,不空则与左节点继续上面比较.
          如果大于节点,则看右节点,右节点空则插入,不空则与右节点继续上面比较.
代码实现:
 
<span style="font-size:18px;">/* 
	 **************************************** 
	 *         排序二叉树的插入                * 
	 *  插入一个元素,与根节点比较,如果为空,直接插入,如果相等,不插入  * 
	 *  如果小于节点,则看左节点,左节点空则插入,不空则与左节点继续上面比较.* 
	 *  如果大于节点,则看右节点,右节点空则插入,不空则与右节点继续上面比较.*
	 **************************************** 
	 */  
	
	public void insert(int id,double dd){
		Node newNode = new Node();
		newNode.iData = id;
		newNode.dData = dd;  //get the Node
		
		if (root == null)
			root = newNode; 
		else {
			Node current = root; //start as root
			Node parent;
			while(true){ //search the Node
				parent = current;
				if(id < current.iData){
					current = current.leftChild;
					if (current == null) {
						parent.leftChild = newNode;
						return;
					} 
				}  //end of go to left 
				
				else {
					current = current.rightChild;
					if(current == null){
						parent.rightChild = newNode;
						return;
					}
				}   //end of go to right 
			}
		}
	}</span>

C 删除

    删除节点是二叉搜索树常用的一般操作中最复杂的。
    删除节点要从查找要删的节点开始入手,方法与前面介绍的findO和insertO相同。找到节点后,
这个要删除的节点可能会有三种情况需要考虑:
1.该节点是叶节点(没有子节点) 。
2 . 该节点只有一个子节点。
3 . 该节点有两个子节点。
其中,第一种最简单:第L种也还是比较简单的:而第三种就相当复杂。

 情况一:要删除叶节点,只需要改变该节点的父节点的对应子字段的值,由指向该节点、改为null 就可以
了。要删除的节点仍然存在,但它已经不是树的一部分了。因为Java 语言有垃圾自动收集的机制,所以不需要非得把节点本身给删掉。一旦Java 意识到程序不再与这个节点有关联,就会自动把它清理出存储器。
情况二:删除的节点只有一个子节点。这类节点只有两个连接,一个是连接它的父类节点,一个是连接它的子类节点;我们需要从这个序列中“剪段”这个节点,把它的子节点直接连在其父节点上。这个过程要求改变父类节点适当的引用(左子节点还是右子节点),指向要删除节点的子节点。

情况三:删除的节点有两个子节点:主要思路是先找到其后继节点。
什么是后继节点呢?简单说就是比初始节点大的最小值。
其作用是: 后继节点就是要替换该删除节点的在树中的位置节点。
如何找后继节点呢? 从要删除节点的第一个右子节点开始找.找其左子节点,一直到最后一个左子节点为空为止。这是由二叉树的性质决定的,请仔细想想。
 然后,怎么删除节点呢?
  其思路是: 1 把后继父节点的左子节点LeftChild置为后继节点的右子节点;
     2 把后继节点的 右子节点rightChild置为要删除节点的右子节点;
     3 把current从它的父节点的rightChild字段移除,把这个字段置为中继节点。
     4 把current的左子节点从current移除,中继的左子节点字段置为current的左子节点。
 具体代码如下:

首先在寻找中继节点的程序:
/*
 * 从要删除节点的第一个右子节点开始找.找其左子节点,一直到最后一个左子节点为空为止
 */
	private Node getSuccessor(Node delNode) {
		
		Node successorParent = delNode;
		Node successor = delNode; 
		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;  
		}
		return successor;
	}



然后是删除节点的程序
  /*
     * 1.被删除节点没有子树的情况,直接删除,并修改对应父节点的指针为空。
     * 2.对于只有一个子树的情况,考虑将其子树作为其父节点的子树,关于是左还是右,根据被删除的节点确定.
     * 3.最复杂的是有两个子数的情况,可以考虑两种方法,都是同样的思想:用被删除节点A的左子树的最右节点
     *  或者A的右子树的最左节点作为替代A的节点,并修改相应的最左或最右节点的父节点的指针,修改方法类似
  */
	public boolean delete (int key){
		Node current = root;
		Node parent = root;
		boolean isLeftChild = true;
		
		while(current.iData != key){ //search for the Node 
			parent = current;
			if(key < current.iData){
				isLeftChild = true;
				current = current.leftChild;
			}
			else {
				isLeftChild = false;
				current = current.rightChild;
			}
			if(current == null){
				return false;
			}
		} //end of while
		
		/*
		 * find to delete
		 * 被删除节点没有子树的情况,直接删除.并修改对应父节点的指针为空
		 */
		if(current.leftChild == null && current.rightChild == null){
			if(current == root)
				root = null;
			else if(isLeftChild)
				parent.leftChild = null;
			else 
				parent.rightChild = null;
		}
		
		/*
		 * 对于只有一个子树的情况,考虑将其子树作为其父节点的子树,关于是左还是右,根据被删除<span style="white-space:pre">		</span> *  的节点确定
		 */
		else if (current.rightChild == null){
			if(current == root)
				root = current.leftChild;
			else if(isLeftChild)
				parent.leftChild = current.leftChild;
			else
				parent.rightChild = current.leftChild;
		}
		else if(current.leftChild == null){
			if(current == root)
				root = current.rightChild;
			else if(isLeftChild)
				parent.leftChild = current.rightChild;
			else
				parent.rightChild = current.rightChild;
		}
		/*
		 * 最复杂的是有两个子数的情况
		 * replace with inorder successor
		 */
		else {
			//get successor of node to delete(current)
			Node successor = getSuccessor(current);
			
			
			//connect parent of current to successor instead
			if(current == root)
				root = successor;
			else if (isLeftChild)
				parent.leftChild = successor;
			else 
				parent.rightChild = successor;
			
			//connect successor to current's left child
			successor.leftChild = current.leftChild;
		}//end of tow child 
		// (successor cannot have a left child)
		return true;
	} //end delete()


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值