(折半查找树)BinSearchTree模板类

来源:互联网 发布:思考软件 创新设计 编辑:程序博客网 时间:2024/06/04 18:06

二叉树递归定义:

二叉树 t 要么为空,要么由一项(称作根项)和两个不相交的二叉树 (称作 t 的左子树和右子树)组成。

1)植物学术语:
根——根项(50); 
树枝——从根到子树的线; 
树叶——相关左子树和右子树均为空的项(15、28、36、59、68)。
2)家族术语:
父亲——(25 是 15 的父亲); 
子女——(30 是 25 的右子女);
兄弟——(30 是 15 的兄弟)。
3)二叉树的高度比左子树和右子树的最大高度大 1;
单个项的二叉树的高度是 0;
空树的高度定义为 -1。

遍历二叉树:

1.中序遍历:左--根--右。 假设 t 是一个二叉树,算法如下
inOrder(t){if (t 非空){inOrder(leftTree(t));访问 t 的根项;inOrder(rightTree(t));}}// 中序遍历
图1中的二叉树采用中序遍历的结果:
15  25  28  30  32  36  37  50  55  59  61  68  75
2.后序遍历: 左--右--根。 在二叉树 t 上的算法如下
postOrder(t){if (t 非空){postOrder(leftTree(t));postOrder(rightTree(t));访问 t 的根项;}}// 后序遍历
图1中的二叉树采用后序遍历的结果:
15  28  36  32  30  25  37  59  55  68  61  75  50
3.前序遍历: 根--左--右。在二叉树 t 上的算法如下
preOrder(t){if (t 非空){访问 t 的根项;preOrder(leftTree(t));preOrder(rightTree(t));}}// 前序遍历
图1中的二叉树采用前序遍历的结果:
50  37  25  15  30  28  32  36  75  61  55  59  68
使用前序遍历的二叉树搜索称作 “深度优先搜索”。因为它总是先从左边尽可能地深入,然后再搜索右边。
4.广度优先遍历: 逐层遍历。
在一个非空二叉树 t 中执行广度优先遍历,首先访问根项;
接着自左至右访问根的子女;然后自左至右访问根的孙子; 依次类推。
图1中的二叉树采用广度优先遍历的结果:
50  37  75  25  61  15  30  55  68  28  32  59  36

折半查找树递归定义:

折半查找树 t 是一个二叉树,它满足 t 要么为空,要么为
1)leftTree(t) 中的每一项都小于等于 t 的根项;
2)rightTree(t) 中的每一项都大于等于 t 的根项;
3)leftTree(t) 和 rightTree(t) 都是折半查找树。
实际上,图1中的二叉树就是一个折半查找树,使用中序遍历可以按照增序访问折半查找树中的项。
折半查找树在平均情况下的插入、删除和查找都只需要对数时间(但是在最坏情况下需要线性时间)花费。这个性能要远胜于数组、向量或列表结构的线性时间花费。
PS:树中是允许存在重复项的。
关联容器:
在一个关联容器中,项通过和其他项的比较确定它在容器中的位置。折半查找树是关联容器的一个范例。

BinSearchTree模板类:

BinSearchTree类是折半查找类树,其中缺少顺序容器类的支柱方法: push_back()、pop_back()、push_front() 和 pop_front()。随便插入操作是不合法的,必须根据顺序将项插入到属于它的位置上。
BinSearchTree类的声明:
#ifndef _BINSEARCH_TREE_#define _BINSEARCH_TREE_#include <iostream>using namespace std;/*---------------------(关联容器)折半查找树---------------------*/template <class T>class BinSearchTree{typedef struct tree_node{T item;// 树中的项tree_node *parent,// 指向父项  *left,// 指向左子女项  *right;// 指向右子女项bool isHeader;// 指示这个节点是不是头节点}* Link;Link header;// 头节点unsigned node_count;// 树中项的数目)void insertLeaf(const T& item, Link parent, Link& child);// (insert()调用)void destroy(Link link); // (删除以 link 为树根的子树-- ~BinSearchTree()调用)void prune(Link& link);// (erase()调用)void deleteLink(Link& link);// (erase()调用)public:class iterator{protected:Link link;// 指向节点public:iterator() {}iterator(Link new_link) : link(new_link) {}T& operator*() {return this->link->item;}bool operator!=(iterator& itr) {return bool(link->item != itr.link->item);}bool operator==(iterator& itr) {return bool(link->item == itr.link->item);}Link& field() {return link;}iterator& operator++(int);};BinSearchTree();// 创建树,其中项为空~BinSearchTree();// 释放为这个树分配的空间unsigned size() const {return node_count;}// 返回树中项的数目// 在树中寻找 item。成功:返回指向该 item 的迭代器; 失败:返回 itr = end()// averageTime(n) 是 O(logn), worstTime(n) 是 O(n).iterator find(const T& item) const;// 将 item 插入到树中。返回位于 item 上的迭代器// averageTime(n) 是 O(logn), worstTime(n) 是 O(n).iterator insert(const T& item);// 在树中删除 itr 指向的节点中的项// averageTime(n) 是常数, worstTime(n) 是 O(n).void erase(iterator itr);iterator begin() const {return header->left;}// 树非空,返回树中最小项上的迭代器iterator end() const {return header;}// 树非空,返回的迭代器的前一个位置就是最大项};
BinSearchTree类的实现:
1).创建树
// 创建树,其中项为空template <class T>BinSearchTree<T>::BinSearchTree(){// header的tree_node的item字段始终保持未定义状态header = new tree_node;// 头节点header->parent = NULL;header->left = header;header->right = header;header->isHeader = true;node_count = 0;}

1)在头节点header中,left 和 right 字段分别指向树中最小和最大的项所在的节点;
2)begin()可以方便设计成 返回 header->left;对于 end(),如果树中最大的项(header->right)所在节点的下一节点为头节点,end() 可以设计成 返回 header。
2).insert操作
(迭代版本)使用一个指向根的 child 在树中下降并保存调整过的节点指针的父亲。当插入项成为树的最左边或最右边时要特别小心。
// 将 item 插入到树中。返回位于 item 上的迭代器// averageTime(n) 是 O(logn), worstTime(n) 是 O(n).// (返回值前面必须使用 typename 告诉编译器BinSearchTree<T>::iterator是一种类型而不是类的成员变量) template <class T> typenameBinSearchTree<T>::iterator BinSearchTree<T>::insert(const T& item){if (header->parent == NULL){insertLeaf(item, header, header->parent);header->left = header->parent;header->right = header->parent;return header->parent;// 自动将 Link类型 转换成 iterator类型}// 树为空,在树的根部插入else{Link parent = header,child = header->parent;while (child != NULL){parent = child;if (item < child->item)child = child->left;elsechild = child->right;}if (item < parent->item){insertLeaf(item, parent, parent->left);if (header->left == parent)header->left = parent->left;return parent->left;}// 在父亲的左边插入else{insertLeaf(item, parent, parent->right);if (header->right == parent)header->right = parent->right;return parent->right;}// 在父亲的右边插入}// 树非空}// (insertLeaf将 item 作为树叶插入,调整链接并令 node_count 加 1)template <class T>void BinSearchTree<T>::insertLeaf(const T& item, Link parent, Link& child){child = new tree_node;child->item = item;child->parent = parent;child->left = NULL;child->right = NULL;child->isHeader = false;node_count++;}
3.)find操作
(迭代版本)从一个指向根的 chid 开始在树中下降,根据 child->item 和所搜索项的比较来决定用 child 的左子女还是右子女替换 child。
// 在树中寻找项 item。成功:返回指向该 item 的迭代器; 失败:返回 itr = end()// averageTime(n) 是 O(logn), worstTime(n) 是 O(n).template <class T> typenameBinSearchTree<T>::iterator BinSearchTree<T>::find(const T& item) const{Link parent = header,child = header->parent;while (child != NULL){if (!(child->item < item)){parent = child;child = child->left;}elsechild = child->right;}if (parent == header || item < parent->item)return end();elsereturn parent;}
4).erase操作
(迭代版本)参数为 iterator itr,访问指向 itr 节点的 itr 父节点中的字段。如果 itr 位于根节点,那么这就是 parent 字段,否则就是 itr 的父亲的 left 或 right 的字段。然后改变该指针字段完成对 itr 节点的删除。(itr 是一个对象,不能访问 private 和 protected 内容,需要 通过 itr.field() 访问 link字段)
// 在树中删除 itr 指向的节点中的项// averageTime(n) 是常数, worstTime(n) 是 O(n).template <class T>void BinSearchTree<T>::erase(iterator itr){if (itr.field()->parent->parent == itr.field())deleteLink(itr.field()->parent->parent);else if (itr.field()->parent->left == itr.field())deleteLink(itr.field()->parent->left);elsedeleteLink(itr.field()->parent->right);}template <class T>void BinSearchTree<T>::prune(Link& link){Link linkcopy = link,newlink;node_count--;if ((link->left == NULL) && (link->right == NULL)){if (link == header->left)header->left = link->parent;if (link == header->right)header->right = link->parent;link = NULL;}// link 的项是树叶else if (link->left == NULL){link = link->right;link->parent = linkcopy->parent;if (linkcopy == header->left){newlink = link;while ((newlink->left) != NULL)newlink = newlink->left;header->left = newlink;}}else{link = link->left;link->parent = linkcopy->parent;if (linkcopy == header->right){newlink = link;while ((newlink->right) != NULL)newlink = newlink->right;header->right = newlink;}}delete linkcopy;}template <class T>void BinSearchTree<T>::deleteLink(Link& link){if (link->left == NULL || link->right == NULL)prune(link);else if (link->right->left == NULL){link->item = link->right->item;prune(link->right);}else{Link temp = link->right->left;while (temp->left != NULL)temp = temp->left;link->item = temp->item;prune(temp->parent->left);}}
5).~BinSearchTree
(递归版本)
// 释放为这个树分配的空间template <class T>void BinSearchTree<T>::destroy(Link link){if (link != NULL){destroy(link->left);destroy(link->right);delete(link);}}template <class T>BinSearchTree<T>::~BinSearchTree(){destroy(header->parent);delete header;}
6)iterator接口
// iterator类接口template <class T> typenameBinSearchTree<T>::iterator& BinSearchTree<T>::iterator::operator++(int){Link templink;if (link->right != NULL){link = link->right;while ((link->left) != NULL)link = link->left;}// 节点有右子女else{templink = link->parent;while (link == templink->right){link = templink;templink = templink->parent;}if ((link->right) != templink)link = templink;}// 节点没有右子女return *this;}#endif
驱动程序:
#include "15 BinSearchTree class.h"int main(){BinSearchTree<int> tree;tree.insert(85);tree.insert(70);tree.insert(91);tree.insert(100);tree.insert(120);tree.insert(91);tree.insert(66);cout << "Here is the tree:\n";BinSearchTree<int>::iterator itr = tree.begin();for (; itr != tree.end(); itr++)cout << *itr << "";cout << endl << "Size of the tree: " << tree.size() << endl;if (tree.find(72) == tree.end())cout << "72 was not found in the tree!\n";if (tree.find(91) != tree.end())cout << "91 was found in the tree!\n";cout << "\nDelete \"100\", and the tree:\n";itr = tree.find(100);tree.erase(itr);itr = tree.begin();for (; itr != tree.end(); itr++)cout << *itr << "";cout << endl << "Size of the tree: " << tree.size() << endl;return 0;}
测试结果:










原创粉丝点击