zoukankan      html  css  js  c++  java
  • 算法补充 2011912

    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;
          }
    
  • 相关阅读:
    request常用的方法
    JS通过正则限制 input 输入框只能输入整数、小数(金额或者现金)
    基于云原生的秒杀系统设计思路
    html<input>输入框中各种正则表达式设置
    cursor:hand与cursor:pointer的区别介绍
    读入/输出优化
    手动扩栈,防止溢出
    快速乘(O(1))
    二分图若干性质
    康拓展开
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/2173981.html
Copyright © 2011-2022 走看看