参考: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++实现)的更多相关文章

  1. LeetCode(98): 验证二叉搜索树

    Medium! 题目描述: 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右 ...

  2. 「面试高频」二叉搜索树&双指针&贪心 算法题指北

    本文将覆盖 「字符串处理」 + 「动态规划」 方面的面试算法题,文中我将给出: 面试中的题目 解题的思路 特定问题的技巧和注意事项 考察的知识点及其概念 详细的代码和解析 开始之前,我们先看下会有哪些 ...

  3. LeetCode初级算法--树02:验证二叉搜索树

    LeetCode初级算法--树02:验证二叉搜索树 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.ne ...

  4. LeetCode 第98题--验证二叉搜索树

    1. 题目 2.题目分析与思路 3.代码 1. 题目 给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数.节点的右子树只包含大于当 ...

  5. 【LeetCode】验证二叉搜索树

    [问题]给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征:节点的左子树只包含小于当前节点的数.节点的右子树只包含大于当前节点的数.所有左子树和右子树自身必须也是二叉搜 ...

  6. Java实现二叉搜索树的插入、删除

    前置知识 二叉树的结构 public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() { } TreeNode( ...

  7. 剑指Offer面试题:22.二叉搜索树的后序遍历序列

    一.题目:二叉搜索树的后序遍历序列 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true,否则返回false.假设输入的数组的任意两个数字都互不相同. 例如在下面 ...

  8. 二叉搜索树(Binary Search Tree)

    二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树. 二叉搜索树:一棵二叉树,可以为空:如果不为空,满足以下性质: 非空左子树的所有键值小于其根结点的键值: 非空右 ...

  9. LeetCode - 验证二叉搜索树

    给定一个二叉树,判断其是否是一个有效的二叉搜索树. 一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是二叉搜索树. ...

随机推荐

  1. ag使用需要注意的问题

    1.  set env 对比服务器标准配置,修改本地 /etc/apache2/sites-available/default (远程链接服务器的办法: ssh 12x.xxx.xxx.xxx) 2. ...

  2. Python 四种数值类型(int,long,float,complex)区别及转换

    Python支持四种不同的数值类型,包括int(整数)long(长整数)float(浮点实际值)complex (复数), 数字数据类型存储数值.他们是不可改变的数据类型,这意味着改变数字数据类型的结 ...

  3. Sprint report

    Sprint report 一.需求分析:随着在校大学生人数的不断增加,许多高校出现了许多个校区并存的局面,并且校区之间的地理位置跨度非常大,给高校选课带来了很大的不方便,数据处理手工操作,工作量大, ...

  4. 第一个spring冲刺总结及后诸葛亮报告(附团队贡献分)

    眨眼就完结了第一阶段的冲刺了,之前因为学校停电停水等诸多原因而导致冲刺完毕时间的推迟. 第一阶段总体是做到了运算的功能,只是一些基本的功能实现,但能保证的容错性能较高. 1.在普遍的四则运算中都能见到 ...

  5. 云平台项目--学习经验--回调函数中call和apply

    Js中可以通过call和apply来代替另一个对象调用一个方法,将一个函数对象上下文从初始上下文改变为thisObj指定的新对象.简而言之,改变函数执行的上下文,而call和apply的基本区别在于他 ...

  6. 读C#程序最小公倍数答案就是:2123581660200

    阅读下面程序,请回答如下问题: 问题1:这个程序要找的是符合什么条件的数? 问题2:这样的数存在么?符合这一条件的最小的数是什么? 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间 ...

  7. mysql 好用的sql语句

    1.删除某个库里面全部的表 ,先在mysql库中执行:  SELECT CONCAT('drop table ',table_name,';') FROM information_schema.`TA ...

  8. c# 行转列

    将下面表(1)格式的数据转换为表(2)格式的数据.很明显,这是一个行转列的要求,本想在数据库中行转列,因为在数据库中行转列是比较简单的,方法可以参考本站SQLServer中(行列转换)行转列及列转行且 ...

  9. BZOJ5418 NOI2018屠龙勇士(excrt)

    显然multiset求出每次用哪把剑.注意到除了p=1的情况,其他数据都保证了ai<pi,于是先特判一下p=1.比较坑的是还可能存在ai=pi,稍微考虑一下. 剩下的部分即解bix≡ai(mod ...

  10. 题解 P2580 【于是他错误的点名开始了】

    这个题的题解区就没一简单一点的指针题解?(大概是瞎了) So,这篇题解是给那些想用指针而害怕的同学食用的qwq 记得有一篇题解有个dalao作者放了几个静态模拟的trie树结果最后放了个动态的跑路了. ...