二叉搜索樹

  1. 二叉搜索樹

     二叉搜索樹又被稱爲二叉查找樹、二叉排序樹。其具備以下性質:

     

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

    2>左節點的關鍵碼都小於根結點的關鍵碼

    3>右節點的關鍵碼都大於根結點的關鍵碼

    4>每個子樹都滿足二叉搜索樹

 具備以上性質,所以二叉搜索樹的中序遍歷是有序的。

wKioL1eVs2rxiV8iAAAZo1hBCus902.png-wh_50

2.二叉搜索樹的構造

  每個節點有一個key值和value值,key值是用來區分節點的,每個節點的key值都不相同。每個節點都

有指向左和右的指針。

template<class K, class V>
struct BSTreeNode
{
	BSTreeNode(const K&key, const V&value)
	:_left(NULL)
	, _right(NULL)
	, _key(key)
	, _value(value)
	{}
	BSTreeNode<K, V>* _left;
	BSTreeNode<K, V>* _right;
	K _key;
	V _value;
};

template<class K, class V>
class BSTree
{
	typedef BSTreeNode<K, V> Node;
public:
	BSTree()
		:_root(NULL)
	{}
	~BSTree()
	{
		if (_root)
		{
			clear();
		}
        }
protected:
 Node* _root;
};

3.二叉搜索樹的插入

 如果插入的時候是一顆空樹,則new一個根結點出來,之後插入的時候根據key值來進行判斷插入的位

置,每插入一個值都要從根節點開始判斷,要插入的key值比根結點的key值小,則走左樹,比根節點的

key值大,則走右樹。直到找到正確的位置進行插入,返回true。當然與根節點的值相等的話返回false。

  1>非遞歸的插入

  

bool insert(const K& key, const V&value)

{//遵循左小於根右大於根,每個子樹都滿足

if (_root == NULL)

{

_root = new Node(key, value);

return true;

}

Node*parent = NULL;

Node*cur = _root;

while (cur)

{

if (cur->_key < key)

{

parent = cur;

cur = cur->_right;

}

else if (cur->_key>key)

{

parent = cur;

cur = cur->_left;

}

else


{

return false;

}

}


if (parent->_key > key)

{

parent->_left = new Node(key, value);

}

else

parent->_right = new Node(key, value);

return true;

}

  2>遞歸插入

  

//進行遞歸插入,注意_insertR接收的root參數是引用類型的,

bool insertR(const K&key, const V&value)

{

return _insertR(_root, key, value);

}

protected:

bool _insertR(Node* &root, const K&key, const V&value)

{

if (root == NULL)//此時的root肯定是要插入的key值正確的位置,因爲root是引用的

{

root = new Node(key, value);

return true;

}

if (root->_key > key)

{

_insertR(root->_left, key, value);

}

else if (root->_key < key)

{

_insertR(root->_right, key, value);

}


else

{

return false;

}


}

4.二叉搜索樹的查找

  

  二叉樹最壞的查找情況時間複雜度爲O(n);平均時間複雜度爲O(log2(n))。

  

Node* find(const K&key)//找到的話返回該節點
	{
		assert(_root);
		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;
	}
	
	

5.二叉搜索樹的刪除

  

  二叉搜索樹的刪除可分爲三種情況:

    1>要刪除的節點的左樹爲空,右樹可爲空可不爲空,這個節點可能爲根節點,也可能爲其他節點。


 刪一個普通的左樹爲空的節點。讓該節點的父親節點指向該節點的右節點,刪除該節點。

 刪除這個樹的8這個節點

wKioL1eVtvqjNfsXAAA1mTAV2Bg616.png-wh_50

 2>要刪除的節點的右樹爲空,左樹可爲空可不爲空,這個節點可能爲根節點,也可能爲其他節點。

   刪除的方法與右節點同理。這裏不舉例子了。

 3>要刪除的節點左右都不爲空。

   首先找到該節點右樹的最左節點,然後與其交換,再刪除最左節點。因爲該節點右樹的最左節點比

該節點左樹的節點都大,比該節點右樹的節點都小,滿足二叉搜索樹,所以用其與刪除的節點交換

 wKioL1eVuluBGzoXAAA7wrZdQmk224.png-wh_50

1>非遞歸的刪除
bool remove(const K&key)
	{
		if (_root == NULL)
			return false;
		Node* cur = _root;
		Node* parent = NULL;
		//找到要刪除的節點
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key>key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				break;
			}
		}
		if (cur == NULL)
		{
			return false;
		}
		Node* del;
		//1.cur->left==NULL
		if (cur->_left == NULL)
		{
			del = cur;
			//刪除的是根節點
			if (parent == NULL)
			{
				_root = cur->_right;
			}
			else
			{
				if (parent->_left == cur)
				{
					parent->_left = cur->_right;
				}
				else
				{
					parent->_right = cur->_right;
				}
			}
		}
		//2.cur->right=NULL
		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;
				}
			}
		}
		else //左右不爲空
		{
			parent = cur;
			//找到右樹的最左節點進行替換,這樣的話還是滿足二叉搜索樹
			Node* firstLeftN = cur->_right;
			while (firstLeftN->_left)
			{
				parent= firstLeftN;
				firstLeftN = firstLeftN->_left;
			}
			del = firstLeftN;
			cur->_key = firstLeftN->_key;
			cur->_value = firstLeftN->_value;
			if (parent->_left == firstLeftN)
			{
				parent->_left = firstLeftN->_right;
			}
			else
			{
				parent->_right = firstLeftN->_right;
			}
		}
		delete del;
		return true;
	}
		 
	2>遞歸的刪除
	bool removeR(const K&key)
	{
	  return _removeR(_root, key);
	}
	bool _removeR(Node*& root, const K&key)
	{
		if (root == NULL)
		{
			return false;
		}
		if (root->_key < key)
		{
			_removeR(root->_right, key);
		}
		else if (root->_key>key)
		{
			_removeR(root->_left, key);
		}
		else
		{
			Node *del = root;
			//1.要刪的節點左爲空
			if (root->_left == NULL)
			{
				root = root->_right;
			}
			//右爲空
			else if (root->_right == NULL)
			{
				root = root->_left;
			}
			//左右不爲空
			else
			{
				Node*firstLeftN = root->_right;
				while (firstLeftN->_left)
				{
					firstLeftN = firstLeftN->_left;
				}
					
				swap(root->_key, firstLeftN->_key);
				swap(root->_value, firstLeftN->_value);
     			return _removeR(root->_right,key);

			}
			delete del;
		    return true;
		}
		
	}
	


 




    

      

  



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