您的位置:首页 > 理论基础 > 数据结构算法

(数据结构笔记)二叉查找树的实现

2015-09-26 22:13 513 查看
二叉查找树是一种比较基础的数据结构,其优化后可以变成AVL树,红黑树,treap树等等较为高效的树。使二叉树成为二叉查找树的方法是:对于树中的每个节点,使其左子树中的所有项均小于该节点,其右子树中的所有项均大于该节点。

二叉查找树可以利用递归较为简单地实现,其具体的定义和算法可以很方便地查询得到,故不再赘述。

二叉查找树应具有的公有成员函数:

1.contains(x):如果树中有值为x的节点,则返回true。

2.empty():如果树为空,返回true。

3.insert(x):在树中的恰当位置插入x节点,如果x已存在则什么也不做。

4.remove(x):删除树中x节点,如果x不存在则什么也不做。

5.findmin():返回树中的最小值。

6.findmax():返回树中的最大值。

7.make_empty():清空树。

8.print_tree():递增地打印树中节点(中序历遍)。

二叉查找树的实现框架:

<span style="font-size:14px;">template<typename T>
class BinarySearchTree{
public:
BinarySearchTree() = default;
BinarySearchTree(const BinarySearchTree&);
~BinarySearchTree();
const BinarySearchTree& operator=(const BinarySearchTree &);

bool contains(const T&);
bool empty();
const T& findmin();
const T& findmax();
void insert(const T&);
void remove(const T&);
void make_empty();
void print_tree();
private:
struct BinaryNode { //接口类
T element;
BinaryNode *left;
BinaryNode *right;
BinaryNode(const T& elem, BinaryNode * l, BinaryNode * r) :
element(elem), left(l), right(r) {}
};
BinaryNode *root;
bool contains(const T&,BinaryNode*);
BinaryNode * findmin(BinaryNode*);
BinaryNode * findmax(BinaryNode*);
void insert(const T&, BinaryNode*&);
void remove(const T&, BinaryNode*&);
void make_empty(BinaryNode*&);
void print_tree(BinaryNode*);
BinaryNode * clone(BinaryNode*); //递归实现拷贝
};</span>


contains、empty函数的实现
这两个函数较为简单,contains就是简单的调用递归查找。

<span style="font-size:14px;">template<typename T>
bool BinarySearchTree<T>::contains(const T& elem) {
return contains(elem, root);
}

template<typename T>
bool BinarySearchTree<T>::contains(const T& elem, BinaryNode * bin) {
if (bin == nullptr)
return false;
if (bin->element < elem)
return contains(elem, bin->right);
else if (bin->element >elem)
return contains(elem, bin->left);
else
return true;
}

template<typename T>
bool BinarySearchTree<T>::empty() {
if (root == nullptr)
return true;
return false;
}</span>

findmin、findmax函数以及[b]print_tree函数
的实现[/b]
前两个函数虽然可以简单地利用递归查找,但是我们应该尽量避免使用尾递归,所以使用while语句代替递归调用。

另外就是注意处理空树的情况。

<span style="font-size:14px;">template<typename T>
const T & BinarySearchTree<T>::findmin() {
return findmin(root)->element;
}

template<typename T> typename
BinarySearchTree<T>::BinaryNode *
BinarySearchTree<T>::findmin(BinaryNode *bin) {
if (bin == nullptr)
return nullptr;
while (bin->left != nullptr)
bin = bin->left;
return bin;
}

template<typename T>
const T & BinarySearchTree<T>::findmax() {
return findmax(root)->element;
}
template<typename T> typename
BinarySearchTree<T>::BinaryNode *
BinarySearchTree<T>::findmax(BinaryNode* bin) {
if (bin == nullptr)
return nullptr;
while (bin->right != nullptr)
bin = bin->right;
return bin;
}template<typename T>
void BinarySearchTree<T>::print_tree() {
<span style="white-space:pre"> </span>print_tree(root);
}

template<typename T>
void BinarySearchTree<T>::print_tree(BinaryNode *bin) {
<span style="white-space:pre"> </span>if (bin != nullptr) {
<span style="white-space:pre"> </span>print_tree(bin->left);
<span style="white-space:pre"> </span>std::cout << bin->element<<" ";
<span style="white-space:pre"> </span>print_tree(bin->right);
<span style="white-space:pre"> </span>}
}</span>

insert、remove以及make_empty函数的实现

insert与contains的思路比较相似。

remove分两种情况:一是处理具有两个子树的节点,有两种方式,利用其右子树的最小节点(或是利用其左子树的最大节点)代替该节点并递归地删除那个节点。二是单子树或是无子树的节点,可以将子树绕过该节点链接到父节点,然后删除该节点。

特别要注意的是,因为这三个函数对树进行了插入或删除的操作,所以参数要使用引用类型,否则会出现错误。

<span style="font-size:14px;">template<typename T>
void BinarySearchTree<T>::insert(const T& elem) {
insert(elem,root);
}

template<typename T>
void BinarySearchTree<T>::insert(const T& elem, BinaryNode* &bin) {
if (bin == nullptr) {
bin = new BinaryNode(elem, nullptr, nullptr);
}
else if (bin->element < elem) {
insert(elem, bin->right);
}
else if (bin->element > elem) {
insert(elem, bin->left);
}
//如果找到elem,什么也不做
}

template<typename T>
void BinarySearchTree<T>::remove(const T& elem) {
remove(elem, root);
}

template<typename T>
void BinarySearchTree<T>::remove(const T& elem,BinaryNode* &bin) {
if (bin == nullptr) //找不到elem,什么也不做
return;
if (elem > bin->element)
remove(elem, bin->right);
else if (elem < bin->element)
remove(elem, bin->left);
else if (bin->left != nullptr && bin->right != nullptr) { //删除拥有两个子树的节点
auto t = findmin(bin->right);
bin->element = t->element;
remove(t->element, t);
}
else { //删除树叶或单子树节点
auto old = bin;
bin = (bin->left != nullptr) ? bin->left : bin->right;
delete old;
}
}

template<typename T>
void BinarySearchTree<T>::make_empty() {
make_empty(root);
}

template<typename T>
void BinarySearchTree<T>::make_empty(BinaryNode* &bin) {
if (bin != nullptr) {
make_empty(bin->left);
make_empty(bin->right);
delete bin;
bin = nullptr;
}
}</span>
最后是拷贝构造函数、析构函数和拷贝赋值运算符
使用了clone工具函数来实现递归操作。

<span style="font-size:14px;">template<typename T> typename
BinarySearchTree<T>::
BinaryNode * BinarySearchTree<T>::clone(BinaryNode* bin) {
if (bin == nullptr)
return nullptr;
return new BinaryNode(bin->el
4000
ement, clone(bin->left), clone(bin->right));
}

template<typename T>
BinarySearchTree<T>::
BinarySearchTree(const BinarySearchTree& bin) {
root=clone(bin.root); //同类或友元中可访问private成员
}

template<typename T>
inline BinarySearchTree<T>::~BinarySearchTree() {
make_empty();
}
template<typename T> typename
const BinarySearchTree<T>& BinarySearchTree<T>::operator=(const BinarySearchTree & bin) {
if (*this != bin) {
make_empty();
root = clone(bin.root);
}
return *this;
}</span>

新手一枚,望各位大大多提意见!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: