【二叉搜索树】

随机生成时平均深度为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. 洛谷-P3809-后缀排序(后缀数组)

    看了求后缀数组的倍增法之后很快就理解了,但是自己写的倍增法用map排序还是超时了.然后看了两天别人写的模板,题目是通过了,但感觉代码还是半懂半背的.以后多熟悉熟悉吧: 后缀数组 #include &q ...

  2. HihoCode-1675-稀疏矩阵乘积

    上来先一顿暴力,结果70分就超时了. 然后意识到稀疏矩阵,有很多0,如果c[i][j] != 0,那么一定存在至少一个k满足a[i][k] != 0 && b[k][j] != 0; ...

  3. Java JDBC调用inout类型参数的存储过程

    存储过程参数类型:in.out.inout,in:输入类型,out:输出类型,inout:既可输入,也可以输出. 一.JDBC调用inout类型参数的存储过程,并且获得返回值 Class.forNam ...

  4. python基础之文件操作1

    文件操作:os.mknod("test.txt")        创建空文件fp = open("test.txt",w)     直接打开一个文件,如果文件不 ...

  5. numpy的索引

    import numpy as np A =np.arange(3,15).reshape(3,4) print(A) #第一行 print(A[2]) #返回元素 print(A[1][2]) pr ...

  6. Excel技巧:如何绘制一份优秀的甘特图(项目管理)

    作者:秦路,天善智能特约专家.资深数据分析师,数据化运营专家.擅长结合运营和数据,建立数据化运营体系. 个人公众号:秦路(微信ID:tracykanc) 今天我给大家分享的内容是如何利用Excel绘制 ...

  7. cssy元素居中的方法有哪些?

    css的元素居中 各位小伙伴们在努力写网页的时候有没有遇到过这样的一个问题呢? 在写的时候发现他不居中,可是要分分钟逼死强迫症的啊! 别急,我来啦 哈哈哈 今天就带来三种css的元素居中的方法 第一种 ...

  8. tfgan折腾笔记(一):核心功能简要概述

    tfgan是什么? tfgan是tensorflow团队开发出的一个专门用于训练各种GAN的轻量级库,它是基于tensorflow开发的,所以兼容于tensorflow.在tensorflow1.x版 ...

  9. 前端每日实战:102# 视频演示如何用纯 CSS 创作一个小和尚

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/oMmYXp 可交互视频 此视频是可 ...

  10. 利用pandas选取某个属性符合指定条件的所有行

    最近遇到利用pandas选取指定行的需求,经常忘记,在此做下记录 选取某个属性等于特定值的所有行记录 df[(df[‘column_name’] == target_value)] 注:等于用 '== ...