1. 程式人生 > >二叉搜尋樹的定義、查詢、插入和刪除

二叉搜尋樹的定義、查詢、插入和刪除

二叉搜尋樹的定義

二叉搜尋樹,也稱有序二叉樹,排序二叉樹,是指一棵空樹或者具有下列性質的二叉樹:

1. 若任意節點的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;

2. 若任意節點的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;

3. 任意節點的左、右子樹也分別為二叉查詢樹。

4. 沒有鍵值相等的節點。


二叉搜尋樹的刪除:

具體實現過程解析:

二叉搜尋樹的結構實現:

//二叉搜尋樹結構
template<class K, class V>
struct BSTreeNode
{
	BSTreeNode* _left;
	BSTreeNode* _right;
	K _key;
	V _value;

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

};

查詢實現有迭代和遞迴兩種

迭代法:

        //在二叉搜尋樹中查詢節點
	Node* Find(const K& key)
	{
		Node* cur=_root;
		//開始遍歷查詢
		while (cur)
		{
			if (cur->_key > key)
			{
				cur = cur->_left;
			}
			else if(cur->_key<key)
			{
				cur = cur->_right;
			}
			else
			{
				return cur;
			}
		}
		 
		return NULL;
	}

遞迴法:

                //遞迴查詢法
		Node* _Find_R(Node* root, const K& key)
		{
			if (root == NULL)
			{
				return NULL;
			}
			if (root->_key > key)
			{
				return _Find_R(root->_left, key);
			}
			else if (root->_key < key)
			{
				return _Find_R(root->_right, key);
			}
			else
			{
				return root;
			}
		}

刪除迭代法:
        //在二叉搜尋樹中刪除節點
	bool Remove(const K& key)
	{
		//沒有節點
		if (_root == NULL)
		{
			return false;
		}
		//只有一個節點
		if (_root->_left == NULL&&_root->_right == NULL)
		{
			if (_root->_key == key)
			{
				delete _root;
				_root = NULL;
				return true;
			}

			return false;
		}

		Node* parent = NULL;
		Node* cur = _root;
		//遍歷查詢要刪除節點的位置
		while (cur)
		{
			Node* del = NULL;
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				//要刪除節點的左子樹為空,分3種情況
				if (cur->_left == NULL)
				{
					//注意判斷父節點是否為空,若為空,則要刪除的節點為根節點,如:只有根節點5和其右節點9
					if (parent == NULL)
					{
						_root = cur->_right;
						delete cur;
						cur = NULL;
						return true;
					}
					if (parent->_key > cur->_key)
					{
						del = cur;
						parent->_left = cur->_right;
						delete del;
						return true;
					}
					else if (parent->_key < key)
					{
						del = cur;
						parent->_right = cur->_right;
						delete del;
						return true;
					}
				}
				//要刪除節點的右子樹為空,同樣分3種情況
				else if (cur->_right == NULL)
				{
					//注意判斷父節點是否為空,若為空,則要刪除的節點為根節點,如:只有根節點5和其左節點3
					if (parent == NULL)
					{
						_root = cur->_left;
						delete cur;
						cur = NULL;
						return true;
					}
					if (parent->_key > cur->_key)
					{
						del = cur;
						parent->_left = cur->_left;
						delete del;
						return true;
					}
					else if (parent->_key < cur->_key)
					{
						del = cur;
						parent->_right = cur->_left;
						delete del;
						return true;
					}
				}
				//左右子樹都不為空
				else
				{
					Node* del = cur;
					Node* parent = NULL;
					Node* RightFirst = cur->_right;
					//右邊第一個節點的左子樹為空
					if (RightFirst->_left == NULL)
					{
						swap(RightFirst->_key, cur->_key);
						swap(RightFirst->_value, cur->_value);
						del = RightFirst;
						cur->_right = RightFirst->_right;
						delete del;
						return true;
					}
					//右邊第一個節點的左子樹不為空
					while (RightFirst->_left)
					{
						parent = RightFirst;
						RightFirst = RightFirst->_left;
					}
					   swap(RightFirst->_key, cur->_key);
					   swap(RightFirst->_value, cur->_value);
					   del = RightFirst;
					   parent->_left = RightFirst->_right;
					   delete del;
				       return true;
				}
			}
		}
		return false;
	}

刪除遞迴法:

                bool _Remove_R(Node*& root, const K& key)
		{
			//沒有節點
			if (root == NULL)
			{
				return false;
			}
			//只有一個節點
			if (root->_left == NULL&&root->_right == NULL)
			{
				if (root->_key == key)
				{
					delete root;
					root = NULL;
					return true;
				}
				else
				{
					return false;
				}

			}

			//刪除二叉搜尋樹節點的遞迴寫法
			if (root->_key > key)
			{
				_Remove_R(root->_left, key);
			}
			else if (root->_key < key)
			{
				_Remove_R(root->_right, key);
			}
			else
			{
				Node* del = NULL;
				
				if (root->_left == NULL)
				{
					del = root;
					root = root->_right;
					delete del;
					del = NULL;
					return true;
				}
				else if (root->_right == NULL)
				{
					del = root;
					root = root->_left;
					delete del;
					del = NULL;
					return true;
				}
				else
				{
					Node* RightFirst = root->_right;

					while (RightFirst->_left)
					{
						RightFirst = RightFirst->_left;
					}

					swap(root->_key, RightFirst->_key);
					swap(root->_value, RightFirst->_value);

					_Remove_R(root->_right, key);
					return true;
				}
			}
		}

插入非遞迴:

        //在二叉搜尋樹中插入節點
	bool Insert(const K& key, const V& value)
	{
		if (_root == NULL)
		{
			_root = new Node(key, value);
		}

		Node* cur=_root;
		Node* parent = NULL;
		//首先找到要插入的位置
		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if(cur->_key<key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}
		//在找到插入位置以後,判斷插入父親節點的左邊還是右邊
		if (parent->_key > key)
		{
			parent->_left = new Node(key, value);
		}
		else
		{
			parent->_right = new Node(key, value);
		}

		return true;
	}

插入遞迴:

                //遞迴插入法
		bool _Insert_R(Node*& root, const K& key, const V& value)
		{
			if (root == NULL)
			{
				root = new Node(key, value);
				return true;
			}
			if (root->_key > key)
			{
				return _Insert_R(root->_left, key, value);
			}
			else if(root->_key < key)
			{
				return _Insert_R(root->_right, key, value);
			}
			else
			{
				return false;
			}
		}

當二叉搜尋樹出現如下圖情形時,效率最低:


完整程式碼及測試實現如下:

#include<iostream>
using namespace std;

//二叉搜尋樹結構
template<class K, class V>
struct BSTreeNode
{
	BSTreeNode* _left;
	BSTreeNode* _right;
	K _key;
	V _value;

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

};

template<class K,class V>
class BSTree
{
	typedef BSTreeNode<K, V> Node;
public:
	BSTree()
		:_root(NULL)
	{}
	
	//在二叉搜尋樹中插入節點
	bool Insert(const K& key, const V& value)
	{
		if (_root == NULL)
		{
			_root = new Node(key, value);
		}

		Node* cur=_root;
		Node* parent = NULL;
		//首先找到要插入的位置
		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if(cur->_key<key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}
		//在找到插入位置以後,判斷插入父親節點的左邊還是右邊
		if (parent->_key > key)
		{
			parent->_left = new Node(key, value);
		}
		else
		{
			parent->_right = new Node(key, value);
		}

		return true;
	}


	//在二叉搜尋樹中查詢節點
	Node* Find(const K& key)
	{
		Node* cur=_root;
		//開始遍歷查詢
		while (cur)
		{
			if (cur->_key > key)
			{
				cur = cur->_left;
			}
			else if(cur->_key<key)
			{
				cur = cur->_right;
			}
			else
			{
				return cur;
			}
		}
		 
		return NULL;
	}


	//在二叉搜尋樹中刪除節點
	bool Remove(const K& key)
	{
		//沒有節點
		if (_root == NULL)
		{
			return false;
		}
		//只有一個節點
		if (_root->_left == NULL&&_root->_right == NULL)
		{
			if (_root->_key == key)
			{
				delete _root;
				_root = NULL;
				return true;
			}

			return false;
		}

		Node* parent = NULL;
		Node* cur = _root;
		//遍歷查詢要刪除節點的位置
		while (cur)
		{
			Node* del = NULL;
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				//要刪除節點的左子樹為空,分3種情況
				if (cur->_left == NULL)
				{
					//注意判斷父節點是否為空,若為空,則要刪除的節點為根節點,如:只有根節點5和其右節點9
					if (parent == NULL)
					{
						_root = cur->_right;
						delete cur;
						cur = NULL;
						return true;
					}
					if (parent->_key > cur->_key)
					{
						del = cur;
						parent->_left = cur->_right;
						delete del;
						return true;
					}
					else if (parent->_key < key)
					{
						del = cur;
						parent->_right = cur->_right;
						delete del;
						return true;
					}
				}
				//要刪除節點的右子樹為空,同樣分3種情況
				else if (cur->_right == NULL)
				{
					//注意判斷父節點是否為空,若為空,則要刪除的節點為根節點,如:只有根節點5和其左節點3
					if (parent == NULL)
					{
						_root = cur->_left;
						delete cur;
						cur = NULL;
						return true;
					}
					if (parent->_key > cur->_key)
					{
						del = cur;
						parent->_left = cur->_left;
						delete del;
						return true;
					}
					else if (parent->_key < cur->_key)
					{
						del = cur;
						parent->_right = cur->_left;
						delete del;
						return true;
					}
				}
				//左右子樹都不為空
				else
				{
					Node* del = cur;
					Node* parent = NULL;
					Node* RightFirst = cur->_right;
					//右邊第一個節點的左子樹為空
					if (RightFirst->_left == NULL)
					{
						swap(RightFirst->_key, cur->_key);
						swap(RightFirst->_value, cur->_value);
						del = RightFirst;
						cur->_right = RightFirst->_right;
						delete del;
						return true;
					}
					//右邊第一個節點的左子樹不為空
					while (RightFirst->_left)
					{
						parent = RightFirst;
						RightFirst = RightFirst->_left;
					}
					   swap(RightFirst->_key, cur->_key);
					   swap(RightFirst->_value, cur->_value);
					   del = RightFirst;
					   parent->_left = RightFirst->_right;
					   delete del;
				       return true;
				}
			}
		}
		return false;
	}

	bool Insert_R(const K& key, const V& value)
	{
		return _Insert_R(_root, key, value);
	}

	Node* Find_R(const K& key)
	{
		return _Find_R(_root, key);
	}

	bool Remove_R(const K& key)
	{
		return _Remove_R(_root, key);
	}

	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

protected:
		
		bool _Remove_R(Node*& root, const K& key)
		{
			//沒有節點
			if (root == NULL)
			{
				return false;
			}
			//只有一個節點
			if (root->_left == NULL&&root->_right == NULL)
			{
				if (root->_key == key)
				{
					delete root;
					root = NULL;
					return true;
				}
				else
				{
					return false;
				}

			}

			//刪除二叉搜尋樹節點的遞迴寫法
			if (root->_key > key)
			{
				_Remove_R(root->_left, key);
			}
			else if (root->_key < key)
			{
				_Remove_R(root->_right, key);
			}
			else
			{
				Node* del = NULL;
				
				if (root->_left == NULL)
				{
					del = root;
					root = root->_right;
					delete del;
					del = NULL;
					return true;
				}
				else if (root->_right == NULL)
				{
					del = root;
					root = root->_left;
					delete del;
					del = NULL;
					return true;
				}
				else
				{
					Node* RightFirst = root->_right;

					while (RightFirst->_left)
					{
						RightFirst = RightFirst->_left;
					}

					swap(root->_key, RightFirst->_key);
					swap(root->_value, RightFirst->_value);

					_Remove_R(root->_right, key);
					return true;
				}
			}
		}

		//遞迴查詢法
		Node* _Find_R(Node* root, const K& key)
		{
			if (root == NULL)
			{
				return NULL;
			}
			if (root->_key > key)
			{
				return _Find_R(root->_left, key);
			}
			else if (root->_key < key)
			{
				return _Find_R(root->_right, key);
			}
			else
			{
				return root;
			}
		}
			
		//遞迴插入法
		bool _Insert_R(Node*& root, const K& key, const V& value)
		{
			if (root == NULL)
			{
				root = new Node(key, value);
				return true;
			}
			if (root->_key > key)
			{
				return _Insert_R(root->_left, key, value);
			}
			else if(root->_key < key)
			{
				return _Insert_R(root->_right, key, value);
			}
			else
			{
				return false;
			}
		}

		void _InOrder(Node* root)
		{
			if (root == NULL)
			{
				return;
			}

			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);
		}
protected:
	Node* _root;

};


void Test()
{
	BSTree<int, int> s;
	
	//測試插入
	s.Insert_R(5, 1);
	s.Insert_R(4, 1);
	s.Insert_R(3, 1);
	s.Insert_R(6, 1);
	s.Insert_R(1, 1);
	s.Insert_R(2, 1);
	s.Insert_R(0, 1);
	s.Insert_R(9, 1);
	s.Insert_R(8, 1);
	s.Insert_R(7, 1);

	//二叉搜尋樹按中序輸出是有序的
	s.InOrder();

	//測試查詢
	cout << s.Find_R(6)->_key << endl;

	//測試刪除
	s.Remove(4);
	s.Remove(6);
	s.Remove(3);
	s.Remove(1);
	s.Remove(2);
	
	//再次列印刪除後的結果
	s.InOrder();

}

int main()
{
	Test();
	system("pause");
	return 0;
}






執行結果:

0 1 2 3 4 5 6 7 8 9
6
0 5 7 8 9
請按任意鍵繼續. . .