查找二叉树的定义:
存储结构和二叉树相同:
需要实现的方法:
代码:
tree.h
#ifndef _TREE_H #define _TREE_H typedef int ElemType; typedef struct treenode { ElemType data; struct treenode * left; struct treenode * right; }TREE; TREE *MakeEmptyTree(); TREE *InsertTreeNode(ElemType e,TREE *t); TREE *FindTreeNode(ElemType e,TREE *t); TREE *FindMax(TREE *t); TREE *FindMin(TREE *t); TREE *DeleteTreeNode(ElemType e,TREE *t); void DeleteTree(TREE **t); #endif
tree.c
#include<stdio.h> #include<stdlib.h> #include"tree.h" TREE *MakeEmptyTree() { return NULL; } TREE *InsertTreeNode(ElemType e,TREE *t) { if(t == NULL) { t = (TREE *)malloc(sizeof(TREE)); if(t == NULL) return NULL; t->data = e; t->left = t->right = NULL; }else if(e < t->data) t->left = InsertTreeNode(e,t->left); else t->right = InsertTreeNode(e,t->right); return t; } TREE *FindTreeNode(ElemType e,TREE *t) { if(t == NULL) return NULL; if(t->data == e) return t; else if(t->data < e) return FindTreeNode(e,t->right); else return FindTreeNode(e,t->left); } TREE *FindMax(TREE *t) { if(t == NULL) return NULL; if(t->right == NULL) return t; return FindMax(t->right); } TREE *FindMin(TREE *t) { if(t == NULL)return NULL; if(t->left == NULL) return t; return FindMin(t->left); } TREE *DeleteTreeNode(ElemType e,TREE *t) { TREE *p = NULL; if(t == NULL)return NULL; if(t->data > e)//数据比根小 t->left = DeleteTreeNode(e,t->left);//去左子树删 else if(t->data < e) t->right = DeleteTreeNode(e,t->right);//去右子树删 //这个节点就是要删的 else if(t->left && t->right)//有两个子节点的节点 { //找出右子树里最小的 p = FindMin(t->right); t->data = p->data; t->right = DeleteTreeNode(t->data,t->right); }else//要删除的节点有一个子节点或就是叶子节点 { p = t; if(t->left == NULL)//右数有 t = t->right; else if(t->right == NULL) t = t->left; free(p); return t; } return t; } void DeleteTree(TREE **t) { if(*t == NULL) return; DeleteTree(&((*t)->left)); DeleteTree(&((*t)->right)); free(*t); *t = NULL; }
重点解释一下删除一个节点的算法:
包括两种情况,首先这种是要删除单子树节点的情况:
else//要删除的节点有一个子节点或就是叶子节点 { p = t; if(t->left == NULL)//右数有 t = t->right; else if(t->right == NULL) t = t->left; free(p); return t; }
这里是只有左子树,那么只要把他的左节点挂到根上面去。程序实现就是直接返回这个左节点。
如果要删除的是叶子节点,比如删除上图的3,那么执行第一条语句时:
if(t->left == NULL) t = t->right;
就已经把t赋值为右数,第二条赋值左树,都是NULL所以最终t就是NULL,返回的也就是NULL。
释放p,就是原来的t,就成功删除了叶子节点3.
第二种情况就是要删除的是有双子树的一个节点:
else if(t->left && t->right)//有两个子节点的节点 { //找出右子树里最小的 p = FindMin(t->right); t->data = p->data; t->right = DeleteTreeNode(t->data,t->right); }
我们可以找出右子树的最小的节点,当然也可以是左子树最大的节点,先把它的数据提上来,将它递归删除掉。
testBSTree.c
#include<stdio.h> #include"tree.h" void main() { int n; TREE *tree = MakeEmptyTree(),*p; while(1) { printf("Please enter a num:"); fflush(stdin); if(scanf("%d",&n) != 1) break; if(n == 0) break; tree = InsertTreeNode(n,tree); } printf("Max of tree is %d,min of tree is %d\n", FindMax(tree)->data,FindMin(tree)->data); fflush(stdin); printf("Please enter search num:"); scanf("%d",&n); if(FindTreeNode(n,tree)) printf("find %d\n",n); else printf("not find\n"); p = DeleteTreeNode(n,tree); if(p) printf("delete %d success\n",n); else printf("delete fail\n"); DeleteTree(&tree); if(tree == NULL) printf("delete success\n"); else printf("fail\n"); }
运行时:
可以看到最大值输出76,最小值4,找到7,删除了7这个节点,进而删除了整棵树。