二叉搜索树(BST)的前驱后继、插入删除函数

二叉搜索树性质:
1、左子树上所有结点的值均小于或等于它的根结点的值。
2、右子树上所有结点的值均大于或等于它的根结点的值。
最大堆性质:
1、两个子树上所有节点的值均不大于它的根结点的值。

1、前驱与后继:
对一棵二叉树进行中序遍历(不是层序),遍历后的顺序,当前节点的前一个节点为该节点的前驱节点;当前节点的后一个节点为该节点的后继节点。
1.1 对于二叉搜索树:
结点x的前驱节点:小于x.key的最大关键字节点(6的前驱4,7的前驱6,17的前驱15);
结点x的后继节点:大于x.key的最小关键字节点(6的后继7,7的后继9,13的后继15);
在这里插入图片描述
后继伪代码:

int TreeSuccessor(node x)
{
    
    
	if(x.right != NULL) return Tree_minmum(x.right);
	y = x.p;
	while(y!=NULL && x ==y.right){
    
     //若x为右节点,则后继为最低的祖先且其左孩子也是祖先(13的后继15)
		x = y;
		y = y.p;
	}
	return y; //若x为左节点,则返回父节点
}

2、插入与删除:
2.1、插入:
新插入的节点永远为叶子节点,因此,找到的合适位置为空,记录该空节点的父节点用于插入。
插入伪代码:

void TreeInsert(Tree T, node z)
{
    
    
	y = NULL;
	x = T.root; //x用于找位置指导为空即找到,y为x的父节点
	while(x != NULL){
    
    
		y = x;
		if(z.key<x.key){
    
    
			x = x.left;
		}else{
    
    
			x = x.right;
		}
	}
	z.p = y;
	if(y == NULL){
    
     // 树为空
		T.root = z;
	}
	else if (z.key<y.key){
    
    
		y.left = z;
	}
	else{
    
    
		y.right = z;
	}
}

13插入到15下边:
13插入到15下边
2.2、删除:
分为三种情况:
在这里插入图片描述
a)简单情况: 只有一个孩子或没有孩子,则用另一个孩子或NULL代替z
在这里插入图片描述
b)复杂情况: 有两个孩子,分为右孩子为其后继与否两种情况。
宗旨:代替z的为其后继y(大于z的最小值)

b1)右孩子为其后继:用后继y代替z
在这里插入图片描述
右孩子为后继(大于他的最小值),表明该右孩子没有左孩子。
在这里插入图片描述
b2)右孩子不为其后继:用后继y的右孩子代替yy代替z
在这里插入图片描述
在这里插入图片描述
伪代码:

// v数代替u树的小函数
void Transplant(Tree T, node u,node v)
{
    
    
	if(u.p = NULL) t.root = v;
	else if(u = u.p.left) u.p.left = v;
	else u.p.right = v;
	if(v != NULL) v.p = u.p;
}

删除节点函数:
在这里插入图片描述
**参考资料:**算法导论:12.2节 查询二叉搜索树 与 12.3节 插入与删除

总结:

1、二叉搜索树性质:左子树上所有节点小于根节点(右子树大于)。
2、前驱与后继指的是中序遍历后的节点。
3、二叉搜索树的后继(前驱)为大于(小于)该节点的最小(最大)节点。
4、二叉搜索树中新插入的节点永远为叶子节点,从根节点开始比较直到为空的叶节点。(和堆中插入节点不一样,堆中先放在堆的末尾,然后和根节点比较,大则上移)。
5、二叉搜索树中删除:只有一个孩子或没有孩子,则用另一个孩子或NULL代替删除的节点z;有两个孩子,则用其后继代替。
6、二叉搜索树上基本操作(插入、删除、前驱、后继、最大、最小)时间与树的高度成正比,因为期望高度为lg(n),因此,平均运行时间为lg(n)。
7、红黑树最坏运行时间为lg(n)。

猜你喜欢

转载自blog.csdn.net/qq_33726635/article/details/105714521