參閱資料:http://blog.csdn.net/ns_code/article/details/12977901
二叉樹是很常見的數據結構, 它的遍歷方式有遞歸和非遞歸兩種,其中遞歸方式易於實現,而非遞歸的方式往往效率更高,耗資源更少,各有千秋,下面就來介紹下具體的實現方法。
節點結構:
typedef struct Node{
int val;
Node* left;
Node* right;
Node(int val) : val(val), left(NULL), right(NULL) {}
} *pNode;
先序遍歷:
遞歸方式:
首先遍歷其根結點,然後遍歷左子樹,最後遍歷右子樹,對於其子樹的遍歷方式同上。
void BST::Recursion_preOrder_Traverse(pNode node){
if(node){
printf("%d ", node->val);
Recursion_preOrder_Traverse(node->left);
Recursion_preOrder_Traverse(node->right);
}
}
非遞歸方式:
無非就是模擬遞歸,這裏我們用棧模擬。
首先設置一個當前指針curNode,用於指向當前需要操作的節點。
1:對於一個節點,我們輸出它的值,將其入棧,並判斷左子樹是否爲空
2:如果不爲空,那麼curNode指向它,重複1
3:如果爲空,說明此時左子樹已經遍歷完畢,並令當前節點出棧,因爲已經遍歷過了,令curNode指向當前節點的右節點,判斷curNode是否爲空。
4:如果不爲空,重複1
5:如果爲空,說明其沒有右子樹,繼續出棧,重複4、5
6:如果當前curNode爲空並且棧爲空,則遍歷完畢。
void BST::Non_Recursion_preOrder_Traverse(pNode root){
stack<pNode> pNode_stack;
pNode curNode = root;
while(curNode != NULL || !pNode_stack.empty()){
printf("%d ", curNode->val);
pNode_stack.push(curNode);
curNode = curNode->left;
while(!curNode && !pNode_stack.empty()){//當指針爲空並且棧內有元素時,就可以取出來遍歷右子樹了
curNode = pNode_stack.top();
pNode_stack.pop();
curNode = curNode->right;
}
}
}
中序遍歷:
遞歸方式:
首先遍歷其左子樹,然後輸出自己的值,最後遍歷右子樹,對於其子樹的遍歷方式同上。
void BST::Recursion_inOrder_Traverse(pNode node){
if(node){
Recursion_inOrder_Traverse(node->left);
printf("%d ", node->val);
Recursion_inOrder_Traverse(node->right);
}
}
非遞歸方式:
1:若當前節點左子樹不爲空,則將該節點入棧,重複1
2:若當前節點左子樹爲空,則輸出其值(注意這裏並沒有將該節點入棧),curNode指向它的右子樹,判斷是否爲空
3:若不爲空,則重複1、2
4:若爲空,則將棧頂元素取出,輸出其值,curNode指向它的右子樹,判斷其是否爲空,重複3、4
5:如果當前curNode爲空並且棧爲空,則遍歷完畢。
void BST::Non_Recursion_inOrder_Traverse(pNode root){
stack<pNode> pNode_stack;
pNode curNode = root;
while(curNode != NULL || !pNode_stack.empty()){
if(curNode->left != NULL){
pNode_stack.push(curNode);
curNode = curNode->left;
}
else{
printf("%d ", curNode->val);
curNode = curNode->right;
while(!curNode && !pNode_stack.empty()){
//此時curNode的左子樹全部遍歷完畢,輸出自己
curNode = pNode_stack.top();
printf("%d ", curNode->val);
pNode_stack.pop();
curNode = curNode->right;
}
}
}
}
後序遍歷:
遞歸方式:
首先遍歷左子樹,然後遍歷右子樹,最後輸出自己,對於其子樹的遍歷方式同上。
void BST::Recursion_postOrder_Traverse(pNode node){
if(node){
Recursion_postOrder_Traverse(node->left);
Recursion_postOrder_Traverse(node->right);
printf("%d ", node->val);
}
}
非遞歸方式:
這裏要多加一個記錄上一個訪問節點的preNode
1:首先將節點入棧
2:如果單籤節點是葉子節點或者它的左右孩子已經有輸出的了,則將其直接輸出並出棧,將棧頂節點設爲curNode並將出棧節點設爲preNode
3:若2不滿足,則將該節點的右孩子和左孩子依次入棧,重複2
4:若棧爲空,則遍歷結束。
void BST::Non_Recursion_postOrder_Traverse(pNode root){
stack<pNode> pNode_stack;
pNode curNode = root;
pNode preNode = NULL;
pNode_stack.push(curNode);
while(!pNode_stack.empty()){
curNode = pNode_stack.top();
if((curNode->left == NULL && curNode->right == NULL) ||
(preNode != NULL && (curNode->left == preNode || curNode->right == preNode))){
printf("%d ", curNode->val);
pNode_stack.pop();
preNode = curNode;
}
else{
if(curNode->right != NULL)
pNode_stack.push(curNode->right);
if(curNode->left != NULL)
pNode_stack.push(curNode->left);
}
}
}
程序總覽:
#include <cstdio>
#include <stack>
using namespace std;
typedef struct Node{
int val;
Node* left;
Node* right;
Node(int val) : val(val), left(NULL), right(NULL) {}
} *pNode;
class BST{
private:
pNode root;
void Non_Recursion_Insert_Node(pNode *root, int x);
void Non_Recursion_postOrder_Traverse(pNode root);
void Recursion_postOrder_Traverse(pNode node);
void Non_Recursion_inOrder_Traverse(pNode root);
void Recursion_inOrder_Traverse(pNode root);
void Recursion_Delete_BST(pNode node);
void Non_Recursion_preOrder_Traverse(pNode root);
void Recursion_preOrder_Traverse(pNode node);
public:
void Non_Recursion_Insert_Node(int x);
void Non_Recursion_postOrder_Traverse();
void Recursion_postOrder_Traverse();
void Non_Recursion_inOrder_Traverse();
void Recursion_inOrder_Traverse();
void Non_Recursion_preOrder_Traverse();
void Recursion_preOrder_Traverse();
void Build_BST(int *num, int n);
BST();
~BST();
};
void BST::Build_BST(int *num, int n){
for(int i = 0; i < n; i++){
Non_Recursion_Insert_Node(&this->root, num[i]);
}
}
void BST::Non_Recursion_Insert_Node(int x){
Non_Recursion_Insert_Node(&this->root, x);
}
void BST::Non_Recursion_Insert_Node(pNode *root, int x){
pNode child = *root;
pNode parent = NULL;
while(child != NULL){
parent = child;
if(child->val > x){
child = child->left;
}
else{
child = child->right;
}
}
if(parent == NULL){
*root = new Node(x);
}
else if(parent->val > x){
parent->left = new Node(x);
}
else{
parent->right = new Node(x);
}
}
void BST::Non_Recursion_preOrder_Traverse(){
Non_Recursion_preOrder_Traverse(this->root);
}
void BST::Non_Recursion_preOrder_Traverse(pNode root){
stack<pNode> pNode_stack;
pNode curNode = root;
while(curNode != NULL || !pNode_stack.empty()){
printf("%d ", curNode->val);
pNode_stack.push(curNode);
curNode = curNode->left;
while(!curNode && !pNode_stack.empty()){//當指針爲空並且棧內有元素時,就可以取出來遍歷右子樹了
curNode = pNode_stack.top();
pNode_stack.pop();
curNode = curNode->right;
}
}
}
void BST::Recursion_preOrder_Traverse(pNode node){
if(node){
printf("%d ", node->val);
Recursion_preOrder_Traverse(node->left);
Recursion_preOrder_Traverse(node->right);
}
}
void BST::Recursion_preOrder_Traverse(){
Recursion_preOrder_Traverse(this->root);
}
void BST::Non_Recursion_inOrder_Traverse(){
Non_Recursion_inOrder_Traverse(this->root);
}
void BST::Non_Recursion_inOrder_Traverse(pNode root){
stack<pNode> pNode_stack;
pNode curNode = root;
while(curNode != NULL || !pNode_stack.empty()){
if(curNode->left != NULL){
pNode_stack.push(curNode);
curNode = curNode->left;
}
else{
printf("%d ", curNode->val);
curNode = curNode->right;
while(!curNode && !pNode_stack.empty()){
//此時curNode的左子樹全部遍歷完畢,輸出自己
curNode = pNode_stack.top();
printf("%d ", curNode->val);
pNode_stack.pop();
curNode = curNode->right;
}
}
}
}
void BST::Recursion_inOrder_Traverse(pNode node){
if(node){
Recursion_inOrder_Traverse(node->left);
printf("%d ", node->val);
Recursion_inOrder_Traverse(node->right);
}
}
void BST::Recursion_inOrder_Traverse(){
Recursion_inOrder_Traverse(this->root);
}
void BST::Non_Recursion_postOrder_Traverse(){
Non_Recursion_postOrder_Traverse(this->root);
}
void BST::Non_Recursion_postOrder_Traverse(pNode root){
stack<pNode> pNode_stack;
pNode curNode = root;
pNode preNode = NULL;
pNode_stack.push(curNode);
while(!pNode_stack.empty()){
curNode = pNode_stack.top();
if((curNode->left == NULL && curNode->right == NULL) ||
(preNode != NULL && (curNode->left == preNode || curNode->right == preNode))){
//如果當前節點爲葉子節點或者它的子節點有已經輸出的 那麼就輸出這個節點
//爲什麼任意左右節點只要有輸出的,該節點就會輸出呢?這是因爲底下的else決定的
//訪問該節點之前一定會訪問它的左右子節點,如果preNode保存的是它的左節點,那麼
//一定不存在右節點,當然下一個會訪問他自己,如果perNode保存的是右節點,則說明
//左節點已經被訪問完畢,這是由入棧順序決定的。
printf("%d ", curNode->val);
pNode_stack.pop();
preNode = curNode;
}
else{
if(curNode->right != NULL)
pNode_stack.push(curNode->right);
if(curNode->left != NULL)
pNode_stack.push(curNode->left);
}
}
}
void BST::Recursion_postOrder_Traverse(pNode node){
if(node){
Recursion_postOrder_Traverse(node->left);
Recursion_postOrder_Traverse(node->right);
printf("%d ", node->val);
}
}
void BST::Recursion_postOrder_Traverse(){
Recursion_postOrder_Traverse(this->root);
}
void BST::Recursion_Delete_BST(pNode node){
if(node == NULL)
return;
if(node->left != NULL)
Recursion_Delete_BST(node->left);
if(node->right != NULL)
Recursion_Delete_BST(node->right);
delete node;
}
BST::BST(){
root = NULL;
}
BST::~BST(){
Recursion_Delete_BST(this->root);
}
int main()
{
return 0;
}