参考: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. cocos2dx渲染架构

    2dx的时代UI树便利和渲染是没有分开的,遍历UI树的时候就渲染.3dx版本为了分离了ui树的遍历和渲染,先遍历生成渲染命令发到渲染队列,之后遍历渲染命令队列开始渲染.这样做的好处是渲染命令可以重用, ...

  2. Git 命令简单罗列

    源教程出自 廖雪峰的官方网站 https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 整 ...

  3. 《Linux内核分析》 第二节 操作系统是如何工作的

    Linux内核分析 第二周 操作系统是如何工作的 张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/UST ...

  4. Day Five

    站立式会议 站立式会议内容总结 442 今天:编写具体计划的界面 遇到的问题:相对布局.绝对布局理解不够深刻 明天:完成设定计划时间的功能 331 今天:添加书籍/计划按钮,添加书籍时有一个文件选择 ...

  5. ElasticSearch 2 (12) - Shard数调优(ElasticSearch性能)

    ElasticSearch 2 (12) - Shard数调优(ElasticSearch性能) 摘要 当创建一个索引的时候,我们经常会面对一个问题:要为索引分配多少个shard?多少个replica ...

  6. java 多维数据定义

            //一维数组定义与输出class  less02{ public static void main(String[] args)  {  int stu[]=new int[]{1,2 ...

  7. [问题排查]记录一次两个dubbo提供者同时在线,代码不一致导致问题的排查记录

    1. 需求 有一个需求job定时5秒一次,job[消费者]调用dsc[提供者]提供的dubbo完成:先清空redis的某个key,然后再往redis中放入新的数据,这是一个定时任务,需要每隔5秒执行一 ...

  8. 制作U盘启动盘并重装系统

    进入网站 http://www.msdn.hk/6/209/ 在列表中选择自己需要的系统,比如win7_64,则可以选择下图系统:Windows 7 Ultimate with Service Pac ...

  9. Windows 64位环境的Java 服务配置

    有个任务,需要远程起调Windows64服务器下的程序,那么需要在Windows服务器中注入一个deamon服务,都知道Linux环境做成后台服务非常简单,nohup &很快能解决问题,但wi ...

  10. Struts2 分割字符串标签s:generator

    有些时候会从后台返回一个字符串,可以通过Strut2的标签s:generator进行分割. generator标签,该标签可以将指定字符串按指定分隔符分割成多个字串.生成的多个字串可以用iterato ...