二叉查找树的各项操作(重点是结点的删除部分和递归的运用)
2012-01-16 16:20
225 查看
大半年前学二叉树时,看不懂删除结点的代码,对递归的理解很浅,今天把问题一并解决,加深对递归的理解。
1.删除结点的算法描述:如果待删除的结点至多只有一个子结点,那么需要删除的就是这个结点本身,通过改变指针指向即可;如果待删除的结点有2个结点,那么就需要删除这个结点在中序遍历时的直接后继结点,再通过赋值完成删除。删除后要记得释放结点空间。
2.递归:递归在非线性结构中用的非常普遍。二叉树的查找,插入,删除都可以用递归实现。以前刚学递归的时候老师说递归算法需要长时间的学习才能够入门,当时根本感觉不到,现在却越来越体会到了。递归固然能够使得程序清晰简洁,但是如果写错,debug的时候是比较痛苦的。
3.总结:《算法导论》上描述的删除结点的算法非常简洁而且清晰,逻辑非常严密,但自己再理解上花费了不少时间,说明自己的思考练习还差的很远,今后要进一步加强思维上的练习。
4.算法代码及测试代码:
代码如下: 注:前半部分函数是大半年前的代码,命名规则上与现在有所不同。
1.删除结点的算法描述:如果待删除的结点至多只有一个子结点,那么需要删除的就是这个结点本身,通过改变指针指向即可;如果待删除的结点有2个结点,那么就需要删除这个结点在中序遍历时的直接后继结点,再通过赋值完成删除。删除后要记得释放结点空间。
2.递归:递归在非线性结构中用的非常普遍。二叉树的查找,插入,删除都可以用递归实现。以前刚学递归的时候老师说递归算法需要长时间的学习才能够入门,当时根本感觉不到,现在却越来越体会到了。递归固然能够使得程序清晰简洁,但是如果写错,debug的时候是比较痛苦的。
3.总结:《算法导论》上描述的删除结点的算法非常简洁而且清晰,逻辑非常严密,但自己再理解上花费了不少时间,说明自己的思考练习还差的很远,今后要进一步加强思维上的练习。
4.算法代码及测试代码:
代码如下: 注:前半部分函数是大半年前的代码,命名规则上与现在有所不同。
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <ctype.h> typedef struct node//定义一个二叉树结点 { long item;//结点数值 int count;//计数器 struct node *pLeft; struct node *pRight; }NODE; //函数原型 NODE *CreatNode(long value); NODE *AddNode(long value,NODE *pNode); void ListNodesAsc(NODE *pNode); NODE *tree_search(NODE *pNode,long k); NODE *iterative_tree_search(NODE *pNode,long k); NODE *iterative_tree_search(NODE *pNode,long k); NODE *tree_minimum(NODE *pNode); NODE *tree_maximun(NODE *pNode); void parent(NODE *&pNode,NODE *&p,NODE *head); NODE *tree_successor(NODE *&pNode,NODE *&p,NODE *head); void tree_delete(NODE *head,long k); //声明全局变量,存储根结点 NODE *root=NULL; int main() { long value=0; NODE *pNode=NULL; long test[]={15,6,3,7,2,4,13,9,18,17,20};//测试数据 for(int i=0;i<11;i++) { value=test[i]; if(pNode==NULL) pNode=CreatNode(value); else AddNode(value,pNode); } root=pNode;//得到根结点 ListNodesAsc(pNode); printf("\n"); NODE *result=NULL; //测试 //result=tree_successor(pNode->pLeft->pRight->pRight,result,pNode); //parent(pNode->pLeft->pRight->pRight,result,pNode); //printf("\n%ld",result->item); tree_delete(pNode,15); ListNodesAsc(pNode); getch(); } //创建结点 NODE *CreatNode(long value) { NODE *pNode=(NODE *)malloc(sizeof(NODE)); pNode->item=value; pNode->count=1; pNode->pLeft=pNode->pRight=NULL; return pNode; } //添加结点 NODE *AddNode(long value,NODE *pNode) { if(pNode==NULL) return CreatNode(value); if(pNode->item==value) { pNode->count++; return pNode; } else if(value<pNode->item) { if(pNode->pLeft==NULL) { pNode->pLeft=CreatNode(value); return pNode->pLeft;//注意:这里不能直接写成return CreatNode(value);是因为必须要有根结点与左结点的联系 } else //加上else看起来更加的清晰,有利于维护 return AddNode(value,pNode->pLeft); } else //value>pNode->item的情况 { if(pNode->pRight==NULL) { pNode->pRight=CreatNode(value); return pNode->pRight; } else return AddNode(value,pNode->pRight); } } //升序排列二叉树(中序遍历二叉树) void ListNodesAsc(NODE *pNode) { if(pNode->pLeft!=NULL) ListNodesAsc(pNode->pLeft); for(int i=0;i<pNode->count;i++) printf("%d ",pNode->item); if(pNode->pRight!=NULL) ListNodesAsc(pNode->pRight); } //查找 NODE *tree_search(NODE *pNode,long k) { if(pNode==NULL || k==pNode->item) return pNode; if(k<pNode->item) return tree_search(pNode->pLeft,k); else return tree_search(pNode->pRight,k); } //非递归查找 NODE *iterative_tree_search(NODE *pNode,long k) { while(pNode!=NULL && k!=pNode->item) { if(k<pNode->item) pNode=pNode->pLeft; else pNode=pNode->pRight; } return pNode; } //查找最小值 NODE *tree_minimum(NODE *pNode) { if(pNode==NULL) return NULL; while(pNode->pLeft!=NULL) pNode=pNode->pLeft; return pNode; } //查找最大值 NODE *tree_maximun(NODE *pNode) { if(pNode==NULL) return NULL; while(pNode->pRight!=NULL) pNode=pNode->pRight; return pNode; } //计算父亲结点 void parent(NODE *&pNode,NODE *&p,NODE *head) { if(head!=NULL) { if((head->pLeft!=NULL && head->pLeft==pNode )|| (head->pRight!=NULL && head->pRight==pNode)) { p=head; //return p; //问:为什么这里必须要返回一个指针? 粗心错误,把这个函数的返回值误设为void * } if(head->pLeft!=NULL) parent(pNode,p,head->pLeft); if(head->pRight!=NULL) parent(pNode,p,head->pRight); } } //查找一个结点的后继 NODE *tree_successor(NODE *&pNode,NODE *&p,NODE *head) { if(pNode->pRight!=NULL) return tree_minimum(pNode->pRight); parent(pNode,p,head); NODE *p1=p; while(p1!=NULL && p1->pRight==pNode) { pNode=p1; parent(p1,p1,head); } return p1; } //删除一个结点 void tree_delete(NODE *head,long k) { NODE *target=tree_search(head,k); NODE *y=NULL,*x=NULL; NODE *p=NULL; if(target->pLeft==NULL || target->pRight==NULL) y=target; else y=tree_successor(target,p,head); if(y->pLeft!=NULL) x=y->pLeft; else x=y->pRight; parent(y,p,head); if(p==NULL) root=x; else if(y==p->pLeft) p->pLeft=x; else p->pRight=x; if(y!=target) { target->item=y->item; free(y);//释放被删除的结点的空间 } else free(target); }
相关文章推荐
- 二叉查找树/删除结点操作
- 二叉查找树(Binary Search Tree)--结点的删除操作(导入自原博客)
- Orchard运用 - 如何删除部分内容显示
- 文件操作总结-递归删除文件(文件下含有多级目录和文件)
- 二叉查找树又来了,该死而复杂的删除操作
- 二叉查找树的结点插入,查找,删除,计算二叉树的高度
- 数据结构面试之五—二叉树的常见操作(递归实现部分)
- 删除链表结点和链表分成两部分
- 运用递归的方式删除整个目录及其中的文件
- Java删除文件夹 及目录下 文件 递归操作
- 运用js动态操作table(新增,删除相关列信息)
- 链表操作二——中间结点的删除等
- 怎样在JAVA 中封装数据库操作(增删改查)运用反射机制!已贴出删除和查询方法,求增加和修改!
- 链表操作 对链表进行输入,插入,删除结点,按关键字进行查找操作 C语言
- C# 文件操作 全收录 追加、拷贝、删除、移动文件、创建目录、递归删除文件夹及文件
- (2)单链表的操作 ① 输入一组整型元素序列,使用尾插法建立一个带有头结点的单链表。 ② 实现该线性表的遍历。 ③ 在该单链表的第i个元素前插入一个整数。 ④ 删除该单链表中的第i个元素,其值通过参数
- bo2-8.cpp 不带头结点的单链表(存储结构由c2-2.h定义)的部分基本操作(9个)
- HTML-★★★★JavaScript的DOM操作★★★★-重点部分
- 二叉查找树的插入、删除、查找操作
- 二叉查找树的基本操作之查找插入删除