穿线二叉树直接忽略了。这几天看了些GMA那些大公司的面试题目,丢,什么都不会。。那些人确实有实力,任重道远啊。
1 二叉搜索树BST
上传一图,方便了解。
插入操作
template<class T>
void BinarySearchTree<T>::InsertNode(
BinaryTreeNode<T>* root ,
BinaryTreeNode<T>* newpointer)
{//向二叉搜索树插入新结点
BinaryTreeNode<T>* pointer=NULL;
if(root==NULL){
//用指针newpointer初始化二叉搜索树树根,赋值实现
Initialize(newpointer);
return;
}
else pointer=root;
while(1){
if(newpointer->value()==pointer->value())
return ;
//相等则不用插入
else if(newpointer->value()<pointer->value()) {
if(pointer->leftchild()==NULL){
pointer->left=newpointer;//作为左子树 只要弄清楚这里即可,由于new的关键码值小于pointer,就要进入左子树,所以判断左子树是否为空
return;
}
else pointer=pointer->leftchild();
}
else{
//作为右子树
if(pointer->rightchild()==NULL) {
pointer->right=newpointer;
return;
}
else pointer=pointer->rightchild();
}//end else
}//end while
}
删除操作较复杂些,从二叉搜索树里删除一个结点时,不能把以这个结点为根的子树都删除掉,只能删除掉这一个结点,并且还要保持二叉搜索树原来的性质。这就意味着要进行完整的“脱链”和“挂钩”操作。
普通想法:
设p,p1,r是指针变量,p↑表示s要删除的结点,p1↑表示p↑的父母结点,则删除可以按如下规定进行:
若结点p↑没有左子树,则用右子树的根代替被删除的结点p↑
若结点p↑有左子树,则在左子树里找按中序周游的最后一个结点r↑,将r↑的右指针置成指向p↑的右子树的根,然后用结点p↑的左子树的根去代替被删除的结点p↑
这样树的高度可能会增加许多,比如图中zom可能有很高的子树。
template<class T>
void BinarySearchTree<T>::DeleteNode(BinaryTreeNode<T>* pointer){ //二叉搜索树的删除
BinaryTreeNode<T>* temppointer=NULL;
BinaryTreeNode<T>*parent=GetParent(root,pointer);
//被删结点无左子树吗?
if(pointer->leftchild() == NULL)
{//被删除结点是根结点吗?
if(parent == NULL) //下面可以简化,temppointer=pointer->rightchild();
root=pointer->rightchild();
else if(parent->leftchild()==pointer)
parent->left=pointer->rightchild();
else
parent->right=pointer->rightchild();
delete pointer;
pointer=NULL;
return;
}
else temppointer=pointer->leftchild();
//在左子树中找对称序的最后一个结点
while(temppointer->rightchild()!=NULL)
temppointer=temppointer->rightchild();
//被删除结点的右子树作为temppointer的右子树
temppointer->right=pointer->rightchild();
//被删除结点的左子树根代替被删除结点
if(parent==NULL)
root=pointer->leftchild();
else if(parent->leftchild()==pointer)
parent->left=pointer->leftchild();
else
parent->right=pointer->leftchild();
delete pointer;
pointer=NULL;
return;
}
改进想法:
若结点p↑没有左子树,则用右子树的根代替被删除的结点p↑(相同)
若结点p↑有左子树,则在左子树里找按中序周游的最后一个结点r↑,将r↑的右指针置成指向p↑的右子树的根,然后用结点r↑去代替被删除的结点p↑
这样树的高度可能维持不变或者减少。即保持性质之后要考虑性能。
template <class T> void BinarySearchTree<T>::DeleteNodeEx
(BinaryTreeNode<T>* pointer)
{//若待删除结点不存在,返回
if( pointer == NULL )
return;
//保存替换结点
BinaryTreeNode<T> * temppointer;
//保存替换结点的父结点 该用的时候还是用上啊
BinaryTreeNode<T> * tempparent = NULL;
//保存删除结点的父结点
BinaryTreeNode<T> * parent = GetParent(root ,pointer );
//如果待删除结点的左子树为空,就将它的右子树代替它
if( pointer->leftchild() == NULL )
temppointer=pointer->rightchild();
else{
//当待删除结点左子树不为空,就在左子树中寻找最大结点替换待删除结点
temppointer = pointer->leftchild();
while(temppointer->rightchild() != NULL )
{
tempparent = temppointer;
temppointer = temppointer->rightchild(); //精妙啊
}
//删除替换结点
if(tempparent==NULL) //做边界检查
pointer->left=temppointer->leftchild(); //就是删除结点的左孩子结点,这样连接就跳过一个temppointer结点
else tempparent->right=temppointer->leftchild();
temppointer->left=pointer->leftchild(); //要挂好钩
temppointer->right=pointer->rightchild();
}
//用替换结点去替代真正的删除结点
if(parent==NULL)
root=temppointer;
else if( parent->leftchild() == pointer )
parent->left=temppointer;
else parent->right=temppointer;
delete pointer;
pointer=NULL;
return;
}