Binary tree

      以前有学过的LinkedList和Orded Array。。这两种数据结构有利有弊。

  • LinkedList在插入和删除某个Node的时候只需要更改这个Node的指向下(上)一个Node的referrence就可以了,而Order Array因为在插入和删除某个Node之后必须保持整个数组的有序性,必须要做很多的Node移动,比如在一个升序的数组中要删除其中一个Node,就必须把删除掉的Node之后的Nodes向前移一格。Insert和Delete的快速是LinkedList的优势。
  • Orded Array在search的时候就比LinkedList快速的多。Orded Array可以通过Binary search来搜索想要的Node。search是Orded Array的优势。

    而Binary Tree正是能将2者的优势集中体现的一种数据结构。

树的定义我就不说了。Binary Tree就是每个结点最多有两个子结点的树。

二叉树结点的定义:       

class Node
{
        int iData; // data used as key value
        float fData; // other data
        node leftChild; // this node's left child
        node rightChild; // this node's right child
        public void displayNode()
        {
               // method body}
}

二叉树的定义:

class Tree
{
        private Node root;             // the only data field in Tree
        public void find(int key)
        {
        }
        public void insert(int id, double dd)
        {
        }
        public void delete(int id)
        {
        }
        // various other methods
} // end class Tree

树的类只有一个root结点,其他结点可以通过leftChild,rightChild referrence来得到。。。

因为二叉树是一个有序的:leftChild<parent;rightChild>parent。。。。所以在find的时候就可以在父结点上进行比较,若要找的值大于父结点的key就去和rightChild的key再进行比较,反之和leftChild的key进行大小比较,这样一直向下找,直到找到为止

class 
{
         public Node find(int key)
         {
                  Node current = root;
                  while(current.key!=key)
                  {
                           if(current.key<key)
                                    current = current.leftChild;
                           else
                                    current = current.rughtChild;
                           if(current.key==key)
                                    return null;
                  }
                  return current;
         }
}

insert方法也非常的简单,就是用find去查找,一直找到一个null的位置就插入这个Node,值得注意的就是要多设一个Node parent变量以保存上一个非空的Node。因为在找到null的时候,current已经是null了,如果没有了parent就会丢失信息,就不能把上一个非空的Node的合适的child指向inserted child。

public void insert(Node n)
 {
          if(root==null)
                   root = n;
          Node current = root;
          Node parent = root;
          while(true)
          {
                   parent= current;
                   if(n.key<current.key)
                   {
                            current = current.leftChild;
                            if(current==null)
                            {
                                     parent.leftChild = n;
                                     return;
                            }
                   }
                   else
                   {
                            current = current.rightChild;
                            if(current==null)
                            {
                                     parent.rightChild = n;
                                     return;
                            }
                   }
          }
 }

取出Binary Tree里面的结点有3种方式,分别是preOrder,inOrder,postOrder.现在就只介绍inOrder,其他两个在做代数转换的时候有用。

取出结点可以用递归来实现,递归只要分3部来完成:

  1. 不停的找这个结点的左继,一直找到叶的位置。
  2. 打印出这个Node
  3. 找这个结点的右继,一直找到爷的位置。

 public void inOrder(Node current)
 {
          if(current!=null)
          {
                   inOrder(current.leftChild);
                   displayNode(current);
                   inOrder(current.rightChild);
          }
 }

每个递归都有返回的条件,这个递归返回的条件就是当current==null的时候。

 

找出最大值和最小值是件非常简单的事:

public Node minimun()
 {
          Node current.last;
          current = root;
          while(current.leftChild!=null)
          {
                   last = current;
                   current = current.leftChild;
          }
          return last;
 }

找最大值就不赘述。

因为delete方法比较的复杂,下次再说吧。。。

   

现在来说下delete方法。。。

delete要分3种情况:

  1. delete一个叶结点,即没有子结点的结点
  2. delete一个只有一个子结点的结点
  3. delete一个有两个子结点的结点

前两个都比较简单,但是第3个那个是相当的复杂。。。。。

首先是第1种情况,只需先找到要delete的Node,然后将七父结点的相应Child指向null:

public boolean delete(Node d)
 {
           Node parent,current;
           parent=current=root;
           bool isLeftChild = true;
           while(current.key!=d.key)
           {
                     parent = current;
                     if(d.key<current.key)
                     {
                               isLeftChild = true;
                               current = current.leftChild;
                     }
                     else
                     {
                               isLeftChild = false;
                               current = current.rightChild;
                     }
                     if(current == null)
                               return false;
          }       
          if(current.leftChild==null&&current.rightChild==null)
          {
                   if(current==root)
                             root =null;
                   else if(isLeftChild)
                             parent.leftChild = null;
                   else
                             parent.rightChild = null;
         }
         //continues....

删除有一个结点的Node也非常简单,只要将删除结点的唯一结点连到parent的相应Child上就可以了,二叉树仍将保持有序。。。

       //continues....
         if(current.leftChild==null)
         {
                  if(current==root)
                           root = null;
                  else if(isLeftChild)
                           parent.leftChild = current.rightChild;
                  else
                           parent.rightChild = current.rightChild;
         }       
         if(current.rightChild==null)
         {
                  if(current==root)
                           root = null;
                  else if(isLeftChild)
                           parent.leftChild = current.leftChild;
                  else
                           parent.rightChild = current.leftChild;
         }

如果删除的是有两个Child的Node就非常的麻烦了。。。所以在此就不说为什么(why)要这么做了,只说怎么(how)做

在开始说步骤之前,先说一下public Node getSuccessor(Node delNode)方法。。。这个方法是查找delNode的右子树中最小的一个Node.

public void getSuccessor(Node delNode)
 {
          Node parent,current,successor;
          successor = parent = delNode;
          current = delNode.rightChild;
          while(current!=null)
          {
                   parent = successor;
                   succesor = current;
                   current = current.leftChild;
          }
          if(successor!=delNode.rightChild)
          {
                   parent.leftChild = successor.rightChild;
                   successor.rightChild = delNode.rightChild;
          }
          return successor;
 }

//这个方法最后还判断successor是否就是delNode的右自结点,如果不是则要将successor的rightChild与parent的leftChild联系上,还要将delNode的rightChild与successor的rightChild联系上。。。

好了。。现在就来说下删除一个有两个子结点的Node。

  1. 判断要删除的结点是否是root,如果是,直接root = successor。
  2. 将successor与delNode的相关子结点联系上。
  3. 将delNode的leftChild与successor的leftChild联系上。

        //continue...        
          Node seccssor = getSuccssor(current);
          if(current==root)
                   root=successor;
          else if(isLeftChild)
                   successor = parent.leftChild;
          else
                   successor = parent.rightChild;
          successor.leftChild=current.leftChild;
          return true;
  }

整个删除有两个结点的Node过程其实只要注意两个方面。

  • 首先判断successor是否是delNode的rightChild;如果不是,successorParent.leftChild=successor.rightChild,successor.rightChild=delNode.rightChild;如果是,则不做任何处理。这一步被放在getSuccessor方法内
  • getSuccessor方法外,就是将delNode的相关子结点指向successor,successor的leftChild指向delNode的leftChild
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值