二叉搜索樹的c++類模板封裝實現

二叉搜索樹:一個近似二分搜索的數據結構跳錶有點像,平衡二叉樹可以靠旋轉操作維護自平衡性,解決退化爲鏈表問題;跳錶通過隨機函數進行上層節點增刪,統計意義上維護平衡性。

c++實現代碼:

Binary_SearchTree.h

hpp文件 實現類的成員函數

測試文件

測試運行結果

缺點:


概念:

二叉搜索樹:二叉搜索樹是由二叉樹來組織的,樹中每一個子樹的根節點key值都大於左樹的key值而小於右子樹的key值。

                   二叉搜索樹的中序遍歷key值恰好是從小到達排序。查詢二叉樹、MinMum、MaxMum、Insert和delete等操作時間複雜                    度爲O(h); h爲樹的高度log2(n);

c++實現代碼:

              頭文件,樹節點和樹 類的定義

Binary_SearchTree.h

   

#ifndef _BINARY_SEARCHTREE
#define  _BINARY_SEARCHTREE

template<typename T>//定義Element類,便於外部調用函數更改數據類型
class Element
{
public:
	T key;//便於在節點中隨時加入數據
	char name;

};

template<typename T> class BST;//BST模板類的聲明

template<typename T>
class BSTNode
{
	friend class BST<T>;//友元類聲明 BST二叉樹要訪問節點私有元素
public:
	Element<T> getElement();
	private:
		Element<T> data;
	    BSTNode *leftChild;
	    BSTNode *rightChild;
		void display(int i);//遞歸展示當前節點信息
	
};

template<typename T>//搜索二叉樹模板類
class BST
{
public:
	BST(BSTNode<T>*init = 0);
	bool BST_insert(const Element<T> &node);//插入元素
	BSTNode<T>* BST_Search(const Element<T>&node);//遞歸搜索
	BSTNode<T>* BST_Search(BSTNode<T>*,const Element<T>&);

	BSTNode<T>*BST_Search_Iterator(const Element<T>&);//迭代搜索
	bool Delete_Node(const Element<T>&node);//刪除節點
	BSTNode<T>*MinMum();//樹的key最大節點
	BSTNode<T>*MaxMum();//樹的key最小節點

	void midOrder();//中序遍歷
	void midOrder(BSTNode<T>*root);

	void display();//遞歸左右子樹展示當前樹所有節點信息
	~BST();

private:
	BSTNode<T> *root;

};

#endif

hpp文件 實現類的成員函數

#include"Binary_SearchTree.h"
#include"iostream"
using namespace std;
//節點的成員函數

//節點內容獲取
template<typename T>
void BSTNode<T>::display(int i)
{
	cout << "position: " << i << "  data.Key:" << data.key << " value:" << data.name << endl;
	if (leftChild)
		leftChild->display(2 * i);
	if (rightChild)
		rightChild->display(2 * i + 1);
}
//獲取節點Element
template<typename T>
Element<T> BSTNode<T>::getElement()
{
	return data;
}


//樹的成員函數

//構造初始化
	template<typename T>
	BST<T>::BST(BSTNode<T>*init = NULL)
	{
		root = init;
	}
//插入節點 
	template<typename T>
	bool BST<T>::BST_insert(const Element<T> &node)
	{
		BSTNode<T>*p = NULL;
		BSTNode<T>*q = root;
		while (q)//查找插入位置 最終肯定爲葉子
		{
			p = q;
			if (node.key == q->data.key)
			{
				return false;
			}
			if (node.key > q->data.key)
			{
				q = q->rightChild;
			}
			else
			{
				q = q->leftChild;
			}
		}
        //創建新節點保存插入元素
		q = new BSTNode<T>;
		q->data = node;//Element數據類型淺拷貝,若Element包含指針元素得重載=操作符
		q->leftChild = NULL;
		q->rightChild = NULL;
        //空樹的情況
		if (root == NULL)
		{
			root = q;
		}
		else
		{
			if (p->data.key > q->data.key)
			{
				p->leftChild = q;
			}
			else
			{
				p->rightChild = q;
			}
		}
		return true;
	}


//點展示樹左右子樹
//根據節點遞歸顯示左右子樹

	template<typename T>
	void BST<T>::display()
	{
		if (root == NULL)
		{
			cout << "樹爲空" << endl;
		}
		else
		{
			root->display(1);
		}
	}

	//查找節點 遞歸方法 
	//遞歸的部分需要傳入根節點(BSTNode)
	//外部以Element類型加載數據,故寫兩個函數,改爲一個Element端口
	template<typename T>
	BSTNode<T>*BST<T>::BST_Search(const Element<T>&node)
	{
		return BST_Search(root, node);
	}

	template<typename T>
	BSTNode<T>*BST<T>::BST_Search(BSTNode<T>*b, const Element<T>&node)
	{
		if (b == NULL)
		{
			return NULL;
		}
		if (node.key == b->data.key)
		{
			return b;
		}
		else if (node.key < b->data.key)
		{
			return BST_Search(b->leftChild, node);
		}
		else
		{
			return BST_Search(b->rightChild, node);
		}
	}
	
	//非遞歸查找 迭代方式實際中對大多數計算機更有效
	template<typename T>
	BSTNode<T>*BST<T>::BST_Search_Iterator(const Element<T>&node)
	{
		BSTNode<T>*t = root;
		while (t)
		{
			if (node.key == t->data.key)
			{
				return t;
			}
			else if (node.key < t->data.key)
			{
				t = t->leftChild;
			}
			else
			{
				t = t->rightChild;
			}
		}
	}

	//刪除節點
	template<typename T>
	bool BST<T>::Delete_Node(const Element<T>&node)
	{
		if (root == NULL)
		{
			cout << "root == NULL" << endl;
			return 0;
		}
		BSTNode<T> *del = NULL;
		BSTNode<T> *pcurr = root;
		BSTNode<T> *parent = NULL;
		while (pcurr != NULL && pcurr->data.key != node.key)//先找到
		{
			if (node.key < pcurr->data.key)
			{
				parent = pcurr;
				pcurr = pcurr->leftChild;
			}
			if (node.key > pcurr->data.key)
			{
				parent = pcurr;
				pcurr = pcurr->rightChild;
			}
		}
		if (pcurr == NULL)//找了一遍沒找到
		{
			return false;
		}
		if (pcurr->leftChild == NULL)//只有右孩子
		{
			if (pcurr == root)//如果是根節點 則根節點移動到右孩子即可
				root = root->rightChild;
			else if (pcurr == parent->leftChild)//若待刪節點是parent左孩子
			{
				parent->leftChild = pcurr->rightChild;
			}
			else if (pcurr == parent->rightChild)//若待刪除節點是parent右孩子
			{
				parent->rightChild = pcurr->rightChild;
			}
			del = pcurr;
		}
		else if (pcurr->rightChild == NULL)//只有左孩子
		{
			if (pcurr == root)
				root = root->leftChild;
			else if (pcurr == parent->leftChild)
			{
				parent->leftChild = pcurr->leftChild;
			}
			else
			{
				parent->rightChild = pcurr->leftChild;
			}
			del = pcurr;
		}
		else//既有左孩子又有右孩子 找到右子樹最小(最左)的元素替換,在按照以上方式刪除
		{
			//找到最左邊的節點
			BSTNode<T> *left = pcurr->rightChild;
			parent = pcurr;
			while (left->leftChild)
			{
				parent = left;
				left = left->leftChild;
			}
			del = left;
			pcurr->data.key = left->data.key;//交換節點的值
			if (parent->leftChild == left)
			{
				parent->leftChild = left->rightChild;
			}
			else//當pcurr只有一個右節點時,left是parent的右子樹
			{
				parent->rightChild = left->rightChild;
			}
		}
		delete del;
	}


	//中序遍歷
	template<typename T>
	void BST<T>::midOrder()
	{
		midOrder(root);
	}
	template<typename T>
	void BST<T>::midOrder(BSTNode<T>*root)
	{
		if (root == NULL)
		{
			return;
		}
		midOrder(root->leftChild);
		cout<<root->getElement().key<<" "<<root->getElement().name<<"\t";
		midOrder(root->rightChild);
	}

	//返回樹中最小的節點
	template<typename T>
	BSTNode<T>*	BST<T>::MinMum()
	{
		BSTNode<T>*tmp = root;
		while (tmp->leftChild)
		{
			tmp = tmp->leftChild;
		}
		return tmp;
	}

	//返回樹種最大的節點
	template<typename T>
	BSTNode<T>*	BST<T>::MaxMum()
	{
		BSTNode<T>*tmp = root;
		while (tmp->rightChild)
		{
			tmp = tmp->rightChild;
		}
		return tmp;
	}

template<typename T>
	BST<T>::~BST()
	{
		delTree(root);
	}
	template<typename T>
	void BST<T>::delTree(BSTNode<T>*root)
	{
		BSTNode<T>*tmpLeft = NULL;
		BSTNode<T>*tmpRight = NULL;
		while (root)
		{
			tmpLeft = root->leftChild;
			tmpRight = root->rightChild;
			delete root;
			delTree(tmpLeft);
			delTree(tmpRight);
		}
	}

測試文件

#include"dm_04_BST.hpp"
#include"iostream"
#include"cmath"
using namespace std;

void main()
{
	Element<int> a,b,c,d,e,f,g,h;
	BST<int> tree;
	a.key = 5; a.name = 'a'; cout << tree.BST_insert(a) << endl;
	b.key = 2; b.name = 'b'; cout << tree.BST_insert(b) << endl;
	c.key = 7; c.name = 'c'; cout << tree.BST_insert(c) << endl;
	d.key = 1; d.name = 'd'; cout << tree.BST_insert(d) << endl;
	e.key = 6; e.name = 'e'; cout << tree.BST_insert(e) << endl;
	f.key = 8; f.name = 'f'; cout << tree.BST_insert(f) << endl;
	g.key = 4; g.name = 'g'; cout << tree.BST_insert(g) << endl;
	h.key = 0; h.name = 'h'; cout << tree.BST_insert(h) << endl;
	//打印二叉樹,從根節點開始,遞歸打印左右	
	tree.display();

	cout << "遞歸搜索Key" << endl;
	cout<<tree.BST_Search(e)->getElement().key<<endl;

	cout << "迭代搜索Key" << endl;
	cout << tree.BST_Search_Iterator(e)->getElement().key<<endl;

	cout << "搜索二叉樹中序遍歷恰好是從小到大" << endl;
	tree.midOrder();

	cout << "二叉搜索樹中鍵值最大的" << endl;
	Element<int> max = tree.MaxMum()->getElement();
	cout << "key: " << max.key << " name: " << max.name << endl;
	cout << "二叉搜索樹中鍵值最小的" << endl;
	Element<int> min = tree.MinMum()->getElement();
	cout << "key: " << min.key << " name: " << min.name << endl;

	cout <<endl<< "刪除節點d" << endl;
	tree.Delete_Node(d);
	tree.midOrder();
	cout << endl;
	system("pause");
}

 

測試運行結果

缺點:

二叉搜索樹,在一定條件下會退化爲鏈表,失去二叉搜索樹的優點,構建二叉搜索樹應當隨機構建二叉搜索樹,n個節點n!中排序,每一種排序等概。

平衡二叉樹紅黑樹可以解決這個問題,有時間在努力封裝一下紅黑樹吧。

有些頹廢,希望自己能珍惜時間。

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