二叉樹的算法與講法
二叉樹屬於數據結構中層次性的數據關系,他又祖先——後代,上級——下屬,總體——部分以及其它類似的關系,樹結構在計算機領域中有著廣泛的應用。比如在編譯程序中庸語法樹來表示元程序的語言結構。在數據挖掘中庸決策樹來進行數據分類等等。在我的前一個博客中也有提到就是二叉樹的相關知識重點。不清楚的同行能夠參考我的文章。當中若有不妥之處,還請大家指點。
以下是我在學習二叉樹的時候編寫的二叉樹的幾個常見的功能的函數,以及他的一些構造函數等等。
#ifndef BITREE_H
#define BITREE_H
#include<iostream>
#include<iomanip>
using namespace std;
template <typename T>
struct BiNode
{
T data;
BiNode<T> *lchild, *rchild; //利用遞歸的方法進行結點的構造
};
template<typename T>
class BiTree
{
template<typename T>
friend ostream & operator<<(ostream &os, BiTree<T> &bt);
public:
BiTree(T none); //構造一個空的二叉樹
BiTree(T ary[], int num, T none); //構造一個num個結點的二叉樹
~BiTree(); //析構函數
void Parent(T x); //與pretected中的ParentIn相應
void print(ostream &os); //遍歷操作
void Count(); //與protected中的CountIn相應
void PreOrderPrint(); //與protected中的PreOrderPrintIn相應
void Depth(); //與protected中的DepthIn相應
void PostOrderN(); //與protected中的PostOrderN相應
void Delete(T x); //與pretected中的DeleteIn相應
protected:
void CountIn(BiNode<T> *root);
void Creat(BiNode<T> * &root, T none);
BiNode<T> *Build(T ary[], int num, T none, int idx);
BiNode<T> *ParentIn(BiNode<T> * root, T x); //查詢某結點的雙
親
void Release(BiNode<T>* &root);
void printIn(ostream &os, BiNode<T> *root, int depth); //和上述的四個函數
具有相應的功能
void PreOrderPrintIn(BiNode<T> *root); //求二叉樹的葉子節
點輸出
int DepthIn(BiNode<T> *root); //求二叉樹的深度
void PostOrderNIn(BiNode<T> *root); //求二叉樹的逆後
序輸出遍歷的算法
void DeleteIn(BiNode<T> * root, T x); //求二叉樹的刪除
的算法
private:
BiNode<T> *p = NULL;
BiNode<T> *rootPtr; //申請一個跟指針
int count = 0; //全局變量在Count函數中用
int highl = 0,highr=0; //全局變量在Depth函數中用
};
template<typename T>
void BiTree<T>::CountIn(BiNode<T> *root)
{
if (root != NULL)
{
CountIn(root->lchild);
count++;
CountIn(root->rchild);
/*在左右之間count++是在左子數遞歸結束之時才加
在最後一個左子數結束的時候就是+*/
}
}
template<typename T>
void BiTree<T>::Creat(BiNode<T> * &root, T none) //子數的創建
{
T x;
cout << "請輸入(" << none << "表示空):"; cin >> x;
if (x == none)
root == NULL; //假設輸入的是空的話,那麽這個二叉樹
就是空二叉樹
else //以下準備實現元素的插入
{
root = new BiNode<T>; //首先讓根指針變為根結點
root->data = x; //對結點進行賦值
Creat(root->lchild, none); //創建根結點的左子數,此時左子數為空
Creat(root->rchild, none); //創建根結點的右子數。此時右子數為空
} //當前結點賦值成功,且其子數創建也成功
} //次函數不是循環創建,僅僅是在根結點進行賦值與
子數的創建,以下的操作靠其它
template<typename T>
BiNode<T> *BiTree<T>::Build(T ary[], int num, T none, int idx)
{
/*ary就表示數組,num表示數組長度。none表示空,idx表示結點的序號
在進行第一次操作的時候理所應當的賦值為1*/
BiNode<T> *p; //申請指針p
int left, right; //定義左右
if (idx - 1 < num&&ary[idx - 1] != none)//為什麽此處是idx-1呢????
{
/*由於數組從0開始,又為了idx可以按倍數增長,所以idx從一開始
則在推斷的時候自然就要減去一了,方便後面的賦值*/
p = new BiNode<T>; //將指針p結點劃
p->data = ary[idx - 1]; //將該結點的數值部分賦值為數組中相應
的元素
left = 2 * idx;
right = 2 * idx + 1; //確保了左右子數的左右性
p->lchild = Build(ary, num, none, left);
p->rchild = Build(ary, num, none, right);//開始進行賦值
return p;
}
else
return NULL; //else表示數組已經賦值完了,沒有值在來擴建了
所以就返回空
}
template<typename T>
void BiTree<T>::Release(BiNode<T> * & root)//有釋放的意思
{
if (root != NULL) //首先從根結點開始
{
Release(root->lchild);
Release(root->rchild);
delete root; //興許遍歷性的釋放
}
}
template<typename T>
void BiTree<T>::Count()
{
CountIn(rootPtr);
cout << "|" << setw(5) << "該樹結點數為:" << count <<setw(5)<< "|" <<
endl;
}
template<typename T>
BiTree<T>::BiTree(T none)
{
Creat(rootPtr, none);
}
template <typename T>
BiTree<T>::BiTree(T ary[], int num, T none)
{
rootPtr = Build(ary, num, none, 1); //none用來傳遞空
}
template <typename T>
BiTree<T>::~BiTree()
{
Release(rootPtr);
}
template <typename T>
void BiTree<T>::printIn(ostream &os, BiNode<T> *root, int depth)
{
if (root != NULL)
{
printIn(os, root->rchild, depth + 1);
for (int i = 0; i < 4 * (depth - 1); i++)
os << " ";
os << "*--" << root->data << endl; //這句是函數共同全部
printIn(os, root->lchild, depth+1);
}
}
template<typename T>
void BiTree<T>::PreOrderPrintIn(BiNode<T> *root)
{
if (root != NULL)
{
if (root->lchild==NULL&&root->rchild==NULL)
cout <<setw(3)<< root->data; //先輸出根結點
數據
PreOrderPrintIn(root->lchild); //然後在開始進行左結點輸出
PreOrderPrintIn(root->rchild); //然後右結點輸出
}
}
template<typename T>
void BiTree<T>::PreOrderPrint()
{
PreOrderPrintIn(rootPtr);
}
template<typename T>
int BiTree<T>::DepthIn(BiNode<T> *root)
{
if (root == NULL)return 0; //標誌訪問結束
else //標誌繼續向下訪問
{
highl = DepthIn(root->lchild);//為何在這一步就能夠進行 賦值?
highr = DepthIn(root->rchild);
if (highl > highr)
return highl + 1;
else
return highr + 1;
}
}
template<typename T>
void BiTree<T>::Depth()
{
cout<<DepthIn(rootPtr);
}
template<typename T>
void BiTree<T>::PostOrderNIn(BiNode<T> * root)
{
if (root != NULL)
{
cout << setw(3) << root->data;
PostOrderNIn(root->rchild);
PostOrderNIn(root->lchild);
}
}
template<typename T>
void BiTree<T>::PostOrderN()
{
PostOrderNIn(rootPtr);
}
template<typename T>
BiNode<T> *BiTree<T>::ParentIn(BiNode<T> *root, T x)
{
if (root != NULL)
{
if (root->data == x)cout<<p->data;
else
{
p = root;
ParentIn(root->lchild, x);
ParentIn(root->rchild, x);
}
}
return 0;
}
template<typename T>
void BiTree<T>::Parent(T x)
{
ParentIn(rootPtr, x);
}
template<typename T>
void BiTree<T>::DeleteIn(BiNode<T> * root, T x)
{
if (root != NULL)
{
if (root->data == x)
{
if (p == NULL)
root = NULL;
else
if (p->lchild == root)
p->lchild = NULL;
else
p->rchild = NULL;
}
else
{
p = root;
DeleteIn(root->lchild, x);
DeleteIn(root->rchild, x);
}
}
}
template<typename T>
void BiTree<T>::Delete(T x)
{
DeleteIn(rootPtr, x);
}
template<typename T>
void BiTree<T>::print(ostream & os)
{
printIn(os, rootPtr, 1);
}
template<typename T>
ostream & operator<<(ostream & os, BiTree<T> &bt)
{
bt.print(os);
return os;
}
#endif
************************************************************************
#include"BiTree.h"
#include<iostream>
using namespace std;
void main()
{
char ary[] = { ‘A‘, ‘B‘, ‘C‘, ‘D‘, ‘#‘,
‘E‘, ‘F‘, ‘#‘, ‘G‘, ‘#‘,
‘#‘, ‘H‘, ‘I‘,
‘J‘, ‘K‘,
‘#‘, ‘#‘, ‘L‘ };
char zxh,gmy;
BiTree<char> myBTree(ary, 18, ‘#‘);
cout << myBTree << endl;
cout << "--------------------------------------------------" << endl;
//cout << "++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
cout << "求二叉樹結點個數(第一題算法)" << endl;
myBTree.Count();
//cout << "++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
cout << "--------------------------------------------------" << endl;
//cout << "++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
cout << "求二叉樹葉子節點次序(第二題算法)"<<endl;
cout << "該樹的葉子結點按前序次序de方式排列輸出為:";
myBTree.PreOrderPrint();
cout << endl;
//cout << "++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
cout << "--------------------------------------------------" << endl;
cout << "求二叉樹深度(第三題揭發):" << endl;
cout << "這個二叉樹的深度為:"<<endl;
myBTree.Depth();
cout << "--------------------------------------------------" << endl;
cout << "求二叉樹後序逆遍歷(第四道題解法):" << endl;
cout << "該二叉樹的逆向後序遍歷為:" << endl;
myBTree.PostOrderN();
cout << "--------------------------------------------------" << endl;
cout << "求二叉樹某結點雙親(第五道題解法):" << endl;
cout << "請輸入您想查詢的結點(!註:區分大寫和小寫):";
cin >> zxh;
cout << "您查詢的結點為:" << zxh << "他的雙親為:" << endl;
myBTree.Parent(zxh);
cout << endl;
cout << "--------------------------------------------------" << endl;
cout << "請輸入您想刪除的字符:";
cin >> gmy;
myBTree.Delete(gmy);
cout << "刪除後的二叉樹為:" << endl;
cout << myBTree;
}
*****************************************************************************
個人小結:
第一次接觸到二叉樹這個東西,我明顯的感覺到了與前面學的順序表單鏈表有所不同了,最大
的特點就是二叉樹中函數都是成對的,由於原始的二叉樹函數在主函數中是無法調用的,所以
他就須要在類的構造中在定義一個與之相應的函數,以此方便在主函數中調用了。但說白了二
叉樹呢。也沒什麽難得,僅僅要我們明確當中的原理,在多多的練習就非常easy攻克了。
??二叉樹的算法與講法