【学习笔记】二叉查找树(BST)的实现

这篇学习笔记详细介绍了二叉查找树的实现,包括创建、插入、查找、删除和三种遍历方法(先序、中序、后序)。文章强调了二叉查找树在不平衡时可能退化为链表的问题。
摘要由CSDN通过智能技术生成

前两天想看下红黑树,结果发现基础的二叉查找树都快忘的差不多了,就大概回顾了一下。重写了下代码。

二叉查找树,作为平衡二叉树的基础,每个节点最多有两个孩子,因为不会对自身进行平衡维护,所以容易退化成链表。

创建

//创建节点
void createNode(BSTree **node)
{
	*node = (BSTree *)malloc(sizeof(BSTree));
	(*node)->leftChild = NULL;
	(*node)->rightChild = NULL;
	(*node)->key = -1;
}


插入

//插入节点
_Bool insertNode(BSTree **node, int key)
{
	//先判定是否空指针,是则开辟空间
	if(*node == NULL)
	  createNode(node);

	//再进行插入操作
	if((*node)->key == -1)	//空节点,直接插入当前位置
	  (*node)->key = key;

	else if(key < (*node)->key)	//key小于该节点值,递归左孩子
	  insertNode(&((*node)->leftChild), key);

	else if(key > (*node)->key)	//key大于该节点值,递归右孩子
	  insertNode(&((*node)->rightChild),key);
	
	else	//key重复,返回错误值
	  return false;
	
	return true;
}

查找

//查找节点
_Bool selectNode(BSTree * node, int key)
{
	if(node == NULL)
	{
		puts("NOT SUCH A NODE\n");
		return true;
	}

	else if(key == node->key)
	  return true;

	else if(key < node->key)
	  selectNode(node->leftChild,key);

	else if(key > node->key)
	  selectNode(node->rightChild,key);
}

删除

此处有必要注释一下:
BST中有以下几种节点,涉及到删除的方法不尽相同。
1.该节点有两个孩子
2.该节点只有一个左孩子
3.该节点只有一个右孩子
4.该节点没有孩子(叶子节点 or 没有孩子的root点)

如果该节点有两个孩子,那么我们习惯性的使用其右枝中的最小值对其进行替代。并递归的将该最小值删除。
引用参考资料中的原话:
删除节点有两个儿子:一般的删除策略是用其右子树的最小的数据代替该节点的数据,并递归地删除那个右子树的最小节点。
如图所示(图片来自参考资料中的《【数据结构】二叉查找树...》一篇):
/* 
*              6                             6                       6 
*             / \                           / \                     / \  
*            2   8                         3   8                   3   8 
*           / \   \        -->            / \   \        -->      / \   \ 
*          1   4   10                    1   4   10              1   4   10 
*             /                             / 
*            3                             3 
*/  

如果该节点只有右孩子,则替换原理同上。

如果该节点只有左孩子,则将值替换为其左孩子的值,并递归的将其左孩子删除。
该处代码如下:
if((*pnode)->leftChild && !(*pnode)->rightChild) //目标节点只有左儿子
		{
			tmpNode = (*pnode)->leftChild;
			(*pnode)->key = tmpNode->key;
			return deleteNode(&(*pnode)->leftChild, (*pnode)->key);//递归的删除该已变为枝点的叶子节点
		}

如果该节点为叶子节点,则直接对其进行释放并将指向他的指针设为空。

附上该函数的完整代码如下:
//删除结点
_Bool deleteNode(BSTree ** pnode,int key)
{
	BSTree *tmpNode = NULL;

	if(NULL == pnode || NULL == *pnode)	//指针无目标或树为空
	  return false;

	//查找目标节点
	else if(key < (*pnode)->key)
	  return deleteNode(&(*pnode)->leftChild, key);//&(*pnode)中的&使之重新构成二级指针
	else if(key > (*pnode)->key)
	  return deleteNode(&(*pnode)->rightChild, key);

	//已找到目标节点,即key = pnode->key
	else
	{
		if((*pnode)->leftChild && (*pnode)->rightChild) //目标节点有两个儿子
		{
			tmpNode = findMin((*pnode)->rightChild);
			(*pnode)->key = tmpNode->key;
			return deleteNode(&(*pnode)->rightChild, (*pnode)->key);//递归的删除该已变为枝点的叶子节点
		}

		else if((*pnode)->leftChild) //目标节点只有左儿子
		{
			tmpNode = (*pnode)->leftChild;
			(*pnode)->key = tmpNode->key;
			return deleteNode(&(*pnode)->leftChild, (*pnode)->key);//递归的删除该已变为枝点的叶子节点
		}

		else if((*pnode)->rightChild) //目标节点只有右儿子
		{
			tmpNode = (*pnode)->rightChild;
			(*pnode)->key = tmpNode->key;
			return deleteNode(&(*pnode)->rightChild, (*pnode)->key);//递归的删除该已变为枝点的叶子节点
		}
		
		else	//目标节点没有儿子,包括叶子节点以及没有儿子的root点
		{
			free(*pnode);
			(*pnode) = NULL;
		}
	}

	return true;
}

遍历

树的遍历有三种:先序、中序和后序。每次遍历子树时,也要相应的按序遍历该子树。
1. 先序遍历:[首先访问根节点]  先访问根节点,再遍历左子树,最后遍历右子树
2. 中序遍历:[中间访问根节点]  先遍历左子树,再访问根节点,最后遍历右子树
3. 后序遍历:[最后访问根节点]  先遍历左子树,再遍历右子树,最后访问根节点
如图所示(图片来自参考资料中的《【数据结构】二叉查找树...》一篇):
/* 
*              6             先序遍历: 6 2 1 4 3 8 10 
*             / \                       
*            2   8           中序遍历: 1 2 3 4 6 8 10 
*           / \   \        
*          1   4   10        后序遍历: 1 3 4 2 10 8 6 
*             /                            
*            3                            
*/  


先序遍历 

//先序遍历
void preorder(BSTree *node)
{
	if(node != NULL)
	{
		printf("%d ", node->key);
		preorder(node->leftChild);
		preorder(node->rightChild);
	}
}

中序遍历

在二叉查找树中,中序遍历的结果恰好可以将该树中所有的元素进行升序输出

//中序遍历
void inorder(BSTree *node)
{
	if(node != NULL)
	{
		inorder(node->leftChild);
		printf("%d ", node->key);
		inorder(node->rightChild);
	}
}

后续遍历

//后序遍历
void postorder(BSTree *node)
{
	if(node != NULL)
	{
		postorder(node->leftChild);
		postorder(node->rightChild);
		printf("%d ", node->key);
	}
}


参考资料:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值