二叉搜索树

给出二叉搜索树的定义:

typedef char SearchTreeType;

typedef struct SearchTreeNode
{
	SearchTreeType key; // 关键码
	struct SearchTreeNode* lchild;
	struct SearchTreeNode* rchild;
}SearchTreeNode;

将函数的声明放在head.h的头文件里面:

#pragma once

#include <stdio.h>
#include <windows.h>

typedef char SearchTreeType;

typedef struct SearchTreeNode
{
	SearchTreeType key; // 关键码
	struct SearchTreeNode* lchild;
	struct SearchTreeNode* rchild;
}SearchTreeNode;


// 初始化
void SearchTreeInit(SearchTreeNode** root);

// 创建新节点
SearchTreeNode* CreateSearchTreeNode(SearchTreeType key);

//非递归
// 插入
void SearchTreeInsert_P(SearchTreeNode** root, SearchTreeType key); 

// 查找
SearchTreeNode* SearchTreeFind_P(SearchTreeNode* root, SearchTreeType to_find);

// 删除
void SearchTreeRemove_P(SearchTreeNode** root, SearchTreeType key);

void PreOrder(SearchTreeNode* root);
void InOrder(SearchTreeNode* root);

void DestroySearchTreeNode(SearchTreeNode* node);


//递归
// 插入
void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key);

// 查找
SearchTreeNode* SearchTreeFind(SearchTreeNode* root, SearchTreeType to_find);

// 删除
void SearchTreeRemove(SearchTreeNode** root, SearchTreeType key);

函数的定义(具体实现):

#include "SearchTree.h"

void SearchTreeInit(SearchTreeNode** root)
{
	if (root == NULL)
	{
		return;
	}
	*root = NULL;
}

void DestroySearchTreeNode(SearchTreeNode* node)
{
	free(node);
}

SearchTreeNode* CreateSearchTreeNode(SearchTreeType key)
{
	SearchTreeNode* new_node = (SearchTreeNode*)malloc(sizeof(SearchTreeNode));
	new_node->key = key;
	new_node->lchild = NULL;
	new_node->rchild = NULL;
	return new_node;
}

void SearchTreeInsert_P(SearchTreeNode** root, SearchTreeType key)
{
	if (root == NULL)
	{
		return;
	}

	// 1. 如果这个树是空树
	if (*root == NULL)
	{
		*root = CreateSearchTreeNode(key);
		return;
	}

	// 2. 如果这个树是非空树:
	//   a) 先查找到一个合适的插入位置
	SearchTreeNode* cur = *root;
	SearchTreeNode* parent = NULL;
	while (1)
	{
		if (cur == NULL)
		{
			// 合适的位置已经找到了
			break;
		}

		if (key < cur->key)
		{
			parent = cur;
			cur = cur->lchild;
		}
		else if (key > cur->key)
		{
			parent = cur;
			cur = cur->rchild;
		}
		else
		{
			// 发现当前元素和要插入的值相同,此处我们约定,让其插入失败
			return;
		}
	}
	//   b) 再在对应的位置上创建结点
	SearchTreeNode* new_node = CreateSearchTreeNode(key);
	if (key < parent->key)
	{
		parent->lchild = new_node;
	}
	else
	{
		parent->rchild = new_node;
	}
}

SearchTreeNode* SearchTreeFind_P(SearchTreeNode* root, SearchTreeType to_find)
{

	if (root == NULL)
	{
		return;
	}
	SearchTreeNode* cur = root;
	while (cur)
	{
		if (to_find < cur->key)
		{
			cur = cur->lchild;
		}
		else if (to_find < cur->key)
		{
			cur = cur->rchild;
		}
		else
		{
			break;
		}
	}
	return cur;
}

void SearchTreeRemove_P(SearchTreeNode** root, SearchTreeType key)
{
	if (root == NULL)
	{
		return;
	}

	// 1. 处理空树的情况,直接返回
	if (*root == NULL)
	{
		return NULL;
	}

	// 2. 找到要删除的结点的位置,以及要删除结点的父节点
	SearchTreeNode* to_remove = *root;
	SearchTreeNode* parent = NULL;
	while (to_remove)
	{
		if (key < to_remove->key)
		{
			parent = to_remove;
			to_remove = to_remove->lchild;
		}
		else if (key > to_remove->key)
		{
			parent = to_remove;
			to_remove = to_remove->rchild;
		}
		else
		{
			// 找到了
			break;
		}
	}

	// 3. 如果要查找元素在树中没有找到,也直接返回
	if (to_remove == NULL)
	{
		return;
	}

	// 4. 如果要删除的结点存在,要分情况讨论:
	//   a) 要删除的结点,没有子树,直接删除该结点,并且将父节点置空
	if (to_remove->lchild == NULL && to_remove->rchild == NULL)
	{
		if (to_remove == *root)
		{
			// 如果要删除的元素是根节点,那么就直接处理
			*root = NULL;
		}
		else
		{
			// 如果要删除的元素不是根节点,按以下逻辑判定
			if (parent->lchild == to_remove)
			{
				parent->lchild = NULL;
			}
			else
			{
				parent->lchild = NULL;
			}
		}
		DestroySearchTreeNode(to_remove);
		return;
	}

	//   b) 要删除的结点,只有左子树,删除该结点同时,将该结点的左子树挂到父节点上
	else if (to_remove->lchild != NULL && to_remove->rchild == NULL)
	{
		if (to_remove == *root)
		{
			// 如果要删除的元素是根节点
			*root = to_remove->lchild;
		}
		else
		{
			// 如果要删除的元素不是根节点,按以下逻辑判定
			if (to_remove == parent->lchild)
			{
				parent->lchild = to_remove->lchild;
			}
			else
			{
				parent->rchild = to_remove->lchild;
			}
		}
		DestroySearchTreeNode(to_remove);
		return;
	}

	//   c) 要删除的结点,只有右子树,删除该结点同时,将该结点的右子树挂到父节点上
	else if (to_remove->lchild == NULL && to_remove->rchild != NULL)
	{
		if (to_remove == *root)
		{
			// 如果要删除的元素是根节点
			*root = to_remove->rchild;
		}
		else
		{
			// 如果要删除的元素不是根节点,按以下逻辑判定
			if (to_remove == parent->lchild)
			{
				parent->lchild = to_remove->rchild;
			}
			else
			{
				parent->rchild = to_remove->rchild;
			}
		}
		DestroySearchTreeNode(to_remove);
		return;
	}

	//   d) 要删除的结点,同时有左右子树,找到右子树中的最小值,然后将该最小值赋值给要删除的位置,
	//      然后再删除该右子树中的最小值结点,这样一个结点最多只有一个右子树,就转换成了情况 c)
	else
	{
		SearchTreeNode* min = to_remove->rchild;
		SearchTreeNode* min_parent = to_remove;
		while (min->lchild != NULL)
		{
			min_parent = min;
			min = min->lchild;
		}

		// 代码执行到这里的时候,min就已经指向 to_remove 右子树的最小值
		to_remove->key = min->key;
		if (min_parent->lchild == min)
		{
			min_parent->lchild = min->rchild;
		}
		else
		{
			min_parent->rchild = min->rchild;
		}
		DestroySearchTreeNode(min);
		return;
	}
}

void PreOrder(SearchTreeNode* root)
{
	if (root)
	{
		printf("%c  ", root->key);
		PreOrder(root->lchild);
		PreOrder(root->rchild);
	}
}
void InOrder(SearchTreeNode* root)
{
	if (root)
	{
		InOrder(root->lchild);
		printf("%c  ", root->key);
		InOrder(root->rchild);
	}
}

void SearchTreeInsert(SearchTreeNode** root, SearchTreeType key)
{
	if (root == NULL)
	{
		// 非法输入
		return;
	}
	
	if (*root == NULL) // 关键代码 // 2. 创建新的结点,挂在对应的位置上
	{
		*root = CreateSearchTreeNode(key);
		return;
	}

	// 1. 先找到要往哪个位置插入
	if (key < (*root)->key)
	{
		SearchTreeInsert(&(*root)->lchild, key);
	}
	else if (key > (*root)->key)
	{
		SearchTreeInsert(&(*root)->rchild, key);
	}
	else
	{
		// 发现当前元素和要插入的值相同,此处我们约定,让其插入失败
		return;
	}
}

SearchTreeNode* SearchTreeFind(SearchTreeNode* root, SearchTreeType to_find)
{
	if (root == NULL)
	{
		// 空树
		return;
	}
	if (to_find < root->key)
	{
		return SearchTreeFind(root->lchild, to_find);
	}
	else if (to_find > root->key)
	{
		return SearchTreeFind(root->rchild, to_find);
	}
	else
	{
		// 找到
		return root;
	}
}

void SearchTreeRemove(SearchTreeNode** root, SearchTreeType key)
{
	if (root == NULL)
	{
		// 非法输入
		return;
	}
	
	// 1. 找到要删除的元素在树中的位置
	// 2. 如果没找到的话,不需要进行任何删除操作
	if (*root == NULL)
	{
		// 空树
		return;
	}

	if (key < (*root)->key)
	{
		SearchTreeRemove(&(*root)->lchild, key);
	}
	else if (key > (*root)->key)
	{
		SearchTreeRemove(&(*root)->rchild, key);
	}

	// 3. 如果找到了的话,分情况来讨论
	else
	{
		SearchTreeNode* to_remove = *root;

		//  a) 要删除元素没有子树,直接删除该结点就行了
		if (to_remove->lchild == NULL && to_remove->rchild == NULL)
		{
			*root = NULL;
			DestroySearchTreeNode(to_remove);
		}

		//  b) 要删除元素只有左子树,先把左子树挂在父节点上,再删除当前结点
		else if (to_remove->lchild != NULL && to_remove->rchild == NULL)
		{
			*root = to_remove->lchild;
			DestroySearchTreeNode(to_remove);
		}

		//  c) 要删除元素只有右子树,先把右子树挂在父节点上,再删除当前结点
		else if (to_remove->lchild == NULL && to_remove->rchild != NULL)
		{
			*root = to_remove->rchild;
			DestroySearchTreeNode(to_remove);
		}

		//  d) 要删除元素同时有左右子树,先找到当前元素右子树中最小的那个元素,
		//     把这个最小元素赋值到要删除的元素上,然后再删除刚才的最小元素,然后把问题转换成 b) 或者 c)
		else
		{
			SearchTreeNode* min = to_remove->rchild;
			while (min->lchild != NULL)
			{
				min = min->lchild;
			}
			// 代码执行到这里,意味着 min 已经指向了 to_remove 的右子树中的最小元素

			to_remove->key = min->key;
			SearchTreeRemove(&to_remove->rchild, min->key);
		} // to_remove 左右子树都存在
	} // key == to_remove->key
}

测试代码:

#include "SearchTree.h"

void TestSearchTree()
{
	SearchTreeNode* root;
	SearchTreeInit(&root);
	printf("root expect NULL, actual %p\n", root);

	SearchTreeInsert_P(&root, 'B');
	SearchTreeInsert_P(&root, 'A');
	SearchTreeInsert_P(&root, 'G');
	SearchTreeInsert_P(&root, 'D');
	SearchTreeInsert_P(&root, 'E');
	SearchTreeInsert_P(&root, 'F');

	printf("先序遍历:");
	PreOrder(root);
	printf("\n");

	printf("中序遍历:");
	InOrder(root);
	printf("\n");

	SearchTreeNode* result = SearchTreeFind(root, 'E');
	printf("result expect %p, actual %p \n", root->rchild->lchild->rchild, result);
}

int main()
{
	TestSearchTree();
	system("pause");
	return 0;
}

结果如下:


猜你喜欢

转载自blog.csdn.net/czh269945404/article/details/80052675