二叉搜索树(BST) ------- 插入 查找 删除 的递归与非递归

首先应该对二叉搜索树的性质有所了解。 

二叉搜索树又称为二叉排序树。当左子树不为空时,则左子树的结点值小于根结点值;右子树不为空时反之。空树也是二叉排序树。

头文件及结构体定义代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef int DataType;

typedef struct BSTreeNode{
	DataType data;
	struct BSTreeNode *left;
	struct BSTreeNode *right;
} BSTreeNode;
  • 插入

              插入首先应判断树是否为空,若为空则直接插入结点。

              否则,根据树的性质,找到结点位置,创建新结点,插入到树中。

插入非递归代码:

// 插入 ---- 非递归
int BSTreeInsert2(BSTreeNode **root, DataType data)
{
	BSTreeNode *cur = *root;
	
	BSTreeNode *parent = NULL;
	// 当前结点不为空 
	// 插入值大于当前值 向右子树遍历 遇空时结束循环 
	// 插入值小于当前值 向左子树遍历 遇空时结束循环
	while (cur){
		if (data == cur->data)
			return 0;
		
		parent = cur;            // 记录上一个遍历的结点
		if (data > cur->data){
			cur = cur->right;
		}
		else
			cur = cur->right;
	}
	// 创建新结点
	BSTreeNode *node = (BSTreeNode *)malloc(sizeof(BSTreeNode));
	node->data = data;
	node->left = node->right = NULL;
	
	if (parent == NULL){
		(*root) = node;
	}
	if (data > parent->data){
		parent->right = node;
	}
	else
		parent->left = node;
	return 1;
}

插入递归代码:


// 插入 ---- 递归
// 1表示成功 0表示失败
int BSTreeInsert(BSTreeNode **root, DataType data)
{
	// 如果树为空
	if ((*root) == NULL){
		BSTreeNode *node = (BSTreeNode *)malloc(sizeof(BSTreeNode));
		node->data = data;
		node->left = node->right = NULL;
		*root = node;
		return 1;
	}

	// 若所要插入值已经存在则表示错误
	// 若所要插入值 大于 当前结点值 则向结点左子树搜索 直到遇到空值  否则反之
	BSTreeNode *cur = *root;
	if (data == cur->data)
		return 0;
	if (data > cur->data){
		return BSTreeInsert(&(cur->right), data);
	}
	else
		return BSTreeInsert(&(cur->left), data);
}
  • 查找

       树不为空时, 判断所要查找的data与根节点data比值。

      若  root-> data  >  data    ,则在左子树查找;

      若 root->  data <   data    , 则在右子树查找;

扫描二维码关注公众号,回复: 3477442 查看本文章

查找非递归代码:

// 查找 ---- 非递归
int BSTreeFind2(const BSTreeNode *root, DataType data)
{
	const BSTreeNode *cur = root;
	while (cur){
		if (data == cur->data)
			return 1;
		else if (data > cur->data){
			cur = cur->right;
		}
		else
			cur = cur->left;
	}
	return 0;
}

查找递归代码:

// 插入 ---- 递归
// 1表示成功 0表示失败
int BSTreeInsert(BSTreeNode **root, DataType data)
{
	// 如果树为空
	if ((*root) == NULL){
		BSTreeNode *node = (BSTreeNode *)malloc(sizeof(BSTreeNode));
		node->data = data;
		node->left = node->right = NULL;
		*root = node;
		return 1;
	}

	// 若所要插入值已经存在则表示错误
	// 若所要插入值 大于 当前结点值 则向结点左子树搜索 直到遇到空值  否则反之
	BSTreeNode *cur = *root;
	if (data == cur->data)
		return 0;
	if (data > cur->data){
		return BSTreeInsert(&(cur->right), data);
	}
	else
		return BSTreeInsert(&(cur->left), data);
}
  • 删除

      删除大致分为:空树,没有孩子结点(子树),有一个孩子结点(子树),有左右孩子结点(子树);

      没有孩子时: 将叶子结点删除后,让其父亲结点指向空。

      有一个孩子时: 删除该结点使其父亲结点指向它的孩子结点。

      有左右孩子时: 可用替换法:用左子树最大值或右子树最小值替换要删除结点。    PS:被替换可能存在一个孩子结点,处理方法与之前一样。

删除非递归代码:

// 删除
int BSTreeNodeRemove(BSTreeNode **root, DataType data)
{
	BSTreeNode *cur = *root;
	BSTreeNode *del = NULL;
	BSTreeNode *node = NULL;
	BSTreeNode *parent = NULL;

	if (!cur)
		return 0;
	
	// 查找要删除结点
	while (cur != NULL){
		if (data == cur->data){
			del = cur;
			break;
		}
		parent = cur;
	    if (data > cur->data){
			cur = cur->right;
		}
		else
			cur = cur->left;
	}
	
	if (del == NULL){
		printf(" 未找到该结点\n");
		return;
	}
	// 是叶子结点 直接删除
	// 只free删除结点 而其父亲结点依然指向他
	if (del->left == NULL && del->right == NULL){
		if (data < parent->data){
			parent->left = NULL;
		}
		else
			parent->right = NULL;
		free(del);
		return 1;
	}
	// 只有一个叶子结点(子树) 删除后其叶子结点(子树)继承该结点位置
	// 只有左结点(子树)
	else if (del->right == NULL){
        // 判断删除结点 是左子树 还是 右子树
		if (data < parent->data){
			parent->left = del->left;
		}
		else
			parent->right = del->left;
		free(del);
		return 1;

	}
	
	// 只有右结点(子树)
	else if (del->left == NULL){

		if (data < parent->data){
			parent->left = del->right;
		}
		else
			parent->right = del->right;
		free(del);
		return 1;

	}
	
	// 有左右两个叶子结点(子树)  删除后可用 其左子树最大值 或 右子树最小值替换
	// 例如: 用左子树最大值替换
	else{
		parent = NULL;
		node = del->left;
		// node为替换点
		while (node->right != NULL){
			parent = node;
			node = node->right;
		}
		del->data = node->data;
		if (parent == NULL){
			del->left = node->left;
		}
		else{
			parent->right = node->left;
		}
		free(node);
		return 1;

	}
	return 0;
}

对删除的几种可能可以各自封装,使得代码看起来较为清爽。

封装后的非递归代码:

// 没有左孩子
void RemoveNotLeft(BSTreeNode **root, DataType data, BSTreeNode *cur, BSTreeNode *parent)
{
	// 为根结点
	if (parent == NULL){
		*root = cur->right;
	}
	else{
		if (data > (parent)->data){
			parent->right = cur->right;
		}
		else {
			parent->left = cur->right;
		}
	}
	free(cur);
}

// 没有右孩子
void RemoveNotRight(BSTreeNode **root, DataType data, BSTreeNode *cur, BSTreeNode *parent)
{
	// 为根结点
	if (parent == NULL){
		*root = cur->left;
	}
	else{
		if (data > (parent)->data){
			parent->right = cur->left;
		}
		else {
			parent->left = cur->left;
		}
	}
	free(cur);
}

// 有左右孩子
void RemoveHaveLR(BSTreeNode *cur)
{
	// 找左子树最大结点
	BSTreeNode *del = cur->left;
	BSTreeNode *parent = NULL;

	while (del->right != NULL){
		parent = del;
		del = del->right;
	}
	// del 为子树中最大的
	cur->data = del->data;
	if (parent != NULL){
		parent->right = del->left;
	}
	else{
		cur->left = del->left;
	}
	free(del);
}

int BSTreeNodeRemove2(BSTreeNode **root, DataType data)
{
	BSTreeNode *cur = *root;
	BSTreeNode *parent = NULL;
	if (cur == NULL){
		return 0;
	}

	while (cur != NULL){
		// 找到要删除的结点
		if (data == cur->data){
			// 没有左子树
			if (cur->left == NULL){
				RemoveNotLeft(root, data,cur, parent);
			}
			else if (cur->right == NULL){
				RemoveNotRight(root, data, cur, parent);
			}
			else{
				RemoveHaveLR(cur);
			}
			return 0;
		}
		parent = cur;
		if (data > cur->data){
			cur = cur->right;
		}
		else{
			cur = cur->left;
		}
	}
	return 0;
}

删除递归代码

// 递归的删除
int BSTreeNodeRemove3(BSTreeNode **root, DataType data)
{
	// 空树直接返回
	if (*root == NULL) {
		return 0;
	}

	// 要删除的是不是根
	if (data == (*root)->data) {
		BSTreeNode *del = *root;
		
		// 判断要删除的结点是根的左还是右
		if ((*root)->left == NULL) {
			*root = (*root)->right;
			free(del);
		}
		else if ((*root)->right == NULL) {
			*root = (*root)->left;
			free(del);
		}
		else {
			// 左右都不为空
			RemoveHaveLR(*root);
		}

		return 1;
	}
	// 未找到向后递归运算
	if (data < (*root)->data) {
		return BSTreeNodeRemove3(&(*root)->left, data);
	}
	else {
		return BSTreeNodeRemove3(&(*root)->right, data);
	}
}

猜你喜欢

转载自blog.csdn.net/timecur/article/details/82257459