c++二叉樹的遞迴和非遞迴的前序中序和後序遍歷以及層序遍歷
阿新 • • 發佈:2018-11-12
二叉樹的遞迴版的前序,中序和後序遍歷很簡單也很容易理解,這裡就放一個前序遍歷的例子
//前序遍歷遞迴演算法,遞迴演算法都大同小異,這裡就不一一列舉了
void binaryTree::pro_order(NodeStack::Node *t) {
NodeStack::Node *h = t;
if (h != NULL) {
cout << h->data<<" ";
pro_order(h->lchild);
pro_order(h->rchild);
}
else
return;
}
中序遍歷和後序遍歷只要稍微換一下遞迴呼叫的位置就行了
非遞迴的二叉樹的遍歷需要用到棧,先放出棧的程式碼
#ifndef _NodeStack_H_ #define _NodeStack_H_ #include <iostream> #define MAXSIZE 100 typedef int type; namespace st { class NodeStack { public: struct Node { struct Node *lchild, *rchild; //左右孩子 type data; //存放資料 }; private: Node NodeData[MAXSIZE]; int top; //指向當前有資料的最大的空間 int size; //記錄棧的大小 public: NodeStack(); ~NodeStack(); int push(Node*); //入棧操作 Node pop(); //出棧操作 int empty(); //探空操作 int full(); //判斷是不是滿的 void traverse(); //遍歷棧 int get_top(); //獲取棧頂元素值 }; NodeStack::NodeStack() { top = -1; size = 100; for (int i = 0; i < 100; i++) { NodeData[i].lchild = NodeData[i].rchild = NULL; NodeData[i].data = NULL; } } NodeStack::~NodeStack() { } //入棧操作,成功返回1,失敗返回0 int NodeStack::push(Node* n) { top++; NodeData[top] = *n; return 1; } NodeStack::Node NodeStack::pop() { return NodeData[top--]; } int NodeStack::empty() { if (top == -1) return 1; //棧是空的 else return 0; //棧非空 } int NodeStack::full() { if (top == size - 1) return 1; //棧是滿的 else return 0; //棧不是滿的 } void NodeStack::traverse() { int t = top; std::cout << "棧空間:"; while (t != -1) std::cout << NodeData[t--].data << " "; std::cout << std::endl; } int NodeStack::get_top() { return top; } } #endif // ! _NodeStack_H_
二叉樹的結點結構體是寫在棧的類裡面的
先是前序遍歷
//前序遍歷的非遞迴演算法 void binaryTree::pro_traverse() { NodeStack::Node h = *head; NodeStack::Node *t = &h; cout << "前序遍歷結果如下(非遞迴演算法):" << endl; stack.push(t); while (!stack.empty()) { //只要棧不空 //stack.traverse(); h = stack.pop(); cout << h.data << " "; if (h.rchild != NULL) { //如果右子樹不空則入棧 t = h.rchild; stack.push(t); } if (h.lchild != NULL) { //如果左子樹不空則入棧 t = h.lchild; stack.push(t); } } cout << endl; }
然後是中序遍歷
//中序遍歷的非遞迴演算法
/*每個結點在入棧後都先找所有的左孩子,直到沒有左孩子了為止
*出棧之後找右子樹,如果存在右子樹那麼右子樹也遵循上面的步驟
*/
void binaryTree::mid_traverse() {
NodeStack::Node h = *head;
NodeStack::Node *t = &h;
//先讓頭結點入棧
cout << "中序遍歷的結果如下(非遞迴演算法):" << endl;
stack.push(t);
while (!stack.empty()) {
while (t->lchild != NULL) {
t = t->lchild;
stack.push(t);
}
//接下來出棧
h = stack.pop();
cout << h.data <<" ";
//如果出棧的結點有右子樹那麼入棧
if (h.rchild != NULL) {
t = h.rchild;
stack.push(t);
//之後再對右子樹做同樣操作
while (t->lchild != NULL) {
t = t->lchild;
stack.push(t);
}
}
}
cout << endl;
}
接下來是後序遍歷
//後序遍歷的非遞迴演算法
/*一個結點入棧後它的左右左結點都要入棧,直到沒有左結點了為止
* 到了沒有左結點的時候那麼看看它有沒有右結點,如果有就先把自己入棧,然後右結點按照上一步檢查左結點
* 如果沒有就輸出,然後繼續出棧,重複上面的步驟,這裡需要維持一個記錄入棧次數的陣列,當一個數第三次入棧的時候
* 就不能再入棧了
*/
void binaryTree::pos_traverse() {
NodeStack::Node h = *head;
NodeStack::Node *t = &h;
int num = 0; //記錄入棧的次數
cout << "後序遍歷的結果如下(非遞迴演算法):" << endl;
//先入棧
stack.push(t);
//將所有左子樹入棧
while (t->lchild != NULL) {
t = t->lchild;
stack.push(t);
}
while (!stack.empty()) {
h = stack.pop(); //出棧
if (h.rchild != NULL && isfirst[stack.get_top()+1] == 0) {
//如果右子樹存在
t = &h;
stack.push(t);
isfirst[stack.get_top()]++; //第二次入棧次數加一
t = h.rchild;
stack.push(t);
while (t->lchild != NULL) {
t = t->lchild;
stack.push(t);
}
}
else {
//否則直接輸出就好了
cout << h.data << " ";
//徹底出棧了之後就可以記錄入棧次數為0了
isfirst[stack.get_top() + 1] = 0;
}
}
cout << endl;
}
最後是層序遍歷
//層序遍歷
/*層序遍歷需要用到佇列,我們這裡用陣列模擬,
*先把頭結點入隊,然後逐個出隊,在出隊的同時將左右孩子入隊,我們給隊分配的空間是100,也就是最多支援6層的樹
*2^6=64,2^7=128,對於滿二叉樹的情況就會溢位,所以最多支援6層(頭結點算第0層)
*/
void binaryTree::level_traverse() {
NodeStack::Node h = *head;
int head = 0,tail = 0; //佇列的頭和尾指標,隊空的標誌是head == tail
quene[head++] = h; //head指向下一個將要填充的空間
cout << "層序遍歷的結果是:" << endl;
//接下來開始出隊
while (head != tail) {
h = quene[tail++];
if (h.lchild != NULL) {
//左子樹入隊
quene[head++] = *h.lchild;
}
if (h.rchild != NULL) {
quene[head++] = *h.rchild;
}
cout << h.data << " ";
}
cout << endl;
}
下面貼完整的程式碼
#include <iostream>
#include "NodeStack.h" //結點棧,樹結點的定義也在這個標頭檔案裡
using namespace std;
using namespace st; //這個名稱空間就是指定NodeStack.h的,如果在那個標頭檔案沒有使用這個名稱空間那麼就不需要這一句
typedef int type;
//先寫一個普通的二叉查詢樹
class binaryTree {
private:
//樹的結點的結構體
NodeStack::Node *head; //頭指標
NodeStack stack; //結點棧
int isfirst[100]; //用於記錄是否是第一次入棧(用於後序遍歷的非遞迴演算法)
NodeStack::Node quene[100]; //模擬佇列的陣列,用於層序遍歷
//數的結點的棧,用於非遞迴遍歷樹
public:
binaryTree();
~binaryTree();
NodeStack::Node* get_head(); //獲取頭指標
void destroy(NodeStack::Node* ); //刪除結點
int insert(); //插入操作
void pro_traverse(); //前序遍歷這棵二叉樹
void mid_traverse(); //中序遍歷這棵二叉樹
void pos_traverse(); //後序遍歷這棵二叉樹
void level_traverse(); //層序遍歷
//下面是遍歷的遞迴演算法
void pro_order(NodeStack::Node*);
};
//建構函式,分配一個頭結點的空間和棧的空間
binaryTree::binaryTree() {
//初始化頭指標
head = new NodeStack::Node();
head->lchild = head->rchild = NULL;
head->data = NULL;
for (int i = 0; i < 100; i++) {
isfirst[i] = 0; //全部初始化為0
quene[i].lchild = quene[i].rchild = NULL;
quene[i].data = NULL;
}
}
//解構函式,收回所有分配的空間
binaryTree::~binaryTree() {
NodeStack::Node *t = head;
destroy(t);
head = new NodeStack::Node();
head->lchild = head->rchild = NULL;
head->data = NULL;
}
void binaryTree::destroy(NodeStack::Node *t) {
if (t->rchild != NULL)
destroy(t->rchild);
if (t->lchild != NULL)
destroy(t->lchild);
delete t;
}
NodeStack::Node* binaryTree::get_head() {
return this->head;
}
//插入操作,規定左子樹的數比根節點小,右子樹的數比根節點大
int binaryTree::insert() {
cout << "請輸入要插入的結點的資料:";
int num;
cin >> num;
if (head->data == NULL) {
head->data = num;
return 1;
}
else {
NodeStack::Node *t = new NodeStack::Node();
NodeStack::Node *pre = NULL;
NodeStack::Node *h = head;
t->lchild = t->rchild = NULL;
t->data = num;
while (h != NULL) {
if (h->data > t->data) {
pre = h;
h = h->lchild;
}
else {
pre = h;
h = h->rchild;
}
}
if (pre->data > t->data)
pre->lchild = t;
else
pre->rchild = t;
return 1;
}
}
//前序遍歷的非遞迴演算法
void binaryTree::pro_traverse() {
NodeStack::Node h = *head;
NodeStack::Node *t = &h;
cout << "前序遍歷結果如下(非遞迴演算法):" << endl;
stack.push(t);
while (!stack.empty()) {
//只要棧不空
//stack.traverse();
h = stack.pop();
cout << h.data << " ";
if (h.rchild != NULL) {
//如果右子樹不空則入棧
t = h.rchild;
stack.push(t);
}
if (h.lchild != NULL) {
//如果左子樹不空則入棧
t = h.lchild;
stack.push(t);
}
}
cout << endl;
}
//中序遍歷的非遞迴演算法
/*每個結點在入棧後都先找所有的左孩子,直到沒有左孩子了為止
*出棧之後找右子樹,如果存在右子樹那麼右子樹也遵循上面的步驟
*/
void binaryTree::mid_traverse() {
NodeStack::Node h = *head;
NodeStack::Node *t = &h;
//先讓頭結點入棧
cout << "中序遍歷的結果如下(非遞迴演算法):" << endl;
stack.push(t);
while (!stack.empty()) {
while (t->lchild != NULL) {
t = t->lchild;
stack.push(t);
}
//接下來出棧
h = stack.pop();
cout << h.data <<" ";
//如果出棧的結點有右子樹那麼入棧
if (h.rchild != NULL) {
t = h.rchild;
stack.push(t);
//之後再對右子樹做同樣操作
while (t->lchild != NULL) {
t = t->lchild;
stack.push(t);
}
}
}
cout << endl;
}
//後序遍歷的非遞迴演算法
/*一個結點入棧後它的左右左結點都要入棧,直到沒有左結點了為止
* 到了沒有左結點的時候那麼看看它有沒有右結點,如果有就先把自己入棧,然後右結點按照上一步檢查左結點
* 如果沒有就輸出,然後繼續出棧,重複上面的步驟,這裡需要維持一個記錄入棧次數的陣列,當一個數第三次入棧的時候
* 就不能再入棧了
*/
void binaryTree::pos_traverse() {
NodeStack::Node h = *head;
NodeStack::Node *t = &h;
int num = 0; //記錄入棧的次數
cout << "後序遍歷的結果如下(非遞迴演算法):" << endl;
//先入棧
stack.push(t);
//將所有左子樹入棧
while (t->lchild != NULL) {
t = t->lchild;
stack.push(t);
}
while (!stack.empty()) {
h = stack.pop(); //出棧
if (h.rchild != NULL && isfirst[stack.get_top()+1] == 0) {
//如果右子樹存在
t = &h;
stack.push(t);
isfirst[stack.get_top()]++; //第二次入棧次數加一
t = h.rchild;
stack.push(t);
while (t->lchild != NULL) {
t = t->lchild;
stack.push(t);
}
}
else {
//否則直接輸出就好了
cout << h.data << " ";
//徹底出棧了之後就可以記錄入棧次數為0了
isfirst[stack.get_top() + 1] = 0;
}
}
cout << endl;
}
//前序遍歷遞迴演算法,遞迴演算法都大同小異,這裡就不一一列舉了
void binaryTree::pro_order(NodeStack::Node *t) {
NodeStack::Node *h = t;
if (h != NULL) {
cout << h->data<<" ";
pro_order(h->lchild);
pro_order(h->rchild);
}
else
return;
}
//層序遍歷
/*層序遍歷需要用到佇列,我們這裡用陣列模擬,
*先把頭結點入隊,然後逐個出隊,在出隊的同時將左右孩子入隊,我們給隊分配的空間是100,也就是最多支援6層的樹
*2^6=64,2^7=128,對於滿二叉樹的情況就會溢位,所以最多支援6層(頭結點算第0層)
*/
void binaryTree::level_traverse() {
NodeStack::Node h = *head;
int head = 0,tail = 0; //佇列的頭和尾指標,隊空的標誌是head == tail
quene[head++] = h; //head指向下一個將要填充的空間
cout << "層序遍歷的結果是:" << endl;
//接下來開始出隊
while (head != tail) {
h = quene[tail++];
if (h.lchild != NULL) {
//左子樹入隊
quene[head++] = *h.lchild;
}
if (h.rchild != NULL) {
quene[head++] = *h.rchild;
}
cout << h.data << " ";
}
cout << endl;
}
/*
測試資料:
5
/ \
2 10
/ \ / \
1 3 7
/ \
6 8
*/
int main()
{
binaryTree bt;
for(int i=0;i<8;i++)
bt.insert();
bt.pro_traverse();
bt.mid_traverse();
bt.pos_traverse();
bt.level_traverse();
return 0;
}
測試結果: