旭说数据结构之二叉查找树
来源:互联网 发布:ubuntu 卸载apache2 编辑:程序博客网 时间:2024/04/29 00:59
上一篇详细介绍树的特殊结构——二叉树的相关知识和操作。
这一篇介绍二叉树的特殊结构——二叉查找树。
较之一般的二叉树,二叉查找树限定了结点的左子树的所有结点值均小于该结点,结点的右子树的所有结点值均大于该结点。下图给了一个示意:
所以在往二叉查找树中插入元素时,要注意,不能随便找到一个空位就插入,而是要通过与根结点的比较,判断插在根结点的左子树还有右子树,倘若应该插在右子树,在与右子树的根结点比较,判断应该插在右子树的哪个子树上,如此,这是个递归的过程。于是我们可以用递归来实现插入:
1.递归和非递归插入
//递归插入数据 void insertDataToBST1(BSTNode<DataType>**root,DataType data) { if (*root == NULL) { *root = new BSTNode<DataType>(data); return; } if (data<((*root)->_data)) { insertDataToBST1(&((*root)->_lChild),data); } if (data>((*root)->_data)) { insertDataToBST1(&((*root)->_rChild),data); } }
非递归插入数据的思路也不难,下面给出代码:
//非递归插入数据 void insertDataToBST2(BSTNode<DataType>**root,DataType data) { if (*root == NULL) { *root = new BSTNode<DataType>(data); return; } BSTNode<DataType>* p = *root; while(p){//从根结点开始,寻找到一个能放置data的空位置 if (data > p->_data)//如果data比该结点大,而正好该结点的右孩子为NULL, //则正好插入到这个结点的右孩子处 { if (p->_rChild == NULL) { p->_rChild = new BSTNode<DataType>(data); break; } else//如果右孩子不是空的,则还得往下找 { p = p->_rChild; } } if (data < p->_data) { if (p->_lChild == NULL) { p->_lChild = new BSTNode<DataType>(data); break; } else { p=p->_lChild; } } } }
2.遍历
由于二叉查找树的特殊性质,我们对一颗二叉查找树进行中序遍历,得到的中序序列是按照从小到大的顺序排列的。
二叉查找树也是一颗二叉树,故遍历方法与二叉树的相同:
//递归中序遍历 void inOrderWithRecursion() { cout<<"中序遍历"; inOrder1(_root); } void inOrder1(BSTNode<DataType>* root) { if (root == NULL)return; inOrder1(root->_lChild); cout<<root->_data; inOrder1(root->_rChild); } //非递归中序遍历 void inOrder() { Stack<BSTNode<DataType>*>* nodeStack = new Stack<BSTNode<DataType>*>; BSTNode<DataType>* p = _root; while(p!=NULL)// 从根结点一路向左,入栈 { nodeStack->push(p); p=p->_lChild; } //取出栈中元素,打印,发现该元素有右子树,把右子树一路向左入栈 while(!nodeStack->isEmpty()) { p = nodeStack->pop(); cout<<p->_data; if (p->_rChild) { p=p->_rChild; while(p) { nodeStack->push(p); p=p->_lChild; } } } }
3.删除操作
删除操作是较复杂的一个操作,得分不同的情况进行讨论,下图给出了示意:
此外如果我们删除的结点是根结点,情况也有些许不同:
下面给出代码:代码中的getParentNode是一个成员函数,用于返回给定结点的父结点;findData也是一个成员函数,根据给定值返回对应的结点;findMin用于返回给定子树的最小值结点
bool deleteData(DataType data) { //首先在整个树中寻找是否有这个结点 //findData是一个成员函数 BSTNode<DataType>* p = findData(data); //如果没有找到这个结点,就不用删除了,返回false if (p==NULL)return false; //如果找到了要删除的结点,要判断这个结点是不是根结点 if (p!=_root)//如果删除的不是根结点,则p定有父结点 { if (p->_lChild==NULL&&p->_rChild==NULL)//要删除结点的左右孩子都为空 { //如果要删除节点被父结点的左指针指着,则把这个左指针设为NULL if (getParentNode(p)->_lChild = p) { getParentNode(p)->_lChild = NULL; }else{//如果要删除节点被父结点的右指针指着,则把这个右指针设为NULL getParentNode(p)->_rChild = NULL; } delete p; }else if (p->_lChild && p->_rChild)//要删除结点的左右孩子都不为空 { BSTNode<DataType>*minNode = findMin(p->_rChild); if (minNode == p->_rChild) { p->_data = minNode->_data; p->_rChild=minNode->_rChild; delete minNode; }else{ p->_data = minNode->_data; getParentNode(minNode)->_lChild = NULL; delete minNode; } }else{//要删除结点只有一个孩子 if (p->_rChild)//有右孩子的话 { if (getParentNode(p)->_lChild = p) { getParentNode(p)->_lChild = p->_rChild; }else{ getParentNode(p)->_rChild = p->_rChild; } } if (p->_lChild)//有左孩子的话 { if (getParentNode(p)->_lChild = p) { getParentNode(p)->_lChild = p->_lChild; }else{ getParentNode(p)->_rChild = p->_lChild; } } delete p; } }else{//如果要删除的是根结点 if (p->_lChild==NULL&&p->_rChild==NULL)//如果根结点的左右孩子都为空 { if (_root) { delete _root; _root =NULL; } }else if (p->_lChild&&p->_rChild){//如果根结点左右孩子都有 BSTNode<DataType>*minNode = findMin(p->_rChild); if (minNode == p->_rChild) { p->_data = minNode->_data; p->_rChild=minNode->_rChild; delete minNode; }else{ p->_data = minNode->_data; getParentNode(minNode)->_lChild = NULL; delete minNode; } }else{ if (p->_lChild)//如果有左子树 { _root = p->_lChild; delete p; } if (p->_rChild) { _root = p->_rChild; delete p; } } } return true; }
4.寻找包含关键字的结点
BSTNode<DataType>* findData(DataType data) { BSTNode<DataType>* p = _root; while(p) { if (data > p->_data) { p = p->_rChild; }else if (data<p->_data) { p = p->_lChild; }else { break; } } //p可能为NULL if (p) { cout<<"找到了"<<p->_data<<endl; }else{ cout<<"没有找到"<<data; } return p; }
5.寻找给定子树的的最小值
BSTNode<DataType>* findMin(BSTNode<DataType>* node) { BSTNode<DataType>* p = node; while(p) { if (p->_lChild == NULL) { break; } p = p->_lChild; } return p; }
6. 找一个结点的父结点
BSTNode<DataType>* getParentNode(BSTNode<DataType>* child) { if (child == NULL||child == _root)return NULL; //利用层序遍历的思路,使用队列 Queue<BSTNode<DataType>*>* queue = new Queue<BSTNode<DataType>*>; //先把根结点入队 queue->addDataToQueue(_root); BSTNode<DataType>* p = NULL; //当队列不空时 while(queue->count()){ //取出队首元素,第一次取出的是根结点,打印根结点,再把根结点的左右孩子入队列, //下一次取出的队首元素就是root的左孩子,然后把它的左右孩子入队列 //每次都是打印这个结点,然后把它的左右孩子入队,最终所有的结点都会入队列, p=queue->deleteDataFromQueue(); if (p->_lChild) { if (p->_lChild == child) { return p; } queue->addDataToQueue(p->_lChild); } if (p->_rChild) { if (p->_rChild == child) { return p; } queue->addDataToQueue(p->_rChild); } } }
1 0
- 旭说数据结构之二叉查找树
- 旭说数据结构之二叉树
- 数据结构之二叉查找树
- 数据结构之二叉查找树
- 数据结构之查找二叉树
- 数据结构之二叉查找树
- 数据结构之二叉查找树
- 数据结构之查找二叉树
- 数据结构之二叉查找树
- 数据结构之查找二叉树
- 数据结构之二叉查找树
- 数据结构之二叉查找树
- 数据结构之二叉查找树
- 数据结构之二叉查找树
- 数据结构之二叉查找树
- 数据结构之二叉查找树
- 数据结构之二叉树(二叉查找树)
- 数据结构查找算法之二叉查找树
- Apache Storm 学习:Supervisor,Worker,Executor,Task
- Tcpdump 和 Wireshark 的结合使用(一)
- 数字图像处理领域的二十四个典型算法及vc实现、第一章
- Javascript中null和undefined的区别
- HDU 2433 - Travel
- 旭说数据结构之二叉查找树
- sql server T-SQL 基础
- SQLServer:定时作业的设置方法
- 七步写出优秀的JS代码
- 在Android加入和使用Realm
- adb命令、adb shell与Linux各种命令(busybox)
- python argparse的例子
- iOS 网络请求返回错误码汇总
- 如何写好博客——写作中最容易用错的字词