最近在研究數據結構這本書,自己動手實現的一個二叉查找排序樹的類BinSortTree,實現數據的插入,查找,刪除,層序遍歷,中序遍歷等操作,熟悉數據結構的朋友都知道,根據二叉排序樹的定義,中序遍歷後得到的序列就是按照從小到大的順序排列的,而最後刪除二叉排序樹的時候,要先刪除子節點,才能刪除父節點,其實就是一個後續遍歷的過程。現在把代碼分享一下,供大家參考學習。其實這個跟stl的set容器已經十分相似,只是set使用查找性能更優越的紅黑樹來實現
BinSortTree.h
//二叉排序樹的類,實現插入數據,查找數據,插入數據、刪除數據
#include <iostream>
//定義節點結構體
class Node
{
public:
int nData;//數據
Node *pLeftChild;//左子樹
Node *pRightChild;//右子樹
Node(int nData):pLeftChild(NULL),pRightChild(NULL),nData(nData)
{
}
};
//定義排序樹的類
class BinSortTree
{
public:
BinSortTree();
~BinSortTree();//在析構函數中釋放所有分配的節點
bool Insert(int nData);//插入一個節點
bool Erase(int nErase);//根據關鍵字刪除節點
int GetSize() { return m_nSize;}
//根據關鍵字查找指定的節點,如果找到了,則返回該節點的指針
//如果沒有找到,返回NULL
Node* Find(int nFind);
void Traversal(int nType = 0);//遍歷二叉樹,,0爲中序遍歷,1爲層序遍歷
private:
Node *m_pRoot;//根節點
int m_nSize;//節點的個數
private:
void DeleteNode(Node *pNode);
void InorderTraversal(Node *pNode);//中序遍歷二叉樹
void LevelOrderTraversal(Node *pNode);//層序遍歷
bool Erase(Node **pRoot,int nData);
};
BinSortTree.cpp
#include <iostream>
#include <set>
#include <queue>
#include "BinSortTree.h"
using namespace std;
BinSortTree::BinSortTree()
{
m_pRoot = NULL;
m_nSize = 0;
}
BinSortTree::~BinSortTree()
{
//析構每一個節點
if (NULL != m_pRoot)
{
DeleteNode(m_pRoot);
}
}
void BinSortTree::DeleteNode(Node *pNode)
{
//檢查該節點是否存在左子樹或者右子樹,如果有,遞歸調用刪除
if (NULL != pNode->pLeftChild)
{
DeleteNode(pNode->pLeftChild);
}
if (NULL != pNode->pRightChild)
{
DeleteNode(pNode->pRightChild);
}
cout << "刪除節點:" << pNode->nData << endl;
delete pNode;
}
Node* BinSortTree::Find(int nFind)
{
Node *pTemp = m_pRoot;
//類似於二分查找
while(pTemp != NULL)
{
if (nFind == pTemp->nData)
{
//說明已經找到,返回這個指針
return pTemp;
}
else if (nFind < pTemp->nData)
{
//從左子樹中查找
pTemp = pTemp->pLeftChild;
}
else
{
pTemp = pTemp->pRightChild;
}
}
return NULL;
}
bool BinSortTree::Insert(int nData)
{
Node *pPre = m_pRoot;
Node *pNext = m_pRoot;
//先在樹中查找,如果找到了就返回,如果沒有找到,則在最後一個節點插入
while(pNext != NULL)
{
pPre = pNext;
if (nData == pNext->nData)
{
return false;
}
else if (nData < pNext->nData)
{
pNext = pNext->pLeftChild;
}
else
{
pNext = pNext->pRightChild;
}
}
//說明沒有找到,則插入一個新節點
Node* pNew = new Node(nData);
//如果是一棵空樹,則直接插入
if (m_pRoot == NULL)
{
m_pRoot = pNew;
++m_nSize;//節點數加1
return true;
}
//如果不是一棵空樹,判斷是插入到最後一個節點的左子樹還是右子樹
if (nData < pPre->nData)
{
pPre->pLeftChild = pNew;
}
else
{
pPre->pRightChild = pNew;
}
++m_nSize;
return true;
}
bool BinSortTree::Erase(int nData)
{
return Erase(&m_pRoot, nData);
}
bool BinSortTree::Erase(Node **pRoot, int nData)
{
Node **pPre = pRoot;//保存指向刪除節點指針的指針,便於以後修改
Node *pFind = *pRoot;
//先在樹中查找
while(pFind != NULL)
{
if (nData == pFind->nData)
{
break;
}
else if (nData < pFind->nData)
{
pPre = &pFind->pLeftChild;
pFind = pFind->pLeftChild;
}
else
{
pPre = &pFind->pRightChild;
pFind = pFind->pRightChild;
}
}
if (NULL == pFind)
{
return false;
}
/******分四種情況******/
//1、如果要刪除的節點沒有子節點
if (pFind->pLeftChild == NULL && pFind->pRightChild == NULL)
{
//直接刪除該節點
delete pFind;
--m_nSize;//節點數減1
//將指向該節點的指針置空
*pPre = NULL;
return true;
}
//2、如果要刪除的節點只有左孩子節點
if (NULL != pFind->pLeftChild && NULL == pFind->pRightChild)
{
//被刪除節點的雙親節點重新指向被刪除節點的左孩子節點
*pPre = pFind->pLeftChild;
//刪除節點
delete pFind;
--m_nSize;//節點數減1
return true;
}
//3、如果要刪除的節點只有右孩子節點
if (NULL == pFind->pLeftChild && NULL != pFind->pRightChild)
{
//被刪除節點的雙親節點重新指向被刪除節點的右孩子節點
*pPre = pFind->pRightChild;
//刪除節點
delete pFind;
--m_nSize;//節點數減1
return true;
}
//4、如果要刪除的節點有左右孩子節點
if (NULL != pFind->pLeftChild && NULL != pFind->pRightChild)
{
//找出關鍵字值大於被刪除節點的關鍵字值中的最小值,即尋找被刪除節點右子樹中的最左值
Node *pTarget = pFind->pRightChild;//最左值的指針
Node *pNext = pFind->pRightChild;
while(NULL != pNext)
{
pTarget = pNext;
pNext = pTarget->pLeftChild;
}
//交換最左節點和被刪除節點的值
pFind->nData = pTarget->nData;
//以被刪除節點的右節點爲根節點,最左節點關鍵字的值爲刪除目標,再次調用刪除函數
return Erase(&pFind->pRightChild, pTarget->nData);
}
}
void BinSortTree::Traversal(int nType)
{
if (0 == nType)
{
//中序遍歷二叉樹
InorderTraversal(m_pRoot);
}
else if (1 == nType)
{
LevelOrderTraversal(m_pRoot);
}
}
void BinSortTree::InorderTraversal(Node *pNode)
{
if (pNode == NULL)
{
return;
}
//先遍歷左子樹
if (NULL != pNode->pLeftChild)
{
InorderTraversal(pNode->pLeftChild);
}
//訪問根節點
cout << pNode->nData << endl;
//遍歷右子樹
if (NULL != pNode->pRightChild)
{
InorderTraversal(pNode->pRightChild);
}
}
//層序遍歷二叉樹
void BinSortTree::LevelOrderTraversal(Node *pNode)
{
if (pNode == NULL)
{
return;
}
//層序遍歷需要一個隊列保存未訪問節點,按從根層到底層的順序邊淋(從上到下,從左到右)
queue<Node*> que;
que.push(pNode);
while (!que.empty())
{
//訪問節點
Node *p = que.front();
que.pop();//出隊列
cout << p->nData << endl;//訪問節點
if (NULL != p->pLeftChild)
{
que.push(p->pLeftChild);
}
if (NULL != p->pRightChild)
{
que.push(p->pRightChild);
}
}
}
main.cpp
#include <iostream>
#include "BinSortTree.h"
using namespace std;
int main()
{
BinSortTree tree;
tree.Insert(10);
tree.Insert(1);
tree.Insert(11);
tree.Insert(11);
tree.Insert(-1);
tree.Insert(99);
cout << "*************中序遍歷二叉樹(刪除前)**********" << endl;
tree.Traversal();
tree.Erase(10);
Node *pNode = tree.Find(10);
if (NULL != pNode)
{
cout << "找到節點:" << pNode->nData << endl;
}
cout << "*************中序遍歷二叉樹(刪除後)**********" << endl;
tree.Traversal();
//cout << "*************層序遍歷二叉樹**********" << endl;
//tree.Traversal(1);
return 0;
}