二叉排序树
2016-02-03 23:51
211 查看
二叉查找树(英语:Binary Search Tree),也称二叉搜索树、有序二叉树(英语:ordered binary tree),排序二叉树(英语:sorted
binary tree),是指一棵空树或者具有下列性质的二叉树:
任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
任意节点的左、右子树也分别为二叉查找树;
没有键值相等的节点。
从上述定义可知,二叉排序树是记录之间满足一定次序关系的二叉树。下面介绍如何构建一棵二叉排序树,以及遍历,插入,查找,也会简单的介绍删除结点操作。
构造一棵排序二叉树,则一定要根据其定义来实现。下面给出相关代码:
但是在二叉查找树删去一个结点,分三种情况讨论:(如下参考维基百科:点击打开链接)
1.若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
2.若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉查找树的特性。
3.若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:其一是令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树,*s为*p左子树的最右下的结点,而*p的右子树为*s的右子树;其二是令*p的直接前驱(in-order predecessor)或直接后继(in-order
successor)替代*p,然后再从二叉查找树中删去它的直接前驱(或直接后继),该种情况较为复杂,如下图示。
算法:
binary tree),是指一棵空树或者具有下列性质的二叉树:
任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
任意节点的左、右子树也分别为二叉查找树;
没有键值相等的节点。
从上述定义可知,二叉排序树是记录之间满足一定次序关系的二叉树。下面介绍如何构建一棵二叉排序树,以及遍历,插入,查找,也会简单的介绍删除结点操作。
构造一棵排序二叉树,则一定要根据其定义来实现。下面给出相关代码:
#include<iostream> using namespace std; typedef struct bstNote { int data; struct bstNote *lchild, *rchild; }*bstTree; void insertNote(bstTree &bst, int _data) { if (bst == NULL) { bst = new bstNote; bst->data = _data; bst->lchild = bst->rchild = NULL; return; } if (bst->data == _data) { exit(-1); } else if(bst->data > _data) insertNote(bst->lchild, _data); else insertNote(bst->rchild, _data); } void createBST(bstTree &bst,int *arry,int length){ bst = NULL; for (int i = 0; i < length; i++) { insertNote(bst, arry[i]); } } void preOrder(bstTree bst) { if (bst == NULL) { return; } cout << bst->data << " "; preOrder(bst->lchild); preOrder(bst->rchild); } void inOrder(bstTree bst) { if (bst == NULL) { return; } inOrder(bst->lchild); cout << bst->data << " "; inOrder(bst->rchild); } void postOrder(bstTree bst) { if (bst == NULL) { return; } postOrder(bst->lchild); postOrder(bst->rchild); cout << bst->data << " "; } bstTree searchBST(bstTree bst, int key) { if (bst == NULL) return false; else if (bst->data == key) { cout << "查找成功:"<<bst->data<< endl; return bst; } else if(bst->data>key) return searchBST(bst->lchild, key); else return searchBST(bst->rchild, key); } int main(){ bstTree bst; int arry[] = {4,5,2,1,3,10,7,8,6,0}; int length = sizeof(arry) / sizeof(int); createBST(bst, arry, length); cout << "PreOrder:" << endl;; preOrder(bst); cout << endl; cout << "InOrder:" << endl; inOrder(bst); cout << endl; cout << "PostOrder:" << endl;; postOrder(bst); cout << endl; searchBST(bst,6); insertNote(bst, 9); preOrder(bst); cout << endl; inOrder(bst); }上面的代码比较简单的实现构造,遍历,查找。
但是在二叉查找树删去一个结点,分三种情况讨论:(如下参考维基百科:点击打开链接)
1.若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
2.若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树(当*p是左子树)或右子树(当*p是右子树)即可,作此修改也不破坏二叉查找树的特性。
3.若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:其一是令*p的左子树为*f的左/右(依*p是*f的左子树还是右子树而定)子树,*s为*p左子树的最右下的结点,而*p的右子树为*s的右子树;其二是令*p的直接前驱(in-order predecessor)或直接后继(in-order
successor)替代*p,然后再从二叉查找树中删去它的直接前驱(或直接后继),该种情况较为复杂,如下图示。
算法:
Status DeleteBST(BiTree &T, KeyType key){ //若二叉查找树T中存在关键字等于key的数据元素时,则删除该数据元素,并返回 //TRUE;否则返回FALSE if(!T) return false; //不存在关键字等于key的数据元素 else{ if(key == T->data.key) { // 找到关键字等于key的数据元素 return Delete(T); } else if(key < T->data.key) return DeleteBST(T->lchild, key); else return DeleteBST(T->rchild, key); } } Status Delete(BiTree &p){ //该节点为叶子节点,直接删除 BiTree *q, *s; if (!p->rchild && !p->lchild) { delete p; p = NULL; } else if(!p->rchild){ //右子树空则只需重接它的左子树 q=p->lchild; p->data = p->lchild->data; p->lchild=p->lchild->lchild; p->rchild=p->lchild->rchild; delete q; } else if(!p->lchild){ //左子树空只需重接它的右子树 q=p->rchild; p->data = p->rchild->data; p->lchild=p->rchild->lchild; p->rchild=p->rchild->rchild; delete q; } else{ //左右子树均不空 q=p; s=p->lchild; while(s->rchild){ q=s; s=s->rchild; } //转左,然后向右到尽头 p->data = s->data; //s指向被删结点的“前驱” if(q!=p) q->rchild = s->lchild; //重接*q的右子树 else q->lchild = s->lchild; //重接*q的左子树 delete s; } return true; }
相关文章推荐
- 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
- 2016/02/03
- C/C++的静态库与动态库
- MarkDwon的使用方法
- JavaScript中的作用域和闭包浅谈
- hdu 2089 不要62
- windows下安装、卸载mysql服务
- win禁用睡眠(关屏不睡眠)
- PHP 开发者该知道的 5 个 Composer 小技巧
- CMDB客户端检测的简单实现 (待续)
- 枉法裁判
- Gym 100814C Connecting Graph 并查集+LCA
- 名词解释之人身险保全
- linux 将光盘package作为yum源的方法及实践
- 网络工程 POST与GET请求方法的本质区别
- 基于TCP流协议的数据包通讯
- noj 1006 多项式乘法
- xxxx和xxxx_s在VS2013中错误
- URAL 1326(状态压缩DP)
- 51Nod 1057 N的阶乘(数论)