#include<iostream>
#include<stack>
using namespace std;
typedef int ELEMENT_TYPE;
//定義樹的結點
typedef struct Node{
ELEMENT_TYPE data;
struct Node *lchild,*rchild;
int ltag,rtag;// 如果ltag=0,有左子樹lchild指向左子樹的根節點;如果ltag=1,lchild指向前驅
}BNode;
//定義樹的根節點,(全局變量)默認NULL
BNode* root;
// 向樹中插入結點,構造二叉排序樹
void InsertNodeToCreateTree(ELEMENT_TYPE element){
//構造根節點
if(root==NULL){
root=new BNode();
root->data=element;
root->rchild=NULL;
root->lchild=NULL;
}
else{
BNode* parentNode=root; //當前結點的父結點
BNode* currentNode=root; //當前結點
//構造新的結點
BNode* newNode=new BNode();
newNode->data=element;
newNode->lchild=NULL;
newNode->rchild=NULL;
while(currentNode!=NULL){
parentNode=currentNode;
if(currentNode->data>element){
currentNode=currentNode->lchild;
}
else
currentNode=currentNode->rchild;
}
if(parentNode->data>element)
parentNode->lchild=newNode;
else
parentNode->rchild=newNode;
}
}
//先序遞歸遍歷二叉樹
void PreOrder(BNode* p){
if(p!=NULL){
cout<<p->data<<" ";
PreOrder(p->lchild);
PreOrder(p->rchild);
}
}
//先序非遞歸遍歷二叉樹
void PreOrderF(){
BNode* p=root;
stack<BNode*> stack; //定義存放結點的棧
while(!(p==NULL && stack.empty())){
if(p!=NULL){
cout<<p->data<<" ";
if(p->rchild!=NULL) //如果右子樹不爲空則進棧
stack.push(p);
p=p->lchild;
}
else{
p=stack.top()->rchild;
stack.pop();
}
}
cout<<endl;
}
//中序遞歸遍歷二叉樹
void MiddleOrder(BNode* p){
if(p!=NULL){
MiddleOrder(p->lchild);
cout<<p->data<<" ";
MiddleOrder(p->rchild);
}
}
//中序非遞歸遍歷二叉樹
void MiddleOrderF(){
BNode* p=root;
stack<BNode*> stack;
while(!(p==NULL && stack.empty())){
//當前結點不爲空則進棧
if(p!=NULL){
stack.push(p);
p=p->lchild;
}
else{
p=stack.top();
stack.pop();
cout<<p->data<<" ";
p=p->rchild;
}
}
cout<<endl;
}
//後序遞歸遍歷二叉樹
void PostOrder(BNode* p){
if(p!=NULL){
PostOrder(p->lchild);
PostOrder(p->rchild);
cout<<p->data<<" ";
}
}
//後序非遞歸遍歷二叉樹
void PostOrderF(){
BNode* p=root;
BNode* pre=NULL; //指向當前訪問節點的前驅結點
stack<BNode*> stack;
while(!(p==NULL && stack.empty())){
if(p!=NULL){
stack.push(p);
pre=p;
p=p->lchild;
}
else{
p=stack.top(); //取得棧頂元素
//如果p的右子樹不爲空並且沒有訪問過,則訪問右子樹
if(p->rchild!=NULL && p->rchild!=pre){
pre=p;
p=p->rchild;
}
//如果右子樹爲空或者已經訪問過,則訪問當前結點
else{
cout<<p->data<<" ";
stack.pop(); //右子樹爲空,或則已經訪問過,則訪問了當前結點後直接出棧
pre=p;
p=NULL; //爲下一輪遍歷準備
}
}
}
}
// 二叉排序樹上刪除元素
void DeleteNode(ELEMENT_TYPE element){
int flag=0; //0表示當前結點在其父結點的左子樹上,1表示在其父結點的右子樹上
if(root==NULL){
cout<<"錯誤,二叉樹爲空"<<endl;
}
else{
BNode* currentNode=root;
BNode* parentNode=NULL;
while(currentNode->data!=element){
parentNode=currentNode;
if(currentNode->data>element)
{
flag=0;
currentNode=currentNode->lchild;
}
else
{
flag=1;
currentNode=currentNode->rchild;
}
}
// 如果找到了指定元素的結點
if(currentNode->data==element){
if(flag==0) //當前結點在其父節點的左子樹上
{
//判斷當前結點的子樹的情況:
//當前結點爲葉子結點
if(currentNode->lchild==NULL && currentNode->rchild==NULL){
parentNode->lchild=NULL;
}
// 當前結點只有左子樹
if(currentNode->lchild!=NULL && currentNode->rchild==NULL){
parentNode->lchild=currentNode->lchild;
}
// 當前結點只有右子樹
if(currentNode->lchild==NULL && currentNode->rchild!=NULL){
parentNode->lchild=currentNode->rchild;
}
// 當前結點有左,右子樹
if(currentNode->lchild!=NULL && currentNode->rchild!=NULL){
parentNode->lchild=currentNode->rchild;
BNode* rnode=currentNode->rchild;
BNode* lnode=currentNode->lchild;
//查找右子樹的最左結點
while(rnode->lchild!=NULL)
rnode=rnode->lchild;
rnode->lchild=lnode;
}
}
if(flag==1) //當前結點在其父節點的右子樹上
{
//判斷當前結點的子樹的情況:
//當前結點爲葉子結點
if(currentNode->lchild==NULL && currentNode->rchild==NULL){
parentNode->rchild=NULL;
}
// 當前結點只有左子樹
if(currentNode->lchild!=NULL && currentNode->rchild==NULL){
parentNode->rchild=currentNode->lchild;
}
// 當前結點只有右子樹
if(currentNode->lchild==NULL && currentNode->rchild!=NULL){
parentNode->rchild=currentNode->rchild;
}
// 當前結點有左,右子樹
if(currentNode->lchild!=NULL && currentNode->rchild!=NULL){
parentNode->rchild=currentNode->rchild;
BNode* rnode=currentNode->rchild;
BNode* lnode=currentNode->lchild;
//查找右子樹的最左結點
while(rnode->lchild!=NULL)
rnode=rnode->lchild;
rnode->lchild=lnode;
}
}
delete currentNode;
}
// 如果沒有找到指定元素的結點
else{
cout<<"指定元素的結點不存在"<<endl;
}
}
}
// 中序遞歸線索二叉樹,注意第一個結點後最後一個結點(第一個沒有前驅,最後一個沒有後繼) 這兩個特殊情況
/*
* pre 表示中序遍歷事當前結點的前驅結點
*
*/
BNode* order_pre=NULL;
void InorderLining(BNode* p){
if(p!=NULL){
InorderLining(p->lchild);
if(p->lchild==NULL){
p->ltag=1;
p->lchild=order_pre;//左節點指向根節點
}
if(order_pre!=NULL && order_pre->rchild==NULL)
{
order_pre->rtag=1;
order_pre->rchild=p;
}
order_pre=p;
InorderLining(p->rchild);
}
}
// 根據中序線索化之後查找某個元素值結點的前驅和後繼
//需要注意的是,當對二叉樹進行線索化之後,結點的指針域發生了變化,原來有效的指針的條件都是tag==0
void FindPreAndPost(ELEMENT_TYPE element){
if(root==NULL){
cout<<"錯誤,二叉樹爲空"<<endl;
}
else{
BNode* currentNode=root;
while(currentNode!=NULL &¤tNode->data!=element){
if(currentNode->ltag==1 && currentNode->rtag==1) //實際上是原先的葉子結點
break;
if(currentNode->data>element && currentNode->ltag==0)
currentNode=currentNode->lchild;
if(currentNode->data<element && currentNode->rtag==0)
currentNode=currentNode->rchild;
}
// 如果找到了指定元素的結點
if(currentNode!=NULL &¤tNode->data==element){
cout<<"當前結點的值:"<<element<<" ";
if(currentNode->ltag==1)
{
if(currentNode->lchild!=NULL)
cout<<"前驅是:"<<currentNode->lchild->data<<" ";
else
cout<<"前驅爲空"<<" ";
}
//如果左子樹不爲空的話,則當前結點的前驅爲其左子樹的“最右下方”結點
else{
BNode* lnode=currentNode->lchild;
while(lnode->rchild!=NULL && lnode->ltag==0)
lnode=lnode->rchild;
cout<<"前驅是:"<<lnode->data<<" ";
}
if(currentNode->rtag==1)
{
if(currentNode->rchild!=NULL)
cout<<"後繼是:"<<currentNode->rchild->data<<" ";
}
//如果右子樹不爲空的話,則當前結點的後繼爲其右子樹樹的“最左下方”結點
else{
if(currentNode->rchild==NULL) //如果是中序遍歷,線索化之後的最後一個結點沒有後繼
cout<<"後繼爲空";
else
{
BNode* rnode=currentNode->rchild;
while(rnode->lchild!=NULL && rnode->ltag==0)
rnode=rnode->lchild;
cout<<"後繼是:"<<rnode->data<<" ";
}
}
}
else
cout<<"該節點不存在"<<endl;
}
cout<<endl;
}
//注意,對於程序中對二叉樹的遍歷的時候並沒有考慮線索化,所以針對排序二叉樹的建立,結點刪除,以及各種
//遍歷可以單獨測試
void test01(){
//插入結點創建排序二叉樹
InsertNodeToCreateTree(36);
InsertNodeToCreateTree(57);
InsertNodeToCreateTree(25);
InsertNodeToCreateTree(18);
InsertNodeToCreateTree(30);
InsertNodeToCreateTree(68);
InsertNodeToCreateTree(60);
InsertNodeToCreateTree(59);
InsertNodeToCreateTree(58);
InsertNodeToCreateTree(65);
InsertNodeToCreateTree(63);
InsertNodeToCreateTree(67);
InsertNodeToCreateTree(62);
InsertNodeToCreateTree(64);
//先序遍歷樹
PreOrder(root);
cout<<endl;
PreOrderF();
//中序遍歷樹
MiddleOrder(root);
cout<<endl;
MiddleOrderF();
//後序遍歷樹
PostOrder(root);
cout<<endl;
PostOrderF();
cout<<endl;
//刪除結點
DeleteNode(62);
//遍歷樹
PreOrder(root);
cout<<endl;
PreOrderF();
MiddleOrder(root);
cout<<endl;
MiddleOrderF();
//後序遍歷樹
PostOrder(root);
cout<<endl;
PostOrderF();
cout<<endl;
}
void test02(){
//插入結點創建排序二叉樹
InsertNodeToCreateTree(36);
InsertNodeToCreateTree(57);
InsertNodeToCreateTree(25);
InsertNodeToCreateTree(18);
InsertNodeToCreateTree(30);
InsertNodeToCreateTree(68);
InsertNodeToCreateTree(60);
InsertNodeToCreateTree(59);
InsertNodeToCreateTree(58);
InsertNodeToCreateTree(65);
InsertNodeToCreateTree(63);
InsertNodeToCreateTree(67);
InsertNodeToCreateTree(62);
InsertNodeToCreateTree(64);
//先序遍歷樹
PreOrder(root);
cout<<endl;
PreOrderF();
//中序遍歷樹
MiddleOrder(root);
cout<<endl;
MiddleOrderF();
//線索化二叉樹
InorderLining(root);
//找前驅後繼結點:
FindPreAndPost(18);
FindPreAndPost(30);
FindPreAndPost(68);
FindPreAndPost(65);
FindPreAndPost(67);
FindPreAndPost(62);
FindPreAndPost(64);
FindPreAndPost(55);
}
int main(){
test01();
//test02();
system("pause");
return 0;
}
二叉排序樹的創建,刪除結點;樹的前序,中序,後序非遞歸遍;二叉樹的線索化
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.