二叉搜索樹的簡單操作與實現

二叉搜索樹(BinarySearchTree)性質

  二叉搜索樹首先是一棵二叉樹,二叉樹可能爲空,而一顆非空的二叉搜索樹要滿足以下條件:

  (1)每個元素有一個關鍵字,所有關鍵字是唯一的。(關鍵字不唯一的二叉搜索樹叫有重複值的二叉搜索樹

  (2)在根節點的左子數的元素都小於根節點的關鍵字。

  (3)在根節點的右子數的元素都大於根節點的關鍵字。

  (4)根節點的左右子樹也是一棵二叉搜索樹

二叉搜索樹的結構

c++代碼:

template <class K,class V>
struct BSTnode     //二叉搜索樹節點結構
{
	BSTnode *leftChild;     //左子樹
	BSTnode *rightChild;    //右子樹
	K key;
	V value;

	//構造方法
	BSTnode(const K& theKey,const V& theValue)
		:leftChild(NULL),rightChild(NULL),key(theKey),value(theValue)
	{}
};

template <class K,class V>
class MyBSTree
{
private:
	BSTnode<K, V> rootNode;     //根節點
public:
	BSTnode<K, V>* Find(const K& theKey);          //查找
	bool Insert(const K& theKey, const V& theValue);   //插入
	bool Erase(const K& theKey);                 //刪除
	void InOrder();                          //中序遍歷
};


二叉搜索樹的查找

查找的遞歸實現(c++):

//查找的遞歸實現
template <class K,class V>
BSTnode<K, V>* MyBSTree<K, V>::Find(BSTnode<K,V>* root,const K& theKey)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->key > theKey)
	{
		return Find(root->leftChild, theKey);
	}
	else if (root->key < theKey)
	{
		return Find(root->rightChild, theKey);
	}
	else
	{
		return root;
	}
}

查找的迭代實現(c++):

template <class K,class V>
BSTnode<K, V>* MyBSTree<K, V>::Find(const K& theKey)
{
	BSTnode<K, V>* currentNode = rootNode;
	while (currentNode != NULL)
	{
		if (currentNode->key > theKey)
		{
			currentNode = currentNode->rightChild;
		}
		else if (currentNode->key < theKey)
		{
			currentNode = currentNode->leftChild;
		}
		else
		{
			return currentNode;
		}
	}
	return  NULL;
}
二叉搜索樹的插入

二叉搜索樹的插入步驟:

首先查找二叉搜索樹是否有節點的關鍵字和要插入的相同,有的話則不插入;

如果沒有與要插入的節點的關鍵字相同的節點,則將該節點作爲搜索中斷的節點的孩子插入二叉搜索樹。

插入的遞歸實現

template <class K,class V>
bool MyBSTree<K,V>::Insert(BSTnode<K,V>*& root ,const K& theKey, const V& theValue)
{
	if (root == NULL)
	{
		rootNode = new BSTnode(theKey, theValue);
		return true;
	}
	if (root->key >theKey)
	{
		return Insert(root->leftChild,theKey,theValue);
	}
	else if (root->key < theKey)
	{
		return Insert(root->rightChild,theKey,theValue);
	}
	else
	{
		return false;
	}
}

插入的迭代實現

//插入的迭代實現
template <class K, class V>
bool MyBSTree<K, V>::Insert(const K& theKey, const V& theValue)
{
	if (rootNode == NULL)         //插入空樹
	{
		rootNode = new BSTnode(theKey, theValue);
		return;
	}
	BSTnode<K, V>* currentNode = rootNode;
	BSTnode<K, V>* parentNode = NULL;
	while (currentNode != NULL)   //尋找插入位置
	{
		if (currentNode->key > theKey)
		{
			parentNode = currentNode;
			currentNode = currentNode->leftChild;
		}
		else if (currentNode->key < theKey)
		{
			parentNode = currentNode;
			currentNode = currentNode->rightChild;
		}
		else
		{
			return false;
		}			
	}
	//找到插入位置後,判斷是左節點還是右節點,建立新的節點並與parentNode進行連接
	if (parentNode->key >theKey)
	{
		parentNode->leftChild = new BSTnode(theKey, theValue);
	}
	else if (parentNode->key < theKey)
	{
		parentNode->rightChild = new BSTnode(theKey, theValue);
	}
	return true;
}

二叉搜索樹的刪除

二叉搜索樹刪除的步驟:

要考慮三種情況:(1)p是葉子節點(2)p只有只有一棵非空子樹(3)p有兩棵非空子樹

當p爲葉子節點,只需要把p的父節點對應子樹置爲NULL,如果p爲根節點,則令根節點爲NULL。

當p有一棵非空子樹,子樹繼承p的位置。

當p有兩棵非空子樹,找到p的最近前驅,來替代p的位置,並將前驅刪去,用前驅的子樹替代前驅位置。

刪除的遞歸實現:

//刪除遞歸實現
template <class K, class V>
bool MyBSTree<K, V>::Erase(BSTnode<K,V>*& root,const K& theKey)
{
	if (root == NULL)       //空樹
	{
		return false;
	}
	if (root->leftChild == NULL&&root->rightChild == NULL)     //只有根節點
	{
		if (root->key == theKey)          //要刪除的是根節點
		{
			delete root;
			root = NULL;
			return true;
		}
		else
		{
			return false;
		}
	}
	if (root->key > theKey)
	{
		Erase(root->leftChild, theKey);
	}
	else if (root -> key < theKey)
	{
		Erase(root->rightChild, theKey);
	}
	else      //找到要刪除的節點
	{
		BSTnode<K, V>* tempNode = NULL;   //臨時節點
		if (root->leftChild == NULL)   //沒有左子樹
		{
			tempNode = root;
			root = root->rightChild;          //右子樹繼承自身位置
			delete tempNode;
			return true;
		}
		else if (root ->rightChild == NULL)  //沒有右子樹
		{
			tempNode = root;
			root = root->leftChild;      //左子樹替代自身位置
			delete tempNode;
			return true;
		}
		else   //既有左子樹也有右子樹
		{
			//找到最近前驅
			BSTnode<K, V>* closestNode = root->leftChild;
			while (closestNode->rightChild)   //根節點左子樹的右子樹爲最近前驅
			{
				tempNode = closestNode;
				closestNode = closestNode->rightChild;
			}
			//前驅替換要刪除的節點
			swap(root->key, closestNode->key);
			swap(root->value, closestNode->value);

			Erase(root->leftChild);
		}
	}
}


刪除的迭代實現:

//刪除迭代實現
template <class K, class V>
bool MyBSTree<K, V>::Erase(const K& theKey)
{
	if (rootNode == NULL) //空樹
	{
		return false;
	}
	if (rootNode->leftChild ==NULL&& rootNode->rightChild ==NULL) //只有根節點
	{
		if (rootNode.key == theKey)
		{
			rootNode = NULL;
			delete rootNode;
			return true;
		}
		return false;
	}
	BSTnode<K, V>* parentNode = NULL;
	BSTnode<K, V>* currentNode = rootNode;
	while (currentNode != NULL)
	{   //尋找要刪除的節點
		if (currentNode->key>theKey)
		{
			parentNode = currentNode;
			currentNode = currentNode->leftChild;
		}
		else if (currentNode->key<theKey)
		{
			parentNode = currentNode;
			currentNode = currentNode->rightChild;
		}
		else
		{    //找到要刪除的節點
			if (currentNode->leftChild == NULL)   //沒有左子樹
			{
				if (parentNode == NULL)  //要刪除的爲根節點
				{
					rootNode = currentNode.rightChild;
					delete currentNode;
					currentNode = NULL;
					return true;
				}
				if (parentNode->key>currentNode->key)
				{
					parentNode->leftChild = currentNode->rightChild;
					delete currentNode;
					currentNode = NULL;
					return true;
				}
				else if (parent->key<currentNode->key)
				{
					parentNode->rightChild = currentNode->rightChild;
					delete currentNode;
					currentNode = NULL;
					return true;
				}
			}
			else if (currentNode->rightChild == NULL)  //沒有右子樹,同沒右左子樹
			{
				if (parentNode == NULL)  //要刪除的爲根節點
				{
					rootNode = currentNode.leftChild;
					delete currentNode;
					currentNode = NULL;
					return true;
				}
				if (parentNode->key>currentNode->key)
				{
					parentNode->leftChild = currentNode->leftChild;
					delete currentNode;
					currentNode = NULL;
					return true;
				}
				else if (parent->key<currentNode->key)
				{
					parentNode->rightChild = currentNode->leftChild;
					delete currentNode;
					currentNode = NULL;
					return true;
				}
			}
			else    //既有左子樹也有右子樹
			{
				BSTnode<K, V>* tempNode = currentNode;
				BSTnode<K, V>* closestNode = currentNode->leftChild;
				while (closestNode->rightChild)
				{
					tempNode = closestNode;
					closestNode = closestNode->rightChild;  //closestNode指向最近前驅節點,tempNode指向其父節點
				}
				currentNode->key = closestNode->key;
				currentNode->value = closestNode->value;
				if (tempNode != currentNode)
					tempNode->rightChild = closestNode->leftChild;
				else
				{
					tempNode->leftChild = closestNode->leftChild;
				}
				delete tempNode;
			}
			return true;
		}
	}
}


二叉搜索樹的遍歷

根據二叉搜索樹的性質,所以二叉樹的中序遍歷可以得到有序表。

中序遍歷的實現(c++)

//中序遍歷
template <class K,class V>
void MyBSTree<K, V>::InOrder()
{
	if (rootNode == NULL)
	{
		return;
	}
	InOrder(rootNode->leftChild);
	cout << rootNode->key<<" ";
	InOrder(rootNode->rightChild);
}



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