- 设计一个算法将顺序表L中所有小于0的整数放前半部分,大于等于0的整数放在后半部分
- 二叉树的删除
设计一个算法将顺序表L中所有小于0的整数放前半部分,大于等于0的整数放在后半部分
思路:从左侧找出>0的元素,从右侧找出<=0的元素,然后进行交换
static void Move(SqList &l)
{int i=0,j=l.length-1;while(i<j){//position from left to rightwhile(i<j && l.elem[i]<0)i++;//position from right to leftwhile(i<j && l.elem[j]>=0)j--;//swapif(i<j){int temp=l.elem[i];l.elem[i]=l.elem[j];l.elem[j]=temp;}}
}
二叉树的删除
情况1:删除没有子节点的节点
即删除6,7,8,9,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 &¤t.rightChild==null){if(current == root) // if root,root = null; // tree is emptyelse if(isLeftChild)parent.leftChild = null; // disconnectelse // from parentparent.rightChild = null;}
情况2:有一个子节点的节点
第1步如情况1的第1步相同,还是先找到要删除的节点.
- 若该节点的右节点为空,则将左节点提升为父亲节点
- 若该节点的左节点为空,则将右节点提升为父亲节点
- 从以上两点可得知将剩余子节点提升为父亲节点
- 根据isLeftChild标志判断删除的节点是否为左节点
执行步骤1和步骤4
if(current.rightChild==null)if(current == root)root = current.leftChild;else if(isLeftChild)parent.leftChild = current.leftChild;elseparent.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;elseparent.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.二叉排序树的中序遍历
如上图
二叉排序树的中序遍历的值是一个升序排列,以上结果为15,20,25,30,50,60,70
寻找具有有两个子节点的节点的替补节点
如要删除该节点,要么被代替的节点需要具备以下特征:
- 比该节点的左节点大
- 比该节点的右节点小
如果无法满足以上两点,情况将变的更加复杂.
如要删除节点20,那么节点30则是最佳替补(这里如果有个节点25则更加说明这个情况).
节点25比15大,比30小.
中序后继:由于25在20后面,则成25为节点20的后继.所以当遇到要删除有两个节点的节点时,首要目标就是找到该节点的后继节点,以上的铺垫1内容就是为这里准备的。查找后继节点规则:
- 如果有左节点,则最深处左节点为后继节点
- 如果没有左节点,则第一个右节点为后继节点(如50的后继节点为60)
以下代码体现了以上2个步骤
private Node getSuccessor(Node delNode){Node successorParent = delNode;Node successor = delNode;Node current = delNode.rightChild; // go to right childwhile(current != null) // until no more{ // left children,successorParent = successor;successor = current;current = current.leftChild; // go to left child}return successor;}
删除中序后继节点
找到中序后继后,还要处理一些事情.来考虑一个中序后继的一些特点:
- 一定没有左节点(如果有就不是后继了,可以继续往左节点找)
- 但有可能会有右节点
所以要按照情况2只有右节点的原则处理该右继节点
链接中序后继的右节点
即要删除的节点的右节点变成了中序后继节点的右节点了
所以在getSuccessor方法中while循环结束后,还需要做以下处理
if(successor != delNode.rightChild) // right child,{ // make connectionssuccessorParent.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;
elseparent.rightChild = successor;// connect successor to current's left child
successor.leftChild = current.leftChild;
可以看到删除一个后继的动作相当的复杂
- 改变了其右节点的父亲节点
- 改变了其右节点
- 改变其父亲节点
- 改变了其左节点
完整删除代码示例(来自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 itif(current.leftChild==null &¤t.rightChild==null){if(current == root) // if root,root = null; // tree is emptyelse if(isLeftChild)parent.leftChild = null; // disconnectelse // from parentparent.rightChild = null;}// if no right child, replace with left subtreeelse if(current.rightChild==null)if(current == root)root = current.leftChild;else if(isLeftChild)parent.leftChild = current.leftChild;elseparent.rightChild = current.leftChild;// if no left child, replace with right subtreeelse if(current.leftChild==null)if(current == root)root = current.rightChild;else if(isLeftChild)parent.leftChild = current.rightChild;elseparent.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 insteadif(current == root)root = successor;else if(isLeftChild)parent.leftChild = successor;elseparent.rightChild = successor;// connect successor to current's left childsuccessor.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 descendentsprivate Node getSuccessor(Node delNode){Node successorParent = delNode;Node successor = delNode;Node current = delNode.rightChild; // go to right childwhile(current != null) // until no more{ // left children,successorParent = successor;successor = current;current = current.leftChild; // go to left child}// if successor notif(successor != delNode.rightChild) // right child,{ // make connectionssuccessorParent.leftChild = successor.rightChild;successor.rightChild = delNode.rightChild;}return successor;}