二叉搜索树(BST)
什么是二叉搜索树
二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树数据结构,其中每个节点的值都大于其左子树中的任何节点的值,且小于其右子树中的任何节点的值。它的特点使得在搜索、插入和删除操作上具有高效性。
以下是一些关于二叉搜索树的重要特性:
-
左子树中的所有节点的值都小于根节点的值。
-
右子树中的所有节点的值都大于根节点的值。
-
左右子树本身也是二叉搜索树。
由于这些特性,二叉搜索树可以用于高效地实现插入、搜索和删除操作。搜索操作可以在平均情况下以O(log n)的时间复杂度完成,其中n是树中节点的数量。然而,最坏情况下,树可能退化为链表,搜索操作的时间复杂度将变为O(n)。插入操作的时间复杂度与搜索操作类似,平均情况下为O(log n),最坏情况下为O(n)。删除操作的时间复杂度也是O(log n)。二叉搜索树的应用非常广泛,例如在数据库中用于索引、实现有序集合等。然而,需要注意的是,如果树的平衡性较差,可能会导致性能下降。因此,有时需要采取一些平衡策略,如红黑树或AVL树,来确保树的平衡性。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
//数据没有关键字,可以构建一个关键字
typedef struct
{
int key;
char value[20];
}Data;
typedef struct TreeNode
{
Data data;
struct TreeNode* LChild;
struct TreeNode* RChild;
}Node;
Node* create_node(Data data)
{
Node* newNode = (Node*)calloc(1, sizeof(Node));
assert(newNode);
newNode->data = data;
return newNode;
}
typedef struct BinarySearchTree
{
Node* root;
int count;
}BST;
BST* create_bst()
{
BST* tree = (BST*)calloc(1, sizeof(BST));
assert(tree);
return tree;
}
int size_bst(BST* tree)
{
return tree->count;
}
bool empty_bst(BST* tree)
{
return tree->count == 0;
}
void traverse_midOrder(Node* tree) //中序递归的方法 是有序的
{
if (tree != NULL)
{
traverse_midOrder(tree->LChild);
printf("%d:%s\n", tree->data.key, tree->data.value);
traverse_midOrder(tree->RChild);
}
}
void traverse_layerOrder(BST* tree) //按层去便利
{
if (tree->count == 0)
return;
Node* pmove = tree->root;
Node* queue[1024];
int front = 0;
int tail = 0;
queue[tail++] = pmove;
printf("%d:%s\n", pmove->data.key, pmove->data.value);
while (front != tail)
{
pmove = queue[front++];//出队
if (pmove->LChild != NULL)
{
queue[tail++] = pmove->LChild;
printf("%d:%s\n", pmove->LChild->data.key, pmove->LChild->data.value);
}
else
{
printf("NULL\n");
}
if (pmove->RChild != NULL)
{
queue[tail++] = pmove->RChild;
printf("%d:%s\n", pmove->RChild->data.key, pmove->RChild->data.value);
}
else
{
printf("NULL\n");
}
}
}
void insert_bst(BST* tree, Data data)
{
Node* newNode = create_node(data);
Node* pmove = tree->root;
Node* pre = NULL;
while (pmove != NULL)
{
pre = pmove;
if (pmove->data.key > data.key)
{
pmove = pmove->LChild;
}
else if (pmove->data.key < data.key)
{
pmove = pmove->RChild;
}
else
{
strcpy_s(pmove->data.value, 20, data.value);
return;
}
}
if (tree->root == NULL)
{
tree->root = newNode;
}
else
{
if (pre->data.key > data.key)
{
pre->LChild = newNode;
}
else
{
pre->RChild = newNode;
}
}
tree->count++;
}
Node* search_bst(BST* tree, int key)
{
Node* pmove = tree->root;
while (pmove != NULL && pmove->data.key != key)
{
if (pmove->data.key > key)
{
pmove = pmove->LChild;
}
else
{
pmove = pmove->RChild;
}
}
return pmove;
}
//删除节点
void erase_bst(BST* tree, int key)
{
Node* pmove = tree->root;
if (pmove == NULL)
{
return;
}
//查找要删除的节点
Node* pmoveparent = NULL;
while (pmove != NULL && pmove->data.key != key)
{
pmoveparent = pmove;
if (pmove->data.key > key)
{
pmove = pmove->LChild;
}
else if (pmove->data.key < key)
{
pmove = pmove->RChild;
}
else
{
break;
}
}
if (pmove == NULL)
{
printf("未找到指定位置无法删除!\n");
return;
}
//分析删除的情况
if (pmove->LChild != NULL && pmove->RChild != NULL)
{
//删除节点的左子树找最右边的节点替换或者删除的节点右子树找最左边的节点替换
Node* moveNode = pmove->LChild;
Node* moveNodeParent = pmove;
while (moveNode->RChild != NULL)
{
moveNodeParent = moveNode;
moveNode = moveNodeParent->RChild;
}
Node* newNode = create_node(moveNode->data);
newNode->LChild = pmove->LChild;
newNode->RChild = pmove->RChild;
if (pmoveparent == NULL)
{
tree->root = newNode;
}
else if (pmove == pmoveparent->LChild)
{
pmoveparent->LChild = newNode;
}
else
{
pmoveparent->RChild = newNode;
}
if (moveNodeParent == pmove)
{
pmoveparent = newNode;
}
else
{
pmoveparent = moveNodeParent;
}
free(pmove);
pmove = moveNode;
}
Node* sNode = NULL;
if (pmove->LChild != NULL)
{
sNode = pmove->LChild;
}
else
{
sNode = pmove->RChild;
}
if (tree->root == pmove)
{
tree->root = sNode;
}
else
{
if (pmove == pmoveparent->LChild)
{
pmoveparent->LChild = sNode;
}
else
{
pmoveparent->RChild = sNode;
}
}
free(pmove);
tree->count--;
}
int main()
{
BST* tree = create_bst();
Data data[6] = { 10,"小芳",5,"小美",49,"baby",2,"小小",18,"悠悠",89,"小花" };
for (int i = 0; i < 6; i++)
{
insert_bst(tree, data[i]);
}
printf("size:%d\n", size_bst(tree));
printf("中序结果:\n");
traverse_midOrder(tree->root);
printf("\n层次遍历:\n");
traverse_layerOrder(tree);
Node* pos = search_bst(tree, 18);
if (pos != NULL)
{
printf("查找:%s\n", pos->data.value);
}
printf("\n删除49\n");
erase_bst(tree, 49);
traverse_layerOrder(tree);
return 0;
}
删除结点的思路
例如:要删除80则找80元素对应的左子树的最右边(55)将55代替掉80 。
或者在右子树里面去找最左边的元素。