查找二叉树:也叫排序二叉树,搜索二叉树。具有以下特点(百度百科)
二叉排序树或者是一棵空树,或者是具有下列性质的
二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的
根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
查找二叉树的创建和基本二叉树的创建无差异
二叉树的清空,实际上就是后序遍历删除
// 想要改变指针的值还是需要将他作为返回值,不然就是传入二级指针 static SearchTree MakeEmpty(SearchTree tree) { if(tree){ MakeEmpty(tree->LeftNode); MakeEmpty(tree->RightNode); free(tree); tree = NULL; } return tree; }
查找二叉树的查找
1、基本二叉树的查找方法
// 实际上这样会将所有的节点都遍历一遍而忽略了查找二叉树的特点 // 以root为界限开始区分两者 static SearchTree FindNode(TreeElement element, SearchTree tree) { SearchTree ret_tree = NULL; if (tree){ if(element==tree->element){ ret_tree = tree; return ret_tree; } ret_tree = FindNode(element, tree->LeftNode); ret_tree = FindNode(element, tree->RightNode); } return ret_tree; }
2、二叉树的特点使用尾递归(递归在函数的尾部)
// 抓住了查找二叉树的特点,可以更加精确的进行查找 static SearchTree Find(TreeElement element, SearchTree tree) { if(tree){ if(tree->element==element){ return tree; }else if(tree->element>element){ return Find(element, tree->LeftNode); }else{ return Find(element, tree->RightNode); } } return NULL; }
3、将尾递归转换成赋值和goto语句
因为二叉树的平均深度是logN,所以使用的栈空间也只是logN,一般还是可以直接使用方法2,以下供参考
// 将尾递归转换成赋值和goto语句 static SearchTree FindNoLoop(TreeElement element, SearchTree tree) { next: if(tree){ if(tree->element==element){ return tree; }else{ if(tree->element>element) tree = tree->LeftNode; else tree = tree->RightNode; goto next; } } return NULL; }
查找二叉树查找最大、最小值
static SearchTree FindMax(SearchTree tree) { next: if(tree){ if(tree->RightNode == NULL) return tree; tree = tree->RightNode; goto next; } return tree; } static SearchTree FindMin(SearchTree tree) { if(tree){ if(tree->LeftNode == NULL) return tree; return FindMin(tree->LeftNode); } return NULL; }
往二叉树中插入元素
扫描二维码关注公众号,回复:
1425786 查看本文章
如果插入的元素已经在二叉树中存在,则只是更新二叉树中记录发生频率的域(这里什么都不做)。否则插入到查找二叉树的尾部。
static SearchTree CreateTreeCell(TreeElement element) { SearchTree tree = NULL; tree = (SearchTree)malloc(sizeof(*tree)); if(tree==NULL){ fprintf(stderr,"there is no space\n"); return NULL; } tree->element= element; tree->RightNode = NULL; tree->LeftNode = NULL; return tree; } static SearchTree Insert(TreeElement element, SearchTree tree) { if(tree){ if(element>tree->element){ if(tree->RightNode==NULL){ tree->RightNode = CreateTreeCell(element); }else{ Insert(element, tree->RightNode); } }else{ if(tree->LeftNode==NULL){ tree->LeftNode = CreateTreeCell(element); }else{ Insert(element, tree->LeftNode); } } return tree; } return NULL; }
这是书上的解法,比我的思路好。
static SearchTree InsertNode(TreeElement element, SearchTree tree) { if(tree==NULL){ tree = (SearchTree)malloc(sizeof(*tree)); if(tree==NULL){ fprintf(stderr,"there is no space\n"); return NULL; } tree->element= element; printf("tree->element is %d\n", tree->element); tree->RightNode = NULL; tree->LeftNode = NULL; }else if(element>tree->element){ //需要将返回值指向tree->RightNode tree->RightNode = InsertNode(element, tree->RightNode); }else{ // 需要将返回值指向tree->LeftNode tree->LeftNode = InsertNode(element, tree->LeftNode); } return tree; }
节点的删除
1)删除的节点为树叶
2)删除的节点包含一个子节点
3)删除的节点包含两个子节点(在该节点的右子树中寻找最小,特换为该节点元素,然后删除右子树元素最小的节点)
值得注意的:当两个指针同时指向同一块内存,free掉一个指针会导致另外一个指针成为野指针,所以也需要将其置为NULL
static SearchTree Delete(TreeElement element, SearchTree tree) { if(tree){ if(element>tree->element){ // 无论是插入还是删除都需要建立指针的指向关系 tree->RightNode = Delete(element, tree->RightNode); }else if(element<tree->element){ tree->LeftNode = Delete(element, tree->LeftNode); }else{ if(tree->RightNode!=NULL&&tree->LeftNode!=NULL){ SearchTree tree_min = FindMin(tree->RightNode); if(tree_min){ printf("tree->element is %d\n", tree->element); tree->element = tree_min->element; tree->RightNode = Delete(tree_min->element, tree->RightNode); } }else{ SearchTree tree_temp = tree; if(tree->RightNode){ tree = tree->RightNode; }else if(tree->LeftNode){ tree = tree->LeftNode; } if(tree==tree_temp){//两个指针同时指向同一块内存,需要将其置为NULL tree = NULL; } free(tree_temp); tree_temp = NULL; } } return tree; } }