代码改变世界

算法补充 2011-9-12

2011-09-12 11:37  Clingingboy  阅读(436)  评论(0编辑  收藏  举报

 

  1. 设计一个算法将顺序表L中所有小于0的整数放前半部分,大于等于0的整数放在后半部分
  2. 二叉树的删除

设计一个算法将顺序表L中所有小于0的整数放前半部分,大于等于0的整数放在后半部分

思路:从左侧找出>0的元素,从右侧找出<=0的元素,然后进行交换

static void Move(SqList &l)
{
    int i=0,j=l.length-1;
    while(i<j)
    {
        //position from left to right
        while(i<j && l.elem[i]<0)
            i++;
        //position from right to left
        while(i<j && l.elem[j]>=0)
            j--;
        //swap
        if(i<j)
        {
            int temp=l.elem[i];
            l.elem[i]=l.elem[j];
            l.elem[j]=temp;
        }

    }
}

 

二叉树的删除

 

情况1:删除没有子节点的节点

即删除6,7,8,9,2这些节点

image

  1. 先找到要删除的节点,并记录该节点属于左节点还是右节点
  2. 判断要删除的节点是否为没有子节点,如果确实没有的话,就将其父节点的其中的一个左右节点置空

执行第1步,查找节点如果current不为空则执行第2步

      Node current = root;
      Node parent = root;
      boolean isLeftChild = true;

      while(current.iData != key)        // search for node
         {
         parent = current;
         if(key < current.iData)         // go left?
            {
            isLeftChild = true;
            current = current.leftChild;
            }
         else                            // or go right?
            {
            isLeftChild = false;
            current = current.rightChild;
            }
         if(current == null)             // end of the line,
            return false;                // didn't find it
         }  // end while
      // found node to delete

执行第2步,判断左右节点均未空

// if no children, simply delete it
if(current.leftChild==null &&
                             current.rightChild==null)
   {
   if(current == root)             // if root,
      root = null;                 // tree is empty
   else if(isLeftChild)
      parent.leftChild = null;     // disconnect
   else                            // from parent
      parent.rightChild = null;
   }

情况2:有一个子节点的节点

第1步如情况1的第1步相同,还是先找到要删除的节点.

  1. 若该节点的右节点为空,则将左节点提升为父亲节点
  2. 若该节点的左节点为空,则将右节点提升为父亲节点
  3. 从以上两点可得知将剩余子节点提升为父亲节点
  4. 根据isLeftChild标志判断删除的节点是否为左节点

执行步骤1和步骤4

if(current.rightChild==null)
   if(current == root)
      root = current.leftChild;
   else if(isLeftChild)
      parent.leftChild = current.leftChild;
   else
      parent.rightChild = current.leftChild;

执行步骤2和步骤4

// if no left child, replace with right subtree
if(current.leftChild==null)
   if(current == root)
      root = current.rightChild;
   else if(isLeftChild)
      parent.leftChild = current.rightChild;
   else
      parent.rightChild = current.rightChild;

情况3:删除有两个子节点的节点

铺垫:

1.查找二叉排序树的最大值和最小值

因为二叉树的的节点总是大于左节点,小于右节点的,所以顺着左节点总是能找到最小值,同理顺着右节点总是能找到最大值

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

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

2.二叉排序树的中序遍历

image

如上图

二叉排序树的中序遍历的值是一个升序排列,以上结果为15,20,25,30,50,60,70

 

寻找具有有两个子节点的节点的替补节点

如要删除该节点,要么被代替的节点需要具备以下特征:

  1. 比该节点的左节点大
  2. 比该节点的右节点小

如果无法满足以上两点,情况将变的更加复杂.

如要删除节点20,那么节点30则是最佳替补(这里如果有个节点25则更加说明这个情况).
节点25比15大,比30小.

中序后继:由于25在20后面,则成25为节点20的后继.所以当遇到要删除有两个节点的节点时,首要目标就是找到该节点的后继节点,以上的铺垫1内容就是为这里准备的。查找后继节点规则:

  1. 如果有左节点,则最深处左节点为后继节点
  2. 如果没有左节点,则第一个右节点为后继节点(如50的后继节点为60)

以下代码体现了以上2个步骤

private Node getSuccessor(Node delNode)
   {
   Node successorParent = delNode;
   Node successor = delNode;
   Node current = delNode.rightChild;   // go to right child
   while(current != null)               // until no more
      {                                 // left children,
      successorParent = successor;
      successor = current;
      current = current.leftChild;      // go to left child
      }
   return successor;
   }

删除中序后继节点

找到中序后继后,还要处理一些事情.来考虑一个中序后继的一些特点:

  1. 一定没有左节点(如果有就不是后继了,可以继续往左节点找)
  2. 但有可能会有右节点

所以要按照情况2只有右节点的原则处理该右继节点

链接中序后继的右节点

即要删除的节点的右节点变成了中序后继节点的右节点了

所以在getSuccessor方法中while循环结束后,还需要做以下处理

if(successor != delNode.rightChild)  // right child,
   {                                 // make connections
   successorParent.leftChild = successor.rightChild;
   successor.rightChild = delNode.rightChild;
   }

链接中序后继的左节点

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;

可以看到删除一个后继的动作相当的复杂

  1. 改变了其右节点的父亲节点
  2. 改变了其右节点
  3. 改变其父亲节点
  4. 改变了其左节点

完整删除代码示例(来自Java数据结构和算法)

   public boolean delete(int key) // delete node with given key
      {                           // (assumes non-empty list)
      Node current = root;
      Node parent = root;
      boolean isLeftChild = true;

      while(current.iData != key)        // search for node
         {
         parent = current;
         if(key < current.iData)         // go left?
            {
            isLeftChild = true;
            current = current.leftChild;
            }
         else                            // or go right?
            {
            isLeftChild = false;
            current = current.rightChild;
            }
         if(current == null)             // end of the line,
            return false;                // didn't find it
         }  // end while
      // found node to delete

      // if no children, simply delete it
      if(current.leftChild==null &&
                                   current.rightChild==null)
         {
         if(current == root)             // if root,
            root = null;                 // tree is empty
         else if(isLeftChild)
            parent.leftChild = null;     // disconnect
         else                            // from parent
            parent.rightChild = null;
         }

      // if no right child, replace with left subtree
      else if(current.rightChild==null)
         if(current == root)
            root = current.leftChild;
         else if(isLeftChild)
            parent.leftChild = current.leftChild;
         else
            parent.rightChild = current.leftChild;

      // if no left child, replace with right subtree
      else if(current.leftChild==null)
         if(current == root)
            root = current.rightChild;
         else if(isLeftChild)
            parent.leftChild = current.rightChild;
         else
            parent.rightChild = current.rightChild;

      else  // two children, so replace with inorder successor
         {
         // 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 two children
      // (successor cannot have a left child)
      return true;                                // success
      }  // end delete()
// -------------------------------------------------------------
   // returns node with next-highest value after delNode
   // goes to right child, then right child's left descendents
   private Node getSuccessor(Node delNode)
      {
      Node successorParent = delNode;
      Node successor = delNode;
      Node current = delNode.rightChild;   // go to right child
      while(current != null)               // until no more
         {                                 // left children,
         successorParent = successor;
         successor = current;
         current = current.leftChild;      // go to left child
         }
                                           // if successor not
      if(successor != delNode.rightChild)  // right child,
         {                                 // make connections
         successorParent.leftChild = successor.rightChild;
         successor.rightChild = delNode.rightChild;
         }
      return successor;
      }