【二叉搜索树】

随机生成时平均深度为logN,平均插入、删除和搜索时间都是O(logN)。

可能存在的问题是数据不均衡,使树单边生长,极端情况下变成类似链表,最坏插入、删除、搜索时间O(N)

写这个例程也花了些时间,例程主要包括查找、插入、删除、遍历、清空几个内容。

同时避免之前写链表到了半途再修改,拷贝构造、拷贝赋值、析构也写成了深拷贝的模式。

光这两份代码在一起还无法运行,因为层序遍历那一块用了之前写的队列例程。

测试代码:

 #include <iostream>
#include "bstree.h"
using bstree::BSTree;
int main(void)
{
//测试插入
BSTree<int> number;
cout << "additem" << endl;
number.additem();number.additem();number.additem();number.additem();
number.additem();number.additem();number.additem();number.additem();
number.additem();number.additem();number.additem();number.additem();
number.additem();number.additem();number.additem();number.additem();
number.additem(); number.additem(); number.additem(); number.additem();
//打印
number.printpre();
cout << "--preorder"<<endl;
number.printin();
cout << "--inorder" << endl;
number.printpost();
cout << "--postorder" << endl;
number.printseq();
cout << "--seqorder" << endl; //测试拷贝构造函数
cout << "\ncopy constructor" << endl;
BSTree<int> number2(number);
number2.printpre();
cout << "--preorder" << endl;
number2.printin();
cout << "--inorder" << endl; //测试插入重复元素
cout << "\ncollision" << endl;
number.additem(); //删除测试
//删除节点没有右子树
cout << "\nremove number 3: iter->right = nullptr" << endl;
number.remove();
number.printpre();
cout << "--preorder" << endl;
number.printin();
cout << "--inorder" << endl; //删除测试
//删除节点的右子树没有左子树
cout << "\nremove number 15: iter->right->left = nullptr" << endl;
number.remove();
number.printpre();
cout << "--preorder" << endl;
number.printin();
cout << "--inorder" << endl; //删除测试
//删除节点的右子树有左子树
cout << "\nremove number 10: iter->right->left != nullptr" << endl;
number.remove();
number.printpre();
cout << "--preorder" << endl;
number.printin();
cout << "--inorder" << endl; //删除测试
//删除根
cout << "\nremove number 8: iter == root" << endl;
number.remove();
number.printpre();
cout << "--preorder" << endl;
number.printin();
cout << "--inorder" << endl; //删除测试
//删除不存在的元素
cout << "\nremove number not existed" << endl;
number.remove(); //查找最值
cout << "\nmax = " << number.findmax()->data << endl;
cout << "min = " << number.findmin()->data << endl; //清空树,并测试在空树下删除
cout << "\nclear" << endl;
number.clear();
number.remove(); system("pause");
}

实现代码:

 #ifndef BINARYSEARCHTREE
#define BINARYSEARCHTREE
#include <iostream>
#include "queue.h"
using queue::Queue;
using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::flush;
namespace bstree
{
template <typename T> struct Node
{
Node<T>() : left(nullptr), right(nullptr){}
Node<T>(const T &item) : data(item), left(nullptr), right(nullptr){}
T data;
Node<T>* left;
Node<T>* right;
};
template <typename T> class BSTree
{
//构造函数
public:
BSTree() :nodes(), root(nullptr){}
BSTree(const BSTree& another)
{
root = nullptr;
nodes = ;
void(BSTree::*pf)(const Node<T>*);
pf = &BSTree::additem_from_another;
traverse_seq(another.root, pf);
}
~BSTree(){ clear(); }
BSTree& operator=(const BSTree& another)
{
if (&another != this)
{
clear();
void(BSTree::*pf)(const Node<T>*);
pf = &BSTree::additem_from_another;
traverse_seq(another.root, pf);
}
}
//接口
public:
//元素个数
unsigned int size()const{ return nodes; }
//是否空
bool empty()const{ return noodes == ; }
//获得根指针
Node<T>* getroot()const{ return root; }
//各种遍历
//前中后序使用辅助函数递归完成,层序遍历需使用队列结构
void printpre()const{ traverse(root, printnode, ); }
void printin()const{ traverse(root, printnode, ); }
void printpost()const{ traverse(root, printnode, ); }
void printseq()const{ traverse_seq(root, printnode); }
//#查找元素
Node<T>* find(const T &item)const;
//#查找最值
Node<T>* findmax()const;
Node<T>* findmin()const;
//#增加元素
bool additem(const T &item);
//#删除元素
bool remove(const T &item);
//清空树并将数据初始化
void clear(){ release(root); root = nullptr; nodes = ; } //辅助函数
private:
void release(Node<T>* iter);
Node<T>* find_prev(const T &item)const;
Node<T>* remove_node(Node<T>* iter);
void traverse(const Node<T>* iter, void(*fp)(const Node<T>*), int mode)const;
void traverse_seq(const Node<T>* iter, void(BSTree::*pf)(const Node<T>*));
void traverse_seq(const Node<T>* iter, void(*pf)(const Node<T>*))const;
void additem_from_another(const Node<T>* iter){ additem(iter->data); }
//数据
private:
Node<T>* root;
unsigned int nodes;
}; //辅助函数,打印节点元素
template <typename T> static void printnode(const Node<T>* iter){ cout << iter->data << " " << flush; }
//辅助函数
//查找元素的父树。如果树为空或元素为根,返回空指针;如果元素不存在,返回插入该元素时的父树
template <typename T> Node<T>* BSTree<T>::find_prev(const T &item)const
{
Node<T>* prev = nullptr;
Node<T>* curr = root;
while (curr != nullptr)
{
if (item < curr->data)
{
prev = curr;
curr = curr->left;
}
else if (item > curr->data)
{
prev = curr;
curr = curr->right;
}
else
break;
}
return prev;
}
//查找元素,如果元素不存在则返回空指针
template <typename T> Node<T>* BSTree<T>::find(const T &item)const
{
Node<T>* iter = find_prev(item);
if (iter == nullptr)
return root;
if (item < iter->data)
return iter->left;
else
return iter->right;
}
//查找最值
template <typename T> Node<T>* BSTree<T>::findmax()const
{
if (nodes == )
return nullptr;
Node<T>* iter = root;
while (iter->right != nullptr)
iter = iter->right;
return iter;
}
template <typename T> Node<T>* BSTree<T>::findmin()const
{
if (nodes == )
return nullptr;
Node<T>* iter = root;
while (iter->left != nullptr)
iter = iter->left;
return iter;
}
//插入元素,元素重复则报错
template <typename T> bool BSTree<T>::additem(const T &item)
{
Node<T>* prev = nullptr;
Node<T>* curr = root;
//找到待插入元素应该插入的位置
while (curr != nullptr)
{
if (item < curr->data)
{
prev = curr;
curr = curr->left;
}
else if (item > curr->data)
{
prev = curr;
curr = curr->right;
}
//元素相等导致冲突则报错
else
{
cout << "Elements collision!" << endl;
return false;
}
}
Node<T>* pnew = new Node<T>(item);
if (prev == nullptr)
root = pnew;
else if (item < prev->data)
prev->left = pnew;
else
prev->right = pnew;
++nodes;
return true; }
//删除元素
template <typename T> bool BSTree<T>::remove(const T &item)
{
if (nodes == )
{
cout << "Tree is empty!" << endl;
return false;
}
//函数主体执行查找操作
//查找到相应删除点后,交给remove_node()处理
Node<T>* iter = find_prev(item);
if (iter == nullptr)
{
if (root->data != item)
{
cout << "Not Found!" << endl;
return false;
}
root = remove_node(root);
}
else if (item < iter->data)
{
if (iter->left == nullptr)
{
cout << " Not Found!" << endl;
return false;
}
iter->left = remove_node(iter->left);
}
else
{
if (iter->right == nullptr)
{
cout << "Not Found!" << endl;
return false;
}
iter->right = remove_node(iter->right);
}
--nodes;
return true;
}
//辅助函数,删除具体节点
template <typename T> Node<T>* BSTree<T>::remove_node(Node<T>* iter)
{
//用即将被删除节点的右子树的最左边的子节点替代即将被删除的位置
//情况一,删除节点无右子树
if (iter->right == nullptr)
{
Node<T>* save = iter->left;
delete iter;
return save;
}
//情况二,删除节点的右子书无左子树
else if (iter->right->left == nullptr)
{
Node<T>* save = iter->right;
save->left = iter->left;
delete iter;
return save;
}
//情况三,删除节点的右子树有左子树
else
{
Node<T>* prev = iter->right;
Node<T>* curr = iter->right->left;
while (curr->left != nullptr)
{
prev = curr;
curr = curr->left;
}
prev->left = curr->right;
curr->left = iter->left;
curr->right = iter->right;
delete iter;
return curr;
}
}
//辅助函数,前中后遍历执行模式
template <typename T> void BSTree<T>::traverse(const Node<T>* iter, void(*fp)(const Node<T>*), int mode)const
{
if (iter == nullptr)
return;
if (mode == )
{
(*fp)(iter);
traverse(iter->left, fp, );
traverse(iter->right, fp, );
}
else if (mode == )
{
traverse(iter->left, fp, );
(*fp)(iter);
traverse(iter->right, fp, );
}
else if (mode == )
{
traverse(iter->left, fp, );
traverse(iter->right, fp, );
(*fp)(iter);
}
return;
}
//辅助函数,层序遍历,需队列辅助
//重载两个版本,一个用于遍历树不需改变树元素,调用非成员函数printnode。则标记const,函数参数为(*pf)
//另一个用于拷贝构造与拷贝赋值需改变树元素,调用成员函数。则不标记const,显示声明调用成员函数(BSTree::*pf)
template <typename T> void BSTree<T>::traverse_seq(const Node<T>* iter, void(BSTree::*pf)(const Node<T>*))
{
if (iter != nullptr)
{
Queue<const decltype(iter)> node_address;
node_address.enqueue(iter);
while (!node_address.empty())
{
const Node<T>* temp = node_address.getfirst();
node_address.dequeue();
if (temp->left != nullptr)
node_address.enqueue(temp->left);
if (temp->right != nullptr)
node_address.enqueue(temp->right);
(this->*pf)(temp);
}
}
}
template <typename T> void BSTree<T>::traverse_seq(const Node<T>* iter, void(*pf)(const Node<T>*))const
{
if (iter != nullptr)
{
Queue<const decltype(iter)> node_address;
node_address.enqueue(iter);
while (!node_address.empty())
{
const Node<T>* temp = node_address.getfirst();
node_address.dequeue();
if (temp->left != nullptr)
node_address.enqueue(temp->left);
if (temp->right != nullptr)
node_address.enqueue(temp->right);
(*pf)(temp);
}
}
}
//辅助函数,释放所有节点清空内存
template <typename T> void BSTree<T>::release(Node<T>* iter)
{
if (iter == nullptr)
return;
release(iter->left);
release(iter->right);
delete(iter);
}
}
#endif

【Weiss】【第04章】二叉搜索树例程的更多相关文章

  1. 算法进阶面试题04——平衡二叉搜索树、AVL/红黑/SB树、删除和调整平衡的方法、输出大楼轮廓、累加和等于num的最长数组、滴滴Xor

    接着第三课的内容和讲了第四课的部分内容 1.介绍二叉搜索树 在二叉树上,何为一个节点的后继节点? 何为搜索二叉树? 如何实现搜索二叉树的查找?插入?删除? 二叉树的概念上衍生出的. 任何一个节点,左比 ...

  2. 算法导论(Introduction to Algorithms )— 第十二章 二叉搜索树— 12.1 什么是二叉搜索树

    搜索树数据结构支持很多动态集合操作,如search(查找).minmum(最小元素).maxmum(最大元素).predecessor(前驱).successor(后继).insert(插入).del ...

  3. 算法导论 第十二章 二叉搜索树(python)

    上图: 这是二叉搜索树(也有说是查找树的)基本结构:如果y是x的左子树中的一个结点,那么y.key <= x.key(如a图中的6根结点大于它左子树的每一个结点 6 >= {2,5,5}) ...

  4. 第七章 二叉搜索树(d4)AVL树:(3+4)-重构

  5. 第七章 二叉搜索树 (d3)AVL树:删除

  6. 第七章 二叉搜索树(b3)BST:删除

  7. 第七章 二叉搜索树 (d2)AVL树:插入

  8. 第七章 二叉搜索树 (d1)AVL树:重平衡

  9. 第七章 二叉搜索树(c)平衡与等价

随机推荐

  1. zabbix配置文件详解--服务(server)端、客户(agent)端、代理(proxy)端

    在zabbix服务(server)端.客户(agent)端.代理(proxy)端分别对应着一个配置文件,即:zabbix_server.conf,zabbix_agentd.conf,zabbix_p ...

  2. jenkins使用(2)-配置项目代码的3种方式

    1.通过cmd命令直接进入项目代码的文件夹运行,注意路径中不要有中文 2.代码放到工作区:从本地复制项目代码到工作区目录下 代码结构的优化 3.代码连接git或svn,实时更新代码 svn检出 然后上 ...

  3. in与exist , not in与not exist 的区别

    in和exists     in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询.一直以来认为exists比in效率高的说法是不准确的.     ...

  4. idea 内存溢出解决方法

    在Run/Debug configuration 的 vm options里面输入 -server -XX:PermSize=128M -XX:MaxPermSize=256m 具体如下图:

  5. Spring MVC 增加静态资源配置mvc:resources跳转不了链接

    在使用mvc:resources 要配合 <mvc:annotation-driven/> 一起

  6. js对象或数组深复制

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. elasicsearch数据自动清理脚本

    elasticsearch随着保存的数据越来越多,磁盘占用越来越大,有必要进行定期自动清理. 直接上脚本 cat es-index-clear.sh #/bin/bash #查看索引信息 #curl ...

  8. 为何银行愿为收购supercell做无权追索融资?

    无追索权融资又称纯粹的项目融资,是指贷款人对项目主办人没有任何追索权的项目融资.简单来说,这是一种项目失败,也无法追尝的承诺,一般发生在石油.天然气.煤炭.铜.铝等矿产资源开发等相对较为保值的项目融资 ...

  9. Grafana+Prometheus监控mysql性能

    #cmd /usr/local 今天讲一下如何监控服务器中的mysql数据库的性能 一.数据库操作 1.mysql启动 #service mysqld start #启动数据库 #service my ...

  10. python 保存两位小数

    一.代码 import decimal decimal.getcontext().rounding = decimal.ROUND_HALF_UP def index(number): n = str ...