结构概念如下:
二叉排序树(binary sort tree):
1、也叫做二叉查找树
2、如果他的左子树不为空,则左子树上所有结点的
值均小于他的根结构的值
3、如果他的右子树不为空,则右子树上所有结点的
值均大于他的根结构的值
4、他的左右子树分别为二叉排序树
5、按照二叉树中序遍历其返回结果树有序的
下面就是一颗典型的二叉树,只是是字母,可以将字母换位字母的顺序进行审视,但是它不是平衡二叉树
排序二叉树(BST)的优点在于进行数据查找比较方便,因为他是按照数据来到的顺序进行如上的规则进行的
建树,只要如上的规则进行查找就能找到需要的数据。但是其缺点也是显而易见,树的深度是不可控制的
而且可能极不均匀,考虑 1 2 3 4 5 6 7,这样的数据建树全部节点都在左子树上,级不均匀。那么给
搜索数据的性能带来的较大的影响,所以引入了AVL树平衡二叉树,这个在后面再说
关于排序二叉树BST的各种操作都使用了递归算法,给出递归算法一张我认为很好的图:
这张图实际体现了递归的真谛 顺序调用反向返回,这个列子和图来自小甲鱼C视频也可能来自大话数据结构
上面的代码实际上是:
void print()
{
char a;
scanf("%c",&a);
if(a!='#') print();
if(a!='#') printf("%c",a);
}
关于递归的经典 费布那切数列和汉诺塔等都可以了解一下;
下面回归正题,直接给出代码和测试用例。说明代码大部分来自大话数据结构,销毁和中序遍历是我自己写的,但是我自己进行了理解。
主要删除数据比较难,分为3种情况
1、删除节点的左子树为空,更改*p = (*p)->rchild;注意这里的*p代表的是parent->child,所以这样做就是将父节原来指向删除节点的指针,指向删除节点的下一个右孩子
2、删除节点的右子树为空,同理更改*p = (*p)->lchild;注意这里的*p代表的是parent->child,所以这样做就是将父节原来指向删除节点的指针,指向删除节点的下一个左孩子
3、删除节点左右子树都不为空,需要进行找到直接前驱或者直接后继节点进行数据代替。这个就比较复杂直接看代码吧
分别进行讨论。
其他操作相对简单不用再秒素就是递归,但是需要注意排序返回数据是用中序遍历,销毁树用的是后序遍历。
代码如下:
点击(此处)折叠或打开
- 头文件
- bstort.h
- #include<stdio.h>
- typedef int bool;
- #define false 0
- #define true 1
- #define xfree(x) free(x); x = NULL;
- typedef struct BiTnode
- {
- int data;
- struct BiTnode *lchild,*rchild;
- } BiTnode,*BiTree;
- bool SearchBst(BiTree T,int key,BiTree *f,BiTree *p);
- bool InsertBst(BiTree *T,int key) ;
- void Inordervist(const BiTree T);
- void BTreedestroy(BiTree tree);
- bool DeleteBst(BiTree *T,int key);
- bool Delete(BiTree *p);
点击(此处)折叠或打开
- 实现程序
- bstort.c
- #include<stdio.h>
- #include<stdlib.h>
- #include"bstort.h"
- /*
- T = Bst root node
- key = search key
- f = T's parent node,used if search failed save last search node pointer
- if search failed last T is NULL,inital vlaues is NULL,
- is sucuess f is pointer to p's parent poniter,
- p = if sucess p is pointer to find node pointer,if failed is pointer to last
- search node pointer
- */
- bool SearchBst(BiTree T,int key,BiTree *f,BiTree *p)
- {
- if(!T)
- {
- *p = *f;
- return false;
- }
- else if(key == T->data)
- {
- *p = T;
- return true;
- }
- else if(key < T->data)
- {
- *f = T;
- return SearchBst(T->lchild,key,f,p);
- }
- else
- {
- *f = T;
- return SearchBst(T->rchild,key,f,p);
- }
- }
- /*
- T = Bst root node
- key = key to insert
- */
- bool InsertBst(BiTree *T,int key)
- {
- BiTree p = NULL ,s = NULL ,f=NULL;
- if(!SearchBst(*T,key,&f,&p)) //init NULL,KEY,NULL,&P=NULL
- {
- s = (BiTree)calloc(1,sizeof(BiTnode));
- s->data =key;
- s->lchild = s->rchild = NULL;
- if(!p)
- {
- printf("Create Tree with key:%d\n",key);
- *T = s; //create Bst one node
- }
- else if(key < p->data)
- {
- printf("Insert Key To Tree(left):%d\n",key);
- p->lchild = s;
- }
- else
- {
- printf("Insert Key To Tree(right):%d\n",key);
- p->rchild = s;
- }
- return true;
- }
- else
- {
- return false;
- }
- }
- /*
- inorder traversal method
- */
- void Inordervist(const BiTree T)
- {
- if(T)
- {
- Inordervist(T->lchild);
- printf("%d\n",T->data);
- Inordervist(T->rchild);
- }
- }
- /*
- postorder traversal method to destroy tree
- */
- void BTreedestroy(BiTree T)
- {
- if(T)
- {
- BTreedestroy(T->lchild);
- BTreedestroy(T->rchild);
- printf("Delete node for Key%d\n",T->data);
- xfree(T);
- }
- }
- bool DeleteBst(BiTree *T,int key)//use **p *p is parent->child,here is very import
- {
- if(!*T)//
- {
- printf("no delete data %d find\n........\n",key);
- return true;
- }
- else
- {
- if(key == (*T)->data)
- {
- return Delete(T);
- }
- else if(key < (*T)->data)
- {
- return DeleteBst(&(*T)->lchild,key);//here use lchild pointer's address
- }
- else
- {
- return DeleteBst(&(*T)->rchild,key);
- }
- }
- }
- bool Delete(BiTree *p)//use **p *p is parent->child,here is very import
- {
- BiTree q,s;
- printf("delete data :%d\n........\n",(*p)->data);
- if((*p)->rchild == NULL)//right node is NULL
- {
- q = *p;
- *p = (*p)->lchild;
- xfree(q);
- }
- else if((*p)->lchild ==NULL)//leaf node is NULL
- {
- q = *p;
- *p = (*p)->rchild;
- xfree(q);
- }
- else //exp:use ...20 30 50 (60 delete)... use 50 replace 60 ,use replace not free find node
- {
- q = *p;
- //---------------
- s = (*p)->lchild;
- while(s->rchild) //if s->rchild is NULL q=*p mean (*p)->lchild s have no right node
- {
- q = s;
- s = s->rchild;
- }
- (*p)->data = s->data;
- /*-------------- here find near delete node small data,frist find lchild then find
- all small data root node then find last right node this is require data*/
- if(q!=*p) //if (*p)->lchild s have right node
- {
- q->rchild =s->lchild;
- }
- else // if (*p)->lchild s have no right node
- {
- q->lchild = s ->lchild;
- }
- xfree(s);//free find last right node,beacuse it's data used for find node
- }
- }
点击(此处)折叠或打开
- 测试用例和主函数
- main.c
- #include<stdio.h>
- #include"bstort.h"
- int main(void)
- {
- BiTree root = NULL;
- InsertBst(&root,10);
- InsertBst(&root,20);
- InsertBst(&root,40);
- InsertBst(&root,5);
- InsertBst(&root,1);
- InsertBst(&root,-1);
- InsertBst(&root,-20);
- InsertBst(&root,100);
- printf("Use inorder traversal method:\n");
- Inordervist(root);
- DeleteBst(&root,30);
- DeleteBst(&root,10);
- printf("Use inorder traversal method:\n");
- Inordervist(root);
- printf("Use postorder traversal method destroy Bst:\n");
- BTreedestroy(root);
- }
结构如下:
Create Tree with key:10
Insert Key To Tree(right):20
Insert Key To Tree(right):40
Insert Key To Tree(left):5
Insert Key To Tree(left):1
Insert Key To Tree(left):-1
Insert Key To Tree(left):-20
Insert Key To Tree(right):100
Use inorder traversal method:
-20
-1
1
5
10
20
40
100
no delete data 30 find
........
delete data :10
........
Use inorder traversal method:
-20
-1
1
5
20
40
100
Use postorder traversal method destroy Bst:
Delete node for Key-20
Delete node for Key-1
Delete node for Key1
Delete node for Key100
Delete node for Key40
Delete node for Key20
Delete node for Key5
这里首先演示了建树,然后演示了中序遍历返回有序的结果,然后删除一个不包含的数据30,
然后删除一个包含的数据10,然后再次进行中序遍历,最后使用后续遍历删除。
可以看到结果如我们希望的。