二叉排序树
数据结构c二叉排序树基本操作
2020_12_16
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//二叉排序树
typedef struct BSTNode {
int data;
struct BSTNode *lchild; //左孩子
struct BSTNode *rchild; //右孩子
} BSTNode, *BSTree;
bool Search(BSTree bst, int key, BSTree f, BSTree *p);
void InOderTraverse(BSTree bst) //中序递归遍历二叉树
{
if (bst) {
InOderTraverse(bst->lchild);
printf("%d ", bst->data);
InOderTraverse(bst->rchild);
}
}
static BSTNode *BuyNode(int data) //生成一个节点并进行初始化
{
BSTNode *pTmp = (BSTNode *) malloc(sizeof(BSTNode));
if (NULL == pTmp) {
exit(0);
}
pTmp->data = data;
pTmp->lchild = NULL;
pTmp->rchild = NULL;
return pTmp;
}
bool Insert(BSTree *bst, int key) {
if (*bst == NULL) {//空树
*bst = BuyNode(key); //插入根节点
return true;
}
BSTNode *p;
//先在二叉排序树中查找要插入的值是否已经存在
if (!Search(*bst, key, NULL, &p)) //如果查找失败,则插入;此时p指向遍历的最后一个节点
{
BSTNode *pNew = BuyNode(key);
if (key < p->data) {//将s作为p的左孩子
p->lchild = pNew;
} else if (key > p->data) { //将s作为p的右孩子
p->rchild = pNew;
}
return true; //插入成功
} else {
printf("\nThe node(%d) already exists.\n", key);
}
return false;
}
/*
删除分三种情况:
(1)被删除的节点无孩子,说明该节点是叶子节点,直接删
(2)被删除的节点只有左孩子或者右孩子,直接删,并将其左孩子或者右孩子放在被删节点的位置
(3)被删除的节点既有右孩子又有右孩子
*/
BSTNode *FindParent(BSTree bst, BSTNode *child) {
if (NULL == bst) {
return NULL;
}
if (bst->lchild == child || bst->rchild == child) {
return bst;
} else if (NULL != bst->lchild) {
return FindParent(bst->lchild, child);
} else if (NULL != bst->rchild) {
return FindParent(bst->rchild, child);
}
return NULL;
}
void Delete(BSTree *bst, int key) {
if (NULL == *bst) {
exit(1); //空树直接报错
}
// BSTNode *f = NULL;
BSTNode *p, *q, *s;
if (Search(*bst, key, NULL, &p)) //确实存在值为key的节点,则p指向该节点
{
if (NULL == p->lchild && p->rchild) //无左孩子,有右孩子
{
q = p->rchild;
p->data = q->data; //因为两个节点之间本质的不同在于数据域的不同,而与放在哪个地址没有关系
p->rchild = q->rchild;
p->lchild = q->lchild;
free(q);
} else if (NULL == p->rchild && p->lchild) //无右孩子,有左孩子
{
q = p->lchild;
p->data = q->data;
p->rchild = q->rchild;
p->lchild = q->lchild;
free(q);
} else if (p->rchild && p->lchild) //既有左孩子,又有右孩子
{
q = p;
s = p->lchild; //找左孩子的最右孩子
while (s->rchild) {
q = s;
s = s->rchild;
}
p->data = s->data;
if (q != p) {
q->rchild = s->lchild;
} else {
q->lchild = s->lchild;
}
free(s);
} else {//没有孩子
if (*bst == p) //只有一个根节点
{
free(*bst);
*bst = NULL;
return;
}
BSTNode *parent = FindParent(*bst, p);
if (parent->lchild == p) {
parent->lchild = NULL;
} else {
parent->rchild = NULL;
}
free(p);
}
}
}
//查找成功时,p指向值为key的节点。如果查找失败,则p指向遍历的最后一个节点,f为根节点。
bool Search(BSTree bst, int key, BSTree f, BSTree *p) {
if (!bst) {
*p = f;
return false;
}
if (bst->data == key) {//查找成功,直接返回
*p = bst;
return true;
} else if (bst->data < key) {
return Search(bst->rchild, key, bst, p);
}
return Search(bst->lchild, key, bst, p);
}
int main() {
freopen("input.txt", "r", stdin);
printf("请输入数字个数:\n");
int n, i;
scanf("%d", &n);
BSTNode *root = NULL, *p;
printf("请输入要插入的数字:\n");
for (i = 0; i < n; i++) {
int x;
scanf("%d", &x);
Insert(&root, x);
}
InOderTraverse(root);
printf("请输入要查询的数字:\n");
int x;
scanf("%d", &x);
if (Search(root, x, NULL, &p)) printf("存在此数。\n");
else printf("不存在此数。\n");
// printf("%d ", Insert(&root, 45)); //输出0表示插入失败,输出1表示插入成功
// printf("%d\n", Insert(&root, 4));
printf("请输入删除数字个数:\n");
scanf("%d", &n);
printf("请输入要删除的数字:\n");
for (i = 0; i < n; i++) {
int x;
scanf("%d", &x);
Delete(&root, x);
}
printf("删除后顺序为:\n");
InOderTraverse(root);
return 0;
}