数据结构之树(一)二叉树

1 Tree's Advantage

      Why might you want to use a tree? Usually, because it combines the advantage of two other structures: an ordered array and a linked list. You can search a tree quickly like an ordered array, as you can  also insert and delete items quickly, as you can with a linked list.

    Slow insertion in an ordered array. If you want to insert a new item into an ordered array, you first need to find where the item will go, and then move  all the items with greater keys up on space in the array to make room for it. These multiple moves are time-consuming. Deletion involves the same multimove operation and is thus equally slow.

     Slow searching in a linked list. Finding a specified element in a linked list is not so easy. You must start at the beginning of the list and visit each element until you find the one you're looking for.

2 Binary Search Tree

       A binary search tree has these characteristics: A node's left child must have a key less than its parent, and a node's right child must have a key greater than or equal to its parent.  The following figure shows a binary search tree. 

      A binary search tree average time takes O(log n), the best time takes O(n) which occurs when the items in the tree are already sorted that are all in one side of the tree.


 2.1 Trees Represented as References     

Binary Tree implement in java. Node object like this:

package zyang.tree.binaryTree;

/** 
 * @author  
 * @version 1.0
 * @date    2012-12-9 上午10:05:35 
 * @fuction 
 */

public class Node 
{
	//-------------------------------
	// property
	//-------------------------------
    int iData;     // the key
    double fData;  // the value
    Node leftChild;
    Node rightChild;
    
	//-------------------------------
	// constructor
	//-------------------------------
    public Node()
    {}
    
    public Node(int iData,double fData)
    {
    	this.iData=iData;
    	this.fData=fData;
    }
    
	//-------------------------------
	// API
	//-------------------------------
    public void display()
    {
    	//TODO:
    }
}

Tree object like this:

package zyang.tree.binaryTree;

/** 
 * @author 
 * @version 1.0
 * @date    2012-12-9 上午10:08:43 
 * @fuction the binary search tree
 */

public class Tree {
	//-------------------------------
	// property
	//-------------------------------
	private Node root; 
	
	//-------------------------------
	// API
	//-------------------------------
	public Node find(int key)
	{      if(root==null)  return;   //input control
		Node current=root; //start at the root
		
		while(current.iData!=key)
		{   
			if(key<current.iData) //go left
				current=current.leftChild;
			else                  //go right
				current=current.rightChild;
			if(current==null)                  //base case: if no child
				return null;
		} //end while
		
		return  current;
	}
	
	public void insert(int id,double dd)
	{	
		//found the node like the find method where to insert until this node has no child ,
		//then insert the insertNode as this node's child
		Node insertNode=new Node(id, dd);
		
		Node current=root;
		Node parent=null;
		
		if(root==null)          //no node in tree
			root=insertNode;
		else
		{
			while(true)
			{
				parent=current;
				if(id<=current.iData)
				{
					current=current.leftChild;
					if(current==null)
					{
						parent.leftChild=insertNode;
						return;
					}				
				} //end if
				else
				{
					current=current.rightChild;
					if(current==null)
					{
						parent.rightChild=insertNode;
						return;
					}						
				}//end else					
			} //end while
		}// end else	
	}
	
	/**
	 * finding the node you want to delete
	 * then considering three cases:
	 * 1. The node to be deleted is a leaf (has no children).
	 * 2. The node to be deleted has one child.
	 * 3. The node to be deleted has two children.
	 * @param key  delete node with given key
	 * @return if the key exit and deletes it, return true, otherwise return false
	 */
	public boolean delete(int key)
	{	
		Node current=root;  // record the delete node
		Node parent=root;   // parent of current node
		boolean isLeftChild=true; // if current is parent's left child,isLeftChild equals true, otherwise false
		
		//find the node with key
		while(current.iData!=key)
		{
			parent=current;
			if(key<current.iData)
			{
				isLeftChild=true;
				current=current.leftChild;
			}//end if
			else
			{
				isLeftChild=false;
				current=current.rightChild;
			} //end else
			if(current==null)
				return false;    //didn't find
		} //end while
		
		//found node to delete
		//---case 1: The node to be deleted is a leaf (has no children).
		//specialized situation: the delete node is the root
		if(current.leftChild==null && current.rightChild==null)
		{
			if(current==root)   //if the found node is root
				root=null;
			else if(isLeftChild)
				parent.leftChild=null;
			else 
				parent.rightChild=null;
		} //end if

		//---case 2: The node to be deleted has one child.
		//specialized situation: the node to be deleted may be the root, in which case it has no parent and is simply replaced by the appropriate subtree.
		else if(current.rightChild==null)  //if no right child,replace with left subtree
		{
			if(current==root)
				root=current.leftChild;
			else if(isLeftChild)
				parent.leftChild=current.leftChild;
			else
				parent.rightChild=current.rightChild;
		}//end else if	
		else if(current.leftChild==null) //if no left chuld
		{
			if(current==root)
				root=current.rightChild;
			else if(isLeftChild)
				parent.leftChild=current.leftChild;
			else
				parent.rightChild=current.rightChild;
		} //end else if
		
		//---base case3: The node to be deleted has two children.
		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 else
		
		return true;	
	}
	
	/**
	 * find the successor which is the smallest of the set of nodes that are larger than the deleted node
	* the algorithm of finding the successor:
		First, the program goes to the original node’s right child, which must have a key
larger than the node. Then it goes to this right child’s left child (if it has one), and to
this left child’s left child, and so on, following down the path of left children. The
last left child in this path is the successor of the original node, as shown in Figure
    *specialized situation: successor is the delete node's right child, so successor has no left child
	 * @param delNode  the deleted node
	 * @return the successor node which has made connection already
	 */
	private Node getSuccessor(Node delNode)
	{
		Node successorParent=delNode;
		Node successor=delNode;
		Node current=delNode.rightChild; //go to right node
		while(current!=null)
		{
			successorParent=successor;
			successor=current;
			current =current.leftChild;  //go to left node
		} //end while
		
		//if successor not the delete node's right child, making connections
		if(successor!=delNode.rightChild)
		{
			successorParent.leftChild=successor.rightChild;
			successor.rightChild=delNode.rightChild;
		}//end if
		return successor;
	}
	
	/**
	 * postOrder(先序遍历)
	 * 思想:
	 * step1: do something with the node
	 * step2: visit the node's left child
	 * step3: visit the node's right child
	 * base case: the node passed as an argument is null
	 * @param localRoot
	 */
	public void traversePreOrder(Node localRoot)
	{
		if(localRoot!=null)
		{
			System.out.println(localRoot.iData);
			traversePostOrder(localRoot.leftChild);
			traversePostOrder(localRoot.rightChild);
		}// end if
	}
	
	/**
	 * inOrder(中序遍历LCR:中序遍历可以得到由小到大的有序序列)
	 * 思想:
	 * step1: visit the node's left child
	 * step2: do something with the node
	 * step3: visit the node's right child
	 * base case: the node passed as an argument is null
	 * @param localRoot the node to visit
	 */
	public void traverseInOrder(Node localRoot)
	{
		if(localRoot!=null) 
		{
			traverseInOrder(localRoot.leftChild);
			System.out.println(localRoot.iData);
			traverseInOrder(localRoot.rightChild);		
		} //end if
	}
	
	/**
	 * postOrder(后序遍历)
	 * 思想:
	 * step1: visit the node's left child
	 * step2: visit the node's right child
	 * step3: do something with the node
	 * base case: the node passed as an argument is null
	 * @param localRoot
	 */
	public void traversePostOrder(Node localRoot)
	{
		if(localRoot!=null)
		{
			traversePostOrder(localRoot.leftChild);
			traversePostOrder(localRoot.rightChild);
			System.out.println(localRoot.iData);
		}// end if
	}

	public Node minimum()
	{
		Node current=root;
		Node last=null;
		
		while(current!=null)
		{
			last=current;  //remember the node
			current=current.leftChild; //go to left child
		} //end while
		return last;
	}
		
}


TreeApp.java is sample about how to use the binary tree

package zyang.tree.binaryTree;

/** 
 * @author  yangzhong  E-mail:yangzhonglive@gmail.com
 * @version 1.0
 * @date    2012-12-9 上午10:13:26 
 * @fuction 
 */

public class TreeApp {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Tree theTree= new Tree();
		
		theTree.insert(50, 1.5);
		theTree.insert(25, 1.7);
		theTree.insert(75, 1.9);
		
		Node found=theTree.find(25);
		if(found!=null)
		{
			System.out.println("Found the node with key 25");
		}
		else
			System.out.println("Could not find node with key 25");
		
		//theTree.traverseInOrder(root);
		
	}
}


 

 2.2 Trees Represented as Arrays

   In the array approach, the nodes are stored in an array and are not linked by references. The position of the node in the array corresponds to its position in the tree.

   Every position in the tree, whether it represents an existing node or not, corresponds to a cell in the array. Adding a node at a given position in the tree means inserting
the node into the equivalent cell in the array. Cells representing tree positions with no nodes are filled with 0 or null.

 If a node’s index number is index, this node’s left child is

2*index + 1
its right child is
2*index + 2
and its parent is
(index-1) / 2

You can check this out by the following picture:


    In most situations, representing a tree with an array isn’t very efficient. Unfilled nodes and deleted nodes leave holes in the array, wasting memory. Even worse, when deletion of a node involves moving subtrees, every node in the subtree must be moved to its new location in the array, which is time-consuming in large trees. 

   However, if deletions aren’t allowed, the array representation may be useful, especially if obtaining memory for each node dynamically is, for some reason, too time-consuming. The array representation may also be useful in special situations, like heap usually implemented as an array.

3 Red Black Tree

   A binary search tree is not unbalanced, we can use balanced trees like red-black tree to improve and guarantee the best time O(log n) of binary tree.

When inserting or deleting a new node, certain rules, which we call the red-black rules., must be followed. If they're followed, the tree will be balanced. The flowing figure is a red black tree.

 

References:

http://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91

Data structure & algorithm in JAVA, Robert Lafore


 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值