二叉搜索樹

一. 二叉搜索樹的性質:

  1. 每個節點都有一個作爲搜索依據的關鍵碼(key),所有節點的關鍵碼互不相同。

  2. 左子樹上所有節點的關鍵碼(key)都小於根節點的關鍵碼(key)。

  3. 右子樹上所有節點的關鍵碼(key)都大於根節點的關鍵碼(key)。

  4. 左右子樹都是二叉搜索樹。


二. 以下圖爲例

int a [] = {5,3,4,1,7,8,2,6,0,9};

wKiom1eJsnbz6BZUAABTgFepaIM539.png

三. 代碼實現

#include<iostream>
using namespace std;

template<class K, class V>
struct BSTreeNode
{
	K _key;
	V _value;
	BSTreeNode<K, V>* _left;
	BSTreeNode<K, V>* _right;

	BSTreeNode(const K& key, const V& value)
		:_key(key)
		, _value(value)
		, _left(NULL)
		, _right(NULL)
	{}
};

template<class K, class V>
class BSTree
{
	typedef BSTreeNode<K, V> Node;
public:
	BSTree()
		:_root(NULL)
	{}
	~BSTree()
	{}
	bool Insert(const K& key, const V& value)
	{
		Node* cur = _root;
		Node* parent = cur;
		if (_root == NULL)
		{
			_root = new Node(key, value);
			return true;
		}

		while (cur)
		{
			if (key > cur->_key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (key < cur->_key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
				return false;	
		}
		if (key > parent->_key)
		{
			parent->_right = new Node(key, value);
		}
		else
		{
			parent->_left = new Node(key, value);
		}
		return true;		
	}
	Node* Find(const K& key)
	{
		if (_root == NULL)
			return NULL;
		Node* cur = _root;
		while (cur)
		{
			if (key > cur->_key)
				cur = cur->_right;
			else if (key < cur->_key)
				cur = cur->_left;
			else
				return cur; 
		}
		return NULL;
	}
	bool Remove(const K& key)
	{
		if (_root == NULL)
			return false;

		Node* cur = _root;
		Node* parent = NULL;
		Node* del = NULL;
		
		//find
		while (cur)
		{
			if (key > cur->_key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (key < cur->_key)
			{
				parent = cur;
				cur = cur->_left;
			}
			//delete
			else
			{
				Node* del;
				//要刪的節點的左子樹爲空
				if (cur->_left == NULL)
				{
					del = cur;
					//root
					if (parent == NULL)
						_root = cur->_right;
					else
					{
						if (parent->_left == cur)
							parent->_left = cur->_right;
						else
							parent->_right = cur->_right;
					}		
				}
				//要刪的節點的右子樹爲空
				else if (cur->_right == NULL)
				{
					del = cur;
					if (parent == NULL)
						_root = cur->_left;
					else
					{
						if (parent->_left = cur)
							parent->_left = cur->_left;
						else
							parent->_right = cur->_left;
					}
					//return true;
				}
				//要刪的節點的左右子樹都不爲空
				else
				{
					parent = cur;
					//找右子樹的最左節點或找左子樹的最右節點
					Node* tmp = cur->_right;//tmp不能用引用
					while (tmp->_left)
					{
						parent = tmp;
						tmp = tmp->_left;
					}
					cur->_key = tmp->_key;
					cur->_value = tmp->_value;
					del = tmp;
					//把tmp的子樹連接在tmp的parent上
					if (parent->_left == tmp)
						parent->_left = tmp->_right;
					else
						parent->_right = tmp->_right;		
				}
				delete del;
				return true;
			}	
		}
		return false;
	}
	
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
	void _InOrder(Node*& root)
	{
		if (root == NULL)
			return;
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}

protected:
	Node* _root;
	
};

	int main()
	{
		int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
		BSTree<int, int> bst;
		for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
		{
			bst.Insert(a[i], i);
		}
		bst.InOrder();
		//BSTreeNode<int,int>* node = bst.Find(5); 
		//cout << node->_key << endl;

		//bst.Find(100);

		cout << bst.Remove(13) << endl;
		bst.InOrder();

		cout << bst.Remove(5) << endl;
		bst.InOrder();

		bst.Remove(7);
		bst.InOrder();

		bst.Remove(8);
		bst.InOrder();

		bst.Remove(9);
		bst.InOrder();

		bst.Remove(0);
		bst.Remove(1);
		bst.Remove(2);
		bst.Remove(3);
		bst.Remove(4);
		bst.Remove(5);
		bst.Remove(6);
		bst.Remove(7);
		bst.Remove(8);
		bst.Remove(9);
		bst.InOrder();

		system("pause");
		return 0;
	}

四. 二叉搜索樹的缺陷

   可能變成單鏈表,而失去當它搜索時每次都能排除一半節點的特性。解決辦法是把樹變得平衡。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章