二叉搜索树又叫作有序二叉树、二叉查找树,具有以下特点:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。
二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势(O(log2n);所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
#include
#include
#include
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;
}
二叉搜索树的元素添加顺序会影响二叉搜索树的形状,二叉搜索树的形状会影响它的操作效率,在极端情况下,二叉搜索树可能会呈单枝状分布,使用速度接近单向链表,这种极端情况出现在的原因就添加的元素基本有序。