二分搜索树C++模板实现

    二分搜索树最难的操作是remove,floor,ceil,需要多看。

BST.h

#pragma once
#include<iostream>
#include<queue>
#include<cassert>
using namespace std;

template<typename Key, typename Value>
class BST
{
private:
	struct Node
	{
		Key key;
		Value value;
		Node * left;
		Node * right;

		Node(Key key, Value value)
		{
			this->key = key;
			this->value = value;
			this->left = this->right = NULL;
		}
		Node(Node *node)
		{
			this->key = node->key;
			this->value = node->value;
			this->left = node->left;
			this->right = node->right;
		}
	};

	Node * root;
	int count;

public:
	BST()
	{
		root = NULL;
		count = 0;
	}

	~BST()
	{
		destroy(root);//采用后序遍历的方式依次释放
	}

	int size() { return count; }

	bool isEmpty() { return count == 0; }

	void insert(Key key, Value value)//递归写法
	{
		root = insert(root, key, value);
	}

	//void insert(Key key, Value value)//非递归写法:双指针法
	//{
	//	Node * pnode = root;//指向应该插入的位置
	//	Node * pre = pnode;//指向应该插入位置的父亲节点

	//	//找到应该插入的位置
	//	while (pnode != NULL)
	//	{
	//		if (pnode->key == key)//如果插入的key节点已存在,则替换掉value值即可
	//		{
	//			pnode->value = value;
	//			return;
	//		}
	//		else if (pnode->key > key)
	//		{
	//			pre = pnode;
	//			pnode = pnode->left;
	//		}
	//		else
	//		{
	//			pre = pnode;
	//			pnode = pnode->right;
	//		}
	//	}
	//	
	//	pnode = new Node(key, value);//新建一个节点

	//	//如果没有根节点,则创造一个
	//	if (pre == NULL) 
	//		root = pnode;

	//	//以下两行代表将新建的节点连接上父亲节点
	//	else if (pre->key > pnode->key)
	//		pre->left = pnode;
	//	else
	//		pre->right = pnode;

	//	count++;
	//}

	bool contain(Key key)
	{
		return contain(root, key);
	}

	Value * search(Key key)//返回Value*的好处是,当查找失败时可以返回NULL
	{
		return search(root, key);
	}

	void preOrder()
	{
		preOrder(root);
	}

	void inOrder()
	{
		inOrder(root);
	}

	void postOrder()
	{
		postOrder(root);
	}

	void leverOrder()//利用队列进行层序遍历
	{
		queue<Node *> q;
		q.push(root);

		while (!q.empty())
		{
			Node * node = q.front();
			q.pop();

			cout << node->value << endl;

			if (node->left != NULL)
				q.push(node->left);
			if (node->right != NULL)
				q.push(node->right);
		}
	}

	//寻找最小的键值:非递归写法
	Key minimum()
	{
		assert(count != 0);

		Node * node = root;

		while (node->left != NULL)
			node = node->left;

		return node->key;
	}

	//寻找最大键值:非递归写法
	Key maximum()
	{
		assert(count != 0);

		Node * node = root;
		while (node->right != NULL)
			node = node->right;

		return node->key;
	}

	void removeMin()
	{
		if (root == NULL) return;

		Node * cur = root;//最小键值节点
		Node * pre = cur;//最小键值节点的父节点

		while (cur->left != NULL)
		{
			pre = cur;
			cur = cur->left;
		}

		if (cur == pre)//如果根节点没有左孩子,此时cur与pre都指向root,root为最小键值节点,将根节点指向当前右孩子即可
			root = cur->right;
		else if (cur->right == NULL)//如果最小键值节点没有右孩子,直接删除即可
			pre->left = NULL;//这句不可删,否则pre->left会是乱码
		else//如果最小键值有右孩子,则将pre节点的左孩子直接连接上这个右孩子,即可维护二分搜索树的性质
			pre->left = cur->right;

		delete cur;
		count--;
	}

	void removeMax()
	{
		if (root == NULL) return;

		Node * cur = root;//最大键值节点
		Node * pre = cur;//最大键值节点的父节点

		while (cur->right != NULL)
		{
			pre = cur;
			cur = cur->right;
		}

		if (cur == pre)//如果根节点没有右孩子,此时cur与pre都指向root,root为最大键值节点,将根节点指向当前左孩子即可
			root = cur->right;
		else if (cur->left == NULL)//如果最大键值节点没有左孩子,直接删除即可
			pre->right = NULL;//这句不可删,否则pre->right会是乱码
		else//如果最小键值有左孩子,则将pre节点的右孩子直接连接上这个左孩子,即可维护二分搜索树的性质
			pre->right = cur->left;

		delete cur;
		count--;
	}

	void remove(Key key)//较困难,需要多看几遍!!!
	{
		root = remove(root, key);
	}

	// 寻找key的floor值, 递归算法
	// 如果不存在key的floor值(key比BST中的最小值还小), 返回NULL
	Key * floor(Key key)
	{
		if (count == 0 || key < minimum())
			return NULL;

		Node * floorNode = floor(root, key);
		return &(floorNode->key);
	}

	// 寻找key的ceil值, 递归算法
	// 如果不存在key的ceil值(key比BST中的最大值还大), 返回NULL
	Key* ceil(Key key) {

		if (count == 0 || key > maximum())
			return NULL;

		Node *ceilNode = ceil(root, key);
		return &(ceilNode->key);
	}
private:
	// 在以node为根的二叉搜索树中, 寻找key的floor值所处的节点, 递归算法
	Node * floor(Node * node, Key key)
	{
		if (node == NULL)
			return NULL;

		// 如果node的key值和要寻找的key值相等
		// 则node本身就是key的floor节点
		if (node->key == key)
			return node;

		// 如果node的key值比要寻找的key值大
		// 则要寻找的key的floor节点一定在node的左子树中
		if (node->key > key)
			return floor(node->left, key);

		// 如果node->key < key
		// 则node有可能是key的floor节点, 也有可能不是(存在比node->key大但是小于key的其余节点)
		// 需要尝试向node的右子树寻找一下
		Node * tempNode = floor(node->right, key);
		if (tempNode != NULL)
			return tempNode;

		return node;
	}

	// 在以node为根的二叉搜索树中, 寻找key的ceil值所处的节点, 递归算法
	Node* ceil(Node* node, Key key) {

		if (node == NULL)
			return NULL;

		// 如果node的key值和要寻找的key值相等
		// 则node本身就是key的ceil节点
		if (node->key == key)
			return node;

		// 如果node的key值比要寻找的key值小
		// 则要寻找的key的ceil节点一定在node的右子树中
		if (node->key < key)
			return ceil(node->right, key);

		// 如果node->key > key
		// 则node有可能是key的ceil节点, 也有可能不是(存在比node->key小但是大于key的其余节点)
		// 需要尝试向node的左子树寻找一下
		Node* tempNode = ceil(node->left, key);
		if (tempNode != NULL)
			return tempNode;

		return node;
	}

	Node * remove(Node * node, Key key)
	{
		if (node == NULL)
			return NULL;

		if (node->key > key)
		{
			node->left = remove(node->left, key);
			return node;
		}
		else if (node->key < key)
		{
			node->right = remove(node->right, key);
			return node;
		}
		else //node->key == key
		{
			if (node->left == NULL)
			{
				Node * rightNode = node->right;
				delete node;
				count--;
				return rightNode;
			}

			if (node->right == NULL)
			{
				Node * leftNode = node->left;
				delete node;
				count--;
				return leftNode;
			}

			//node->left != NULL && node->right != NULL
			Node * successor = new Node(minimum(node->right));
			count++;
			successor->right = removeMin(node->right);
			successor->left = node->left;

			delete node;
			count--;

			return successor;
		}
	}

	void destroy(Node * node)
	{
		if (node != NULL)
		{
			destroy(node->left);
			destroy(node->right);

			delete node;
			count--;
		}
	}

	//对以node为根的二叉搜索树进行后序遍历
	void postOrder(Node * node)
	{
		if (node != NULL)
		{
			postOrder(node->left);
			postOrder(node->right);
			cout << node->key << endl;
		}
	}

	//对以node为根的二叉搜索树进行中序遍历
	void inOrder(Node * node)
	{
		if (node != NULL)
		{
			inOrder(node->left);
			cout << node->key << endl;
			inOrder(node->right);
		}
	}

	//对以node为根的二叉搜索树进行前序遍历
	void preOrder(Node * node)
	{
		if (node != NULL)
		{
			cout << node->key << endl;
			preOrder(node->left);
			preOrder(node->right);
		}
	}

	//在以node为根的二叉搜索树中查找key所对应的value
	Value * search(Node * node, Key key)
	{
		if (node->key == NULL)
			return NULL;

		if (node->key == key)
			return &node->value;
		else if (node->key > key)
			return search(node->left, key);
		else //node->key < key
			return search(node->right, key);
	}

	//查看以node为根的二叉搜索树中是否包含键值为key的节点
	bool contain(Node * node, Key key)
	{
		if (node->key == NULL)
			return false;

		if (node->key == key)
			return true;
		else if (node->key > key)
			return contain(node->left, key);
		else //node->key < key
			return contain(node->right, key);
	}

	//向以node为根的二叉搜索树中,插入节点(key,value)
	//返回插入新节点后的二叉搜索树的根
	Node * insert(Node *node, Key key, Value value)
	{
		if (node == NULL)
		{
			count++;
			return new Node(key, value);
		}

		if (node->key == key)
			node->value = value;
		else if (key < node->key)
			node->left = insert(node->left, key, value);
		else //key > node->key
			node->right = insert(node->right, key, value);

		return node;
	}
};

main.cpp

#include<iostream>
#include<time.h>
#include"BST.h"
using namespace std;

int main()
{
	BST<int,int> bst;

	srand((unsigned)time(NULL));
	int nums = 15;
	while (nums--)
	{
		int i = rand() % 100;
		bst.insert(i, i);
	}
	//bst.insert(5, 5);
	//bst.insert(7, 7);
	//bst.insert(6, 6);
	//bst.insert(8, 8);


	bst.inOrder();

	cout << "minmum:" << bst.minimum() << endl;
	cout << "maxmum:" << bst.maximum() << endl;

	bst.removeMin();
	bst.removeMax();
	bst.inOrder();

	cout << "minmum:" << bst.minimum() << endl;
	cout << "maxmum:" << bst.maximum() << endl;

	return 0;
}

猜你喜欢

转载自blog.csdn.net/majichen95/article/details/80370078