一个简单的二叉搜索树(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 - 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树. 一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是二叉搜索树. ...
随机推荐
- Unity3D — — UGUI之简易背包
Uinity版本:2017.3 最近在学Siki老师的<黑暗之光RPG>教程,由于教程内用的是NGUI实现,而笔者本人用的是UGUI,所以在这里稍微写一下自己的实现思路(大致上和NGUI一 ...
- 自己动手写Impala UDF
本文由 网易云发布. 概述 出于对可扩展性和性能的考虑,UDF已变成大数据生态圈查询引擎的必备功能之一,无论是Calcite.Hive.Impala都对其进行支持,但是UDF的支持有利也有弊,好处在 ...
- 20135337朱荟潼 Linux第八周学习总结——进程的切换和系统的一般执行过程
第八周 进程的切换和系统的一般执行过程 一.进程切换关键代码switch_to 1.不同类型进程有不同调度需求--两种分类 2.调度策略--规则 Linux中进程优先级是动态的,周期性调整. 3.时机 ...
- GITHUB使用及入门总结
这是我第一次应用git,以下仅供git的初学者参考. github是一个基于git的代码托管平台,付费用户可以建私人仓库,我们一般的免费用户只能使用公共仓库,也就是代码要公开.这对于一般人来说 ...
- ajax异步导致js方法顺序执行不了
js两个方法调用的顺序,有时候是这样的 f1(); f2(); 本来是先执行f1的,但是如果f1里面进行ajax异步 async:true,那么可能会先执行f2,如果想要顺序执行,那么就把异步设 ...
- tp5+layui 实现上传大文件
前言: 之前所写的文件上传类通常进行考虑的是文件的类型.大小是否符合要求条件.当上传大文件时就要考虑到php的配置和服务器的配置问题.之前简单的觉得只要将php.ini中的表单上传的 大小,单脚本执行 ...
- 11th 回顾5个问题
当初提出的5个问题: 1.书中说很多非常成功的软件都是赢在用户体验,后面的第12章也专门提到了用户体验,说软件开发时可以使用5W1H的方法来判断用户的体验,而需求分析需要获取用户需求,进行用户调研,那 ...
- ELK之消息队列选择redis_kafka_rabbitmq
前言描述 生产初级,Service服务较少,访问量较少,随着业务量的不断增加,日志量成倍增长,然后就遇到了消息队列redis被充爆,不能满足应用的情况.针对此情况,我们来分析下可用的消息多列. 官方推 ...
- Codeforces ECR50 div2题解
A:签到 #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> # ...
- ef 更新数据库
//一:数据库不存在时重新创建数据库 Database.SetInitializer<testContext>(new CreateDatabaseIfNotExists<testC ...