最近在学数据结构,前段时间学了二叉搜索树和平衡二叉树,但当时眼高手低就看了网课啥也没敲。。现在优点愧疚,就补上了。
二叉搜索树:
使用二分查找的思路构树(平衡二叉树完全就是,不过二叉搜索树有些遗憾)。特点:任一节点的权值都大于其左子树上所有点的权值,小于其右子树上所有点的权值。
平衡二叉树:
简介:也是搜索树,不过它改进了:二叉搜索树由于插入顺序的不同,最坏查找次数也不同,运气不好就是O(n).
官方解释:
任一节点的平衡因子的绝对值都不大于1(平衡因子:左子树的高度-右子树的高度。)
这样子由于二叉树的性质查找的时间复杂度就为log(n)了。
今天先展示二叉搜索树的常规操作:创建(也可以当作插入)、查找、删除。
我的代码(有BUG,根节点删除的情况当时没考虑到,所以不要删根节点,不然会段错误)。遍历我是使用的中序非递归(第二次遇到的时候打印)
代码:(有bug多谢指出)
//二叉搜索树的创建(插入)/查找/删除
//二叉搜索树的创建(插入)/查找/删除
#include<stdio.h>
#include<stdlib.h>
typedef struct tree{
int val;
struct tree *left,*right;
}tree;
int count = 0;
tree* searchmax(tree *p) {//查找待删除节点左子树的最大值
tree *q = p;
while(p->right) {
q = p;
p = p->right;
}
q->right = NULL;
if (p->left && p != q) {//最大值左子树非空
q->right = p->left;
}
return p;
}
void create(tree *root,int n) {//暂定都为positive integer,且每个数都unique
//链表地址发生了改变一定要把改变后的地址赋给上一个节点,因为每个节点存的都是下个节点的地址值而不是地址的地址
int num;
tree *p = root;
scanf("%d",&num);
root->val = num;
for (int i = 0;i < n-1;i++) {
p = root;
scanf("%d",&num);
while(p) {
if (num > p->val) {
if (p->right == NULL) {
p->right = (tree *)malloc(sizeof(tree));
p->right->val = num;
p->right->left = NULL;
p->right->right = NULL;
break;
}
p = p->right;
}
else {
if (p->left == NULL) {
p->left = (tree *)malloc(sizeof(tree));
p->left->val = num;
p->left->left = NULL;
p->left->right = NULL;
break;
}
p = p->left;
}
}
}
}
tree* search(tree *root,int num) {
tree *p = root;
tree *q;
while (p) {
if (p->val > num) {
q = p;
p = p->left;
}
else if (p->val < num){
q = p;
p = p->right;
}
else {
count++;
break;
}
count++;
}
if (p) {//返回值为该节点的上一个节点(为了下面的删除方便,查找和删除使用同一个模块了,所以下面大部分的q节点都代表待删除的节点的上一个节点)
return q;
}
else {
return NULL;
}
}
void delete(tree *root) {
int num,flag = 0;
printf("请输入待删除的数字:\n");
scanf("%d",&num);
tree *q = search(root,num);
/*fprintf(stderr,"%d",q->val);*/
tree *p;
if (q->left && q->left->val == num) {
p = q->left;
flag = 1;
}
if (q->right && q->right->val == num) {
p = q->right;
flag = 2;
}
if (p->left == NULL && p->right == NULL) {//左右子树都为空
free(p);
if (flag == 1) {
q->left = NULL;
}
else if (flag == 2) {
q->right = NULL;
}
}
else if (p->left && p->right == NULL) {//左子树非空,右子树空
if (flag == 1) {
q->left = p->left;
free(p);
}
else if (flag == 2) {
q->right = p->left;
free(p);
}
}
else if (p->right && p->left == NULL) {//右子树非空,左子树空
if (flag == 1) {
q->left = p->right;
free(p);
}
else if (flag == 2) {
q->right = p->right;
free(p);
}
}
else {//左右子树都不空,此处采用:左子树的最大值来替换该点
tree *maxleft = searchmax(p->left);//最大值点
if (flag == 1) {
q->left = maxleft;
}
else if (flag == 2) {
q->right = maxleft;
}
if (maxleft != p->left) {
maxleft->left = p->left;
}
maxleft->right = p->right;
free(p);
}
}
void inorder(tree *root,int n) {//非递归中序遍历:第二次路过该点时打印
tree *p = root;
tree *a = (tree *)calloc(n,sizeof(tree));
int top = 0;
while(top >= 0) {
while(p) {
a[top++] = *p;
p=p->left;
}
if (top >= 0) {
if (top == 0) {
break;
}
tree out = a[top-1];
printf("->%d<-",out.val);
p = out.right;
top--;
}
}
}
int main() {
tree *root = (tree*)malloc(sizeof(tree));
root->left = NULL;
root->right = NULL;
int n;
printf("请输入二叉数总数:\n");
scanf("%d",&n);
printf("请按插入顺序输入:\n");
create(root,n);
printf("中序遍历为:\n");
inorder(root,n);
/*fprintf(stderr,"haha");*/
int num;
printf("请输入需要查找的数字:\n");
scanf("%d",&num);
search(root,num);
if (count) {
printf("查到了,查找次数为:%d\n",count);
}
else {
printf("没查到\n");
}
delete(root);
/*fprintf(stderr,"haha");*/
printf("删除后的树:\n");
inorder(root,n);
return 0;
}
来源:CSDN
作者:knswd
链接:https://blog.csdn.net/knswd/article/details/104577419