算法补充 2011-9-12
2011-09-12 11:37 Clingingboy 阅读(436) 评论(0) 编辑 收藏 举报
- 设计一个算法将顺序表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 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这些节点
- 先找到要删除的节点,并记录该节点属于左节点还是右节点
- 判断要删除的节点是否为没有子节点,如果确实没有的话,就将其父节点的其中的一个左右节点置空
执行第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步相同,还是先找到要删除的节点.
- 若该节点的右节点为空,则将左节点提升为父亲节点
- 若该节点的左节点为空,则将右节点提升为父亲节点
- 从以上两点可得知将剩余子节点提升为父亲节点
- 根据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.二叉排序树的中序遍历
如上图
二叉排序树的中序遍历的值是一个升序排列,以上结果为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 child
while(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 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;
可以看到删除一个后继的动作相当的复杂
- 改变了其右节点的父亲节点
- 改变了其右节点
- 改变其父亲节点
- 改变了其左节点
完整删除代码示例(来自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;
}