github地址:https://github.com/lining91/BinTree
本文實現了二叉查找樹的前序遍歷(遞歸與非遞歸)、中序遍歷(遞歸與非遞歸)、後序遍歷(遞歸與非遞歸)、插入過程、刪除過程、查找過程等。
二叉樹的簡單介紹:
1、二叉樹中的每個節點都不能有多餘兩個的兒子。
2、二叉樹的深度要比N小得多。
假設每個節點被指定一個關鍵字值(所有關鍵字是整數、互異的)。
二叉查找樹的性質:
1、左子樹的所有節點值均小於根節點值。
2、右子樹的所有節點值均大於根節點值。
3、左右子樹都滿足上述兩個條件。
插入過程:
1、若當前二叉樹爲空,則插入的元素爲根節點。
2、若插入的元素值小於根節點值,則遞歸從根節點的左子樹中找到可插入位置。
3、若插入的元素值大於根節點值,則遞歸從根節點的右子樹中找到可插入位置。
刪除過程:
1、待刪除節點Z爲葉子節點,則直接刪除該節點。修改父節點的指針。
2、待刪除節點Z爲單支節點(只有左子樹或者右子樹),讓Z的子樹與Z的父節點相連,刪除節點Z。
3、待刪除節點Z左右子樹都不爲空。
方法一:找到Z的後繼節點y,因爲y一定沒有左子樹,所以可以直接刪除y,並讓y的父親節點成爲y的右子樹的父親節點。用y替換Z。
方法二:找到Z的前驅節點x,x一定沒有右子樹,所以可以直接刪除x,並讓x的父親節點成爲x的左子樹的父親節點。用x替換Z。
查找過程:
1、若待查找的元素值和根節點相同,則返回根節點。
2、若待查找的元素值小於根節點的元素值,則遞歸從根節點的左子樹中查找。
3、若待查找的元素值大於根節點的元素值,則遞歸從根節點的右子樹中查找。
遍歷過程:
1、前序遍歷(遞歸和非遞歸兩種):先根節點,後左孩子節點,再右孩子結點。
2、中序遍歷(遞歸和非遞歸兩種):先左孩子結點,後根節點,再右孩子結點。
3、後序遍歷(遞歸和非遞歸兩種):先做孩子節點,後右孩子結點,再根節點。
獲取最大元素的節點:
1、如果根節點無右子樹,則返回根節點。
2、依次查詢根節點的右子樹節點,返回右子樹的最後一個右節點。
獲取最小元素的節點:
1、如果根節點無左子樹,則返回根節點。
2、依次查詢跟節點的左子樹節點,返回左子樹的最後一個左節點。
依次插入數據(15,3,20,8,10,18,6,1,26)之後的二叉樹結構如下:
代碼如下:
#include <iostream>
#include <stack>
using namespace std;
typedef struct STreeNode* pSTreeNode;
typedef int TreeKeyType;
struct STreeNode
{
TreeKeyType key;
pSTreeNode pLeftChild;
pSTreeNode pRightChild;
STreeNode( TreeKeyType Value )
{
key = Value;
pLeftChild = NULL;
pRightChild = NULL;
}
};
class CBinTree
{
public:
CBinTree();
~CBinTree();
void Insert( TreeKeyType Value );
void Insert( pSTreeNode pNode, TreeKeyType Value );
pSTreeNode Search( TreeKeyType Value );
pSTreeNode Search( pSTreeNode pNode, TreeKeyType Value );
void Delete( TreeKeyType Value );
void Preorder( ); // 前序遍歷,非遞歸方法(借用堆棧)
void Inorder( ); // 中序遍歷,非遞歸方法(借用堆棧)
void Postorder( ); // 後序遍歷,非遞歸方法(借用堆棧)
void PreorderRecursively( pSTreeNode pNode ); // 前序遍歷,遞歸調用
void InorderRecursively( pSTreeNode pNode ); // 中序遍歷,遞歸調用
void PostorderRecursively( pSTreeNode pNode ); // 後序遍歷,遞歸調用
pSTreeNode GetMaxKey(); // 獲得二叉查找樹中元素值最大的節點
pSTreeNode GetMinKey(); // 獲得二叉查找樹中元素值最小的節點
void FreeMemory( pSTreeNode pNode ); // 釋放內存
public:
pSTreeNode pRoot;
};
CBinTree::CBinTree()
{
pRoot = NULL;
}
CBinTree::~CBinTree()
{
if ( pRoot == NULL )
return;
FreeMemory( pRoot );
}
void CBinTree::FreeMemory( pSTreeNode pNode )
{
if ( pNode == NULL )
return;
if ( pNode->pLeftChild != NULL )
FreeMemory( pNode->pLeftChild );
if ( pNode->pRightChild != NULL )
FreeMemory( pNode->pRightChild );
delete pNode;
pNode = NULL;
}
void CBinTree::Insert( TreeKeyType Value )
{
if ( pRoot == NULL )
pRoot = new STreeNode( Value );
else
Insert( pRoot, Value );
}
void CBinTree::Insert( pSTreeNode pNode, TreeKeyType Value )
{
if ( pNode->key > Value )
{
if ( pNode->pLeftChild == NULL)
pNode->pLeftChild = new STreeNode( Value );
else
Insert( pNode->pLeftChild, Value );
}
else
{
if ( pNode->pRightChild == NULL)
pNode->pRightChild = new STreeNode( Value );
else
Insert( pNode->pRightChild, Value );
}
}
pSTreeNode CBinTree::Search( TreeKeyType Value )
{
return Search( pRoot, Value );
}
pSTreeNode CBinTree::Search( pSTreeNode pNode, TreeKeyType Value )
{
if ( pNode == NULL )
return NULL;
if ( pNode->key == Value )
return pNode;
else
{
if ( pNode->key > Value )
return Search( pNode->pLeftChild, Value );
else
return Search( pNode->pRightChild, Value );
}
}
void CBinTree::Delete( TreeKeyType Value )
{
pSTreeNode pParentNode = pRoot;
pSTreeNode pFindNode = pRoot;
// 找到Value元素對應的節點
while ( pFindNode != NULL )
{
if ( pFindNode->key == Value )
break;
pParentNode = pFindNode;
if ( pFindNode->key > Value )
pFindNode = pFindNode->pLeftChild;
else
pFindNode = pFindNode->pRightChild;
}
if ( pFindNode == NULL )
return;
// 處理Value元素的父節點和Value元素的節點
if ( pFindNode->pLeftChild == NULL || pFindNode->pRightChild == NULL )
{
// 一個子結點爲空或者兩個子結點都爲空
pSTreeNode pTemp = NULL;
if ( pFindNode->pLeftChild != NULL)
pTemp = pFindNode->pLeftChild;
else if ( pFindNode->pRightChild != NULL )
pTemp = pFindNode->pRightChild;
if ( pParentNode->pLeftChild == pFindNode )
pParentNode->pLeftChild = pTemp;
else
pParentNode->pRightChild = pTemp;
delete pFindNode;
pFindNode = NULL;
}
else
{
// 找到前驅節點
pSTreeNode pTemp = pFindNode->pLeftChild;
pSTreeNode pTempParent = pFindNode;
while ( pTemp->pRightChild != NULL )
{
pTempParent = pTemp;
pTemp = pTemp->pRightChild;
}
pFindNode->key = pTemp->key;
pTempParent->pRightChild = NULL;
delete pTemp;
pTemp = NULL;
}
}
void CBinTree::Preorder( )
{
if ( pRoot == NULL )
{
cout << "二叉樹爲空!" << endl;
return;
}
stack<pSTreeNode> StackTree;
pSTreeNode pNode = pRoot;
while( pNode != NULL || !StackTree.empty())
{
while ( pNode != NULL )
{
cout << " " << pNode->key << " ";
StackTree.push(pNode);
pNode = pNode->pLeftChild;
}
pNode = StackTree.top();
StackTree.pop();
pNode = pNode->pRightChild;
}
}
void CBinTree::Inorder( )
{
if ( pRoot == NULL )
{
cout << "二叉樹爲空!" << endl;
return;
}
stack<pSTreeNode> StackTree;
pSTreeNode pNode = pRoot;
while ( pNode != NULL || !StackTree.empty() )
{
while ( pNode != NULL )
{
StackTree.push( pNode );
pNode = pNode->pLeftChild;
}
pNode = StackTree.top();
StackTree.pop();
cout << " " << pNode->key << " ";
pNode = pNode->pRightChild;
}
}
// 藉助變量visited表示是否訪問過該根節點。訪問過的話,這輸出。
void CBinTree::Postorder( )
{
if ( pRoot == NULL )
{
cout << "二叉樹爲空!" << endl;
return;
}
stack< pair<pSTreeNode, bool>> StackTree;
StackTree.push( make_pair( pRoot, false ));
while ( !StackTree.empty() )
{
pSTreeNode pNode = StackTree.top().first;
bool bVisited = StackTree.top().second;
if (pNode == NULL)
{
StackTree.pop();
continue;
}
if (bVisited)
{
cout << " " << pNode->key << " ";
StackTree.pop();
}
else
{
StackTree.top().second = true;
StackTree.push( make_pair( pNode->pRightChild, false));
StackTree.push( make_pair( pNode->pLeftChild, false));
}
}
}
void CBinTree::PreorderRecursively( pSTreeNode pNode )
{
if (pNode == NULL)
return;
cout << " " << pNode->key << " ";
PreorderRecursively( pNode->pLeftChild );
PreorderRecursively( pNode->pRightChild );
}
void CBinTree::InorderRecursively( pSTreeNode pNode )
{
if (pNode == NULL)
return;
InorderRecursively( pNode->pLeftChild );
cout << " " << pNode->key << " ";
InorderRecursively( pNode->pRightChild );
}
void CBinTree::PostorderRecursively( pSTreeNode pNode )
{
if (pNode == NULL)
return;
PostorderRecursively( pNode->pLeftChild );
PostorderRecursively( pNode->pRightChild );
cout << " " << pNode->key << " ";
}
int main()
{
CBinTree* pBinTree = new CBinTree();
if ( pBinTree == NULL )
return 0;
pBinTree->Insert( 15 );
pBinTree->Insert( 3 );
pBinTree->Insert( 20 );
pBinTree->Insert( 8 );
pBinTree->Insert( 10 );
pBinTree->Insert( 18);
pBinTree->Insert( 6 );
pBinTree->Insert( 1);
pBinTree->Insert( 26);
pSTreeNode pRoot = pBinTree->pRoot;
cout << " 非遞歸前序遍歷 :" ;
pBinTree->Preorder();
cout << endl;
cout << " 遞歸前序遍歷 :" ;
pBinTree->PreorderRecursively( pRoot );
cout << endl;
cout << " 非遞歸中序遍歷 :" ;
pBinTree->Inorder();
cout << endl;
cout << " 遞歸中序遍歷 :" ;
pBinTree->InorderRecursively( pRoot );
cout << endl;
cout << " 非遞歸後序遍歷 :" ;
pBinTree->Postorder();
cout << endl;
cout << " 遞歸後續遍歷 :";
pBinTree->PostorderRecursively( pRoot );
cout << endl;
pSTreeNode pMaxNode = pBinTree->GetMaxKey();
pSTreeNode pMinNode = pBinTree->GetMinKey();
if ( pMaxNode != NULL )
cout << " 該二叉查找樹的最大元素是:" << pMaxNode->key << endl;
if (pMinNode != NULL )
cout << " 該二叉查找樹的最小元素是:" << pMinNode->key << endl;
TreeKeyType DeleteKey = 15;
pSTreeNode pSearchNode = pBinTree->Search( DeleteKey );
if ( pSearchNode != NULL )
cout << " 需要查詢的元素是:" << DeleteKey << ", 實際查詢到的元素是:" << pSearchNode->key << endl;
else
cout << " 沒有查詢到元素" << DeleteKey << endl;
pBinTree->Delete( DeleteKey );
cout << " 刪除元素" << DeleteKey << "之後的遞歸前序遍歷:";
pBinTree->PreorderRecursively( pRoot );
cout << endl;
DeleteKey = 1;
pBinTree->Delete( DeleteKey );
cout << " 刪除元素" << DeleteKey << "之後的遞歸前序遍歷:";
pBinTree->PreorderRecursively( pRoot );
cout << endl;
DeleteKey = 8;
pBinTree->Delete( DeleteKey );
cout << " 刪除元素" << DeleteKey << "之後的遞歸前序遍歷:";
pBinTree->PreorderRecursively( pRoot );
cout << endl;
DeleteKey = 26;
pBinTree->Delete( DeleteKey );
cout << " 刪除元素" << DeleteKey << "之後的遞歸前序遍歷:";
pBinTree->PreorderRecursively( pRoot );
cout << endl;
delete pBinTree;
pBinTree = NULL;
system( "pause" );
return 1;
}
運行結果如下: