二叉搜索树的表示与实现

六、二叉搜索树的表示与实现

二叉搜索树介绍:

​ 二叉搜索树又叫作有序二叉树、二叉查找树,具有以下特点:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。

​ 二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势(O(log2n);所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。

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

typedef struct TreeNode
{
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	size_t height;	// 结点的高度
	size_t density; // 结点的密度
} TreeNode;

// 创建结点
TreeNode *create_node(int val)
{
	TreeNode *root = malloc(sizeof(TreeNode));
	root->val = val;
	root->left = NULL;
	root->right = NULL;
	root->height = 1;
	root->density = 1;
	return root;
}

// 自动调整树的高度和密度
void auto_tree(TreeNode *root)
{
	if (NULL == root)
		return;

	int lh = 0, rh = 0, ld = 0, rd = 0;
	if (NULL != root->left)
	{
		// 当左子树不为空时,调整左子树的高度和密度
		auto_tree(root->left);
		// 重新获取左子树的高度和密度
		lh = root->left->height;
		ld = root->left->density;
	}

	if (NULL != root->right)
	{

		// 当右子树不为空时,调整右子树的高度和密度
		auto_tree(root->right);
		// 重新获取右子树的高度和密度
		rh = root->right->height;
		rd = root->right->density;
	}

	// 更新当前结点的高度和密度
	root->height = lh > rh ? lh + 1 : rh + 1;
	root->density = ld + rd + 1;
}

void _add_tree(TreeNode **root, TreeNode *node)
{
	if (NULL == *root)
	{
		*root = node;
		return;
	}

	if ((*root)->val > node->val)
		_add_tree(&(*root)->left, node);
	else
		_add_tree(&(*root)->right, node);
}

void add_tree(TreeNode **root, int val)
{
	// root是main函数中root指针的地址
	_add_tree(root, create_node(val));
	auto_tree(*root);
}

// 之所这样设计是为了方便删除并兼顾查询,查询到的是指向值为val结点的指针的地址
TreeNode **_query_tree(TreeNode **root, int val)
{
	if (NULL == *root)
		return root;

	if (val == (*root)->val)
		return root;
	if (val <= (*root)->val)
		return _query_tree(&(*root)->left, val);
	else
		return _query_tree(&(*root)->right, val);
}

bool query_tree(TreeNode *root, int val)
{
	TreeNode **node = _query_tree(&root, val);
	return NULL != *node;
}

void _del_tree(TreeNode **root)
{
	TreeNode *temp = *root;
	if (NULL == temp->left)
		*root = temp->right;
	else if (NULL == temp->right)
		*root = temp->left;
	else
	{
		*root = temp->left;
		_add_tree(root, temp->right);
	}
	free(temp);
}

bool del_tree(TreeNode **root, int val)
{
	TreeNode **node = _query_tree(root, val);
	if (NULL == *node)
		return false;

	_del_tree(node);
	auto_tree(*root);
	return true;
}

bool modify_tree(TreeNode **root, int old, int val)
{
	TreeNode **node = _query_tree(root, old);
	if (NULL == *node)
		return false;

	_del_tree(node);
	_add_tree(root, create_node(val));
	auto_tree(*root);
	return true;
}

void _in_order_tree(TreeNode *root)
{
	if (NULL == root)
		return;

	_in_order_tree(root->left);
	printf("%d ", root->val);
	_in_order_tree(root->right);
}

void in_order_tree(TreeNode *root)
{
	_in_order_tree(root);
	printf("\n");
}

void level_order_tree(TreeNode *root)
{
	if (NULL == root)
		return;

	TreeNode *queue[root->density];
	int front = 0, rear = 0;
	queue[rear++] = root;

	while (front != rear)
	{
		int cnt = rear - front;
		while (cnt--)
		{
			TreeNode *node = queue[front++];
			printf("[v:%d h:%d d:%d] ", node->val, node->height, node->density);
			if (NULL != node->left)
				queue[rear++] = node->left;
			if (NULL != node->right)
				queue[rear++] = node->right;
		}
		printf("\n");
	}
}

// 访问第k个小的数,按大小值的顺序访问
void _assign_tree(TreeNode *root, int k, int *pos, int *ptr)
{
	if (NULL == root)
		return;

	_assign_tree(root->left, k, pos, ptr);
	if (++*pos == k)
		*ptr = root->val;
	_assign_tree(root->right, k, pos, ptr);
}

int assign_tree(TreeNode *root, int k)
{
	if (k < 1)
		return -1;

	int pos = 0, val = -1;
	_assign_tree(root, k, &pos, &val);
	return val;
}

int main(int argc, const char *argv[])
{
	TreeNode *root = NULL;
	for (int i = 0; i < 10; i++)
	{
		add_tree(&root, rand() % 100);
	}
	in_order_tree(root);
	modify_tree(&root, 77, 99);
	in_order_tree(root);
	level_order_tree(root);

	return 0;
}

二叉搜索树的缺点:

​ 二叉搜索树的元素添加顺序会影响二叉搜索树的形状,二叉搜索树的形状会影响它的操作效率,在极端情况下,二叉搜索树可能会呈单枝状分布,使用速度接近单向链表,这种极端情况出现在的原因就添加的元素基本有序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值