(折半查找树)BinSearchTree模板类

二叉树递归定义:

二叉树 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> typename
	BinSearchTree<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;
			else
				child = 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> typename
	BinSearchTree<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;
		}
		else
			child = child->right;
	}
	if (parent == header || item < parent->item)
		return end();
	else
		return 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);
	else
		deleteLink(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> typename
	BinSearchTree<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;
}
测试结果:










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值