一个简单的二叉搜索树(C++实现)
参考:http://www.cnblogs.com/skywang12345/p/3576373.html
这里主要就是自己实现的代码,删除动作有点不一样:
#ifndef __BSTREE_H__
#define __BSTREE_H__
/*
参考:http://www.cnblogs.com/skywang12345/p/3576373.html 这里是介绍二叉查找树 1)若任意结点的左子树不空,则左子树上所有的结点的值均小于它的根结点的值
2)若任意结点的右子树不空,则左子树上所有的结点的值均大于它的根结点的值
3)任意结点的左右子树也分别为二叉查找树
4)没有键值相等的结点(但是这里实现的可以有相同key值的结点)。当键值相同时,插入在右子树中。
*/
#include<iomanip>
#include<iostream>
using namespace std; template <class T>
class BSTNode
{
public:
T key;
BSTNode *left;
BSTNode *right;
BSTNode *parent; BSTNode(T value, BSTNode *p, BSTNode *l, BSTNode *r):key(value), parent(p),left(l), right(r)
{
//cout << "BSTNode() +++ " << endl;
}
}; template <class T>
class BSTree
{
private:
public:
BSTNode <T> *mRoot; public:
BSTree();
~BSTree(); void insert(T key);
void print();
void preOrder();
T maximum();
T minimum();
int remove(T data);
void destory(); private:
void insert(BSTNode<T> *&tree, BSTNode<T> *z);
void print(BSTNode<T> *tree, T key, int direction);
void preOrder(BSTNode<T> *tree) const;
BSTNode<T>* maximum(BSTNode<T> *tree);
BSTNode<T>* minimum(BSTNode<T> *tree);
BSTNode<T>* getNode(T data);
void destory(BSTNode<T> *tree);
}; template <class T>
BSTree<T>::BSTree()
{
mRoot = NULL;
} template <class T>
BSTree<T>::~BSTree()
{ } template <class T>
void BSTree<T>::insert(T key)
{
BSTNode<T> *z = new BSTNode<T>(key, NULL, NULL, NULL);
if(z)
{
insert(mRoot, z);
}
} // 这里的&是引用传递
template <class T>
void BSTree<T>::insert(BSTNode<T> *&tree, BSTNode<T> *pNode)
{
BSTNode<T> *pIndex = NULL;
BSTNode<T> *pTemp = tree; // 先找到插入的位置
while(pTemp != NULL)
{
pIndex = pTemp;
if(pNode->key < pTemp->key)
pTemp = pTemp->left;
else
pTemp = pTemp->right;
} pNode->parent = pIndex;
if(!pIndex)
tree = pNode;
else if(pNode->key < pIndex->key)
pIndex->left = pNode;
else
pIndex->right = pNode; } template <class T>
void BSTree<T>::print()
{
if(mRoot)
{
print(mRoot, mRoot->key, );
}
} /*
key:结点的键值
direction:
-1 - 表示为左孩子
0 - 表示为根节点
1 - 表示为左孩子
*/
template <class T>
void BSTree<T>::print(BSTNode<T> *tree, T key, int direction)
{
if(tree)
{
if(direction == )
cout << setw() << tree->key << " is root" << endl;
else
cout << setw() << tree->key << " is " << setw() << key << "'s " << setw() << (direction==?"right child":"left child") << endl; print(tree->left, tree->key, -);
print(tree->right, tree->key, );
}
} template <class T>
void BSTree<T>::preOrder()
{
cout << "preOrder: ";
preOrder(mRoot);
cout << endl;
} // 这里是遍历。
template <class T>
void BSTree<T>::preOrder(BSTNode<T> *tree) const
{
if(tree)
{
#if 1 // 前置遍历
cout << tree->key << " ";
preOrder(tree->left);
preOrder(tree->right);
#endif #if 0 // 中序遍历
preOrder(tree->left);
cout << tree->key << " ";
preOrder(tree->right);
#endif #if 0 // 后序遍历
preOrder(tree->left);
preOrder(tree->right);
cout << tree->key << " ";
#endif
}
} // 找二叉查找树中的最大值,返回key值最大的那个结点
template <class T>
BSTNode<T> * BSTree<T>::maximum(BSTNode<T> *tree)
{
BSTNode<T> *temp = tree;
if(temp)
{
while(temp->right)
{
temp = temp->right;
} return temp;
}
else
{
return NULL;
}
} // 找二叉查找树中的最小值,返回key值最小的那个结点
template <class T>
BSTNode<T> * BSTree<T>::minimum(BSTNode<T> *tree)
{
BSTNode<T> *temp = tree;
if(temp)
{
while(temp->left)
{
temp = temp->left;
} return temp;
}
else
{
return NULL;
}
} template <class T>
T BSTree<T>::maximum()
{
BSTNode<T> *temp = maximum(mRoot);
if(temp)
{
return temp->key;
} return NULL;
} template <class T>
T BSTree<T>::minimum()
{
BSTNode<T> *temp = minimum(mRoot);
if(temp)
{
return temp->key;
} return NULL;
} // 通过data去获取结点。
template <class T>
BSTNode<T>* BSTree<T>::getNode(T data)
{
BSTNode<T> *temp = mRoot;
if(!temp)
{
return NULL;
} while(temp)
{
if(temp->key == data)
return temp;
else if(temp->key < data)
temp = temp->right;
else
temp = temp->left;
} return NULL;
} // 这个仅仅是用来打印结点的。测试用的
template <class T>
void showNode(BSTNode<T>* node)
{
if(node->parent)
{
cout << " parent: " << node->parent->key << endl;
}
else
{
cout << " parent is NULL" << endl;
} if(node->left)
{
cout << " left: " << node->left->key << endl;
}
else
{
cout << " left is NULL" << endl;
} if(node->right)
{
cout << " right: " << node->right->key << endl;
}
else
{
cout << " right is NULL" << endl;
}
} /*
参考:http://blog.csdn.net/zq17865815296/article/details/52658908
先说一下如何删除二叉树查找树的节点吧。总共有三种情况
1.被删除的节点是叶子节点,这时候只要把这个节点删除,再把指向这个节点的父节点指针置为空就行
2.被删除的节点有左子树,或者有右子树,而且只有其中一个,那么只要把当前删除节点的父节点指向被删除节点的左子树或者右子树就行。
3.被删除的节点既有左子树而且又有右子树,这时候需要把左子树的最右边的节点或者右子树最左边的节点提到被删除节点的位置,为什么要这样呢,
根据二叉查找树的性质,父节点的指针一定比所有左子树的节点值大而且比右子树的节点的值小,为了删除父节点不破坏二叉查找树的平衡性,
应当把左子树最大的节点或者右子树最小的节点放在父节点的位置,这样的话才能维护二叉查找树的平衡性。(我是找的右子树的最小节点)
*/
template <class T>
int BSTree<T>::remove(T data)
{
cout << "remove :" << data << endl;
BSTNode<T>* node = getNode(data);// 这里要找到要删除的结点。
if(node)
{
showNode(node);
if(node->parent == NULL)// 删除根结点
{
// 这里选择的是把左子树接到右子树中key最小的那个结点的左结点上。还有一种是把右子树接到左子树的key最大的那个右结点上
BSTNode<T> *temp = minimum(node->right);
if(temp)
{
temp->left = node->left;
mRoot = node->right;// 要更新根节点
}
delete node;
node = NULL;
return ;
} if((node->right == NULL) && (node->left == NULL)) // 删除叶子结点
{
if(node->parent->left == node)
{
node->parent->left = NULL;
}
else
{
node->parent->right = NULL;
}
}
else if(node->right && node->left) // 删除有两个子节点的
{
BSTNode<T> *temp = minimum(node->right); // 获取后继结点,这个结点一定是没有左子树的。
cout << "have left and right child, mimmum :" << temp->key << endl;
if(temp == temp->parent->left) // 后继结点如果是左结点,就将它的右子树接到它父亲的左子树中。
{
temp->parent->left = temp->right;
}
else // 后继结点如果是右结点,就将它的右子树接到它父亲的右子树中。
{
temp->parent->right = temp->right;
}
node->key = temp->key; // 把后继结点的key保存在要删除的结点中
delete temp; // 其实是删除的后继结点。
temp = NULL;
}
else // 删除只有一个只有一个子结点。
{
if(node->right) // 有右子节点
{
if(node->parent->left == node)
{
node->parent->left = node->right;
}
else
{
node->parent->right = node->right;
}
}
else
{
if(node->parent->left == node)
{
node->parent->left = node->left;
}
else
{
node->parent->right = node->left;
}
}
delete node;
node = NULL;
} }
else
{
return -;
} return ;
} template <class T>
void BSTree<T>::destory(BSTNode<T> *tree)
{
if(tree)
{
if(tree->left)
destory(tree->left);
if(tree->right)
destory(tree->right);
delete tree;
tree = NULL;
}
} template <class T>
void BSTree<T>::destory()
{
destory(mRoot);
} #endif // __BSTREE_H__
下面是测试代码:
#include<iostream>
#include"bstree.h"
using namespace std; /*
可以插入相同的,会插入在右子树中。
*/
void fun()
{
cout << "fun() +++ " << endl;
int i = , len = ;
BSTree<int>* tree = new BSTree<int>;
if(tree->mRoot == NULL)
cout << "fun() mRoot is NULL" << endl;
int arr[] = {, , , , , , , , , };
int count = sizeof(arr)/sizeof(int);
for(int i = ; i<count; i++)
{
tree->insert(arr[i]);
}
tree->insert(); tree->insert();
tree->preOrder();
int maxkey = tree->maximum();
cout << "Max key = " << maxkey << endl;
int minkey = tree->minimum();
cout << "Min key = " << minkey << endl;
tree->remove();
tree->remove(); tree->preOrder();
//tree->print(); tree->destory();
cout << "fun() --- " << endl;
} int main()
{
cout << "hello world" << endl;
fun();
return ;
}
注意:上面只有bstree.h,没有bstree.cpp。
关于为何C++的模板类声明和实现要放在一起可以参考:http://www.cnblogs.com/xcywt/p/8039574.html
一个简单的二叉搜索树(C++实现)的更多相关文章
- LeetCode(98): 验证二叉搜索树
Medium! 题目描述: 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右 ...
- 「面试高频」二叉搜索树&双指针&贪心 算法题指北
本文将覆盖 「字符串处理」 + 「动态规划」 方面的面试算法题,文中我将给出: 面试中的题目 解题的思路 特定问题的技巧和注意事项 考察的知识点及其概念 详细的代码和解析 开始之前,我们先看下会有哪些 ...
- LeetCode初级算法--树02:验证二叉搜索树
LeetCode初级算法--树02:验证二叉搜索树 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.ne ...
- LeetCode 第98题--验证二叉搜索树
1. 题目 2.题目分析与思路 3.代码 1. 题目 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数.节点的右子树只包含大于当 ...
- 【LeetCode】验证二叉搜索树
[问题]给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征:节点的左子树只包含小于当前节点的数.节点的右子树只包含大于当前节点的数.所有左子树和右子树自身必须也是二叉搜 ...
- Java实现二叉搜索树的插入、删除
前置知识 二叉树的结构 public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() { } TreeNode( ...
- 剑指Offer面试题:22.二叉搜索树的后序遍历序列
一.题目:二叉搜索树的后序遍历序列 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true,否则返回false.假设输入的数组的任意两个数字都互不相同. 例如在下面 ...
- 二叉搜索树(Binary Search Tree)
二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树. 二叉搜索树:一棵二叉树,可以为空:如果不为空,满足以下性质: 非空左子树的所有键值小于其根结点的键值: 非空右 ...
- LeetCode - 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树. 一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是二叉搜索树. ...
随机推荐
- Linux Socket 编程简介
在 TCP/IP 协议中,"IP地址 + TCP或UDP端口号" 可以唯一标识网络通讯中的一个进程,"IP地址+端口号" 就称为 socket.本文以一个简单的 ...
- 调试OV2735总结
调试找到的问题: 1:开始调试的时候因为之前的工程师原理图和BOM出错,导致本来是2.8V电压的焊接的是1.8V的LDO所以这个是第一个问题 2:因为FAE反应说sensor没有反应I2C没有通信,所 ...
- Redis源码阅读(二)高可用设计——复制
Redis源码阅读(二)高可用设计-复制 复制的概念:Redis的复制简单理解就是一个Redis服务器从另一台Redis服务器复制所有的Redis数据库数据,能保持两台Redis服务器的数据库数据一致 ...
- 开源一个最近写的spring与mongodb结合的demo(spring-mongodb-demo)
由于工作需要,给同事们分享了一下mongodb的使用,其中主要就是做了一个spring-data+mongodb的小例子,本着分享的精神,就上传到了github.com上,有需要的同学请移步githu ...
- error: Build input file cannot be found: '*******/node_modules/react-native/Libraries/WebSocket/libfishhook.a' 问题解决记录
解决了刚才的'config.h' file not found问题,本以为就可以顺畅的跑起来,谁知道又被恶心到了,Build input file cannot be found!!! 问题: err ...
- PAT甲题题解-1014. Waiting in Line (30)-模拟,优先级队列
题意:n个窗口,每个窗口可以排m人.有k为顾客需要办理业务,给出了每个客户的办理业务时间.银行在8点开始服务,如果窗口都排满了,客户就得在黄线外等候.如果有一个窗口用户服务结束,黄线外的客户就进来一个 ...
- PAT甲题题解-1124. Raffle for Weibo Followers-模拟,水题
水题一个,贴个代码吧. #include <iostream> #include <cstdio> #include <algorithm> #include &l ...
- js实现随机的四则运算题目
老师给出的题,写一个小程序,可以生成随机的四则运算题目给给小学生用.以前自己就写了一个四则运算的简单js小程序,是这样的: 事件 + - * / 这是个自己输入的算法,但要求是自动产生随机数.于是我用 ...
- Java的起源和发展
程序设计语言的发展 第一代语言:机器语言 0011 1100 …… 第二代语言:汇编语言 ADD 12,0x13 第三 ...
- OpenState之 Mac学习 实验
OpenState之 Mac学习 实验 目录 OpenState安装 Port Knocking 实验 Mac Learning 实验 环境要求: 系统ubuntu 14.04 mininet:2.3 ...