二叉树(C++):创建,前中后序遍历(递归+非递归),获取叶子节点个数,获取树的高度
文章目錄
- 前言
- 創(chuàng)建二叉樹
- 先序遍歷
- 中序遍歷
- 后序遍歷
- 獲取葉子節(jié)點個數(shù)
- 獲取樹的高度
- 測試代碼
前言
現(xiàn)有如下二叉樹:
關(guān)于二叉樹的相關(guān)操作,我們能夠發(fā)現(xiàn)二叉樹從根節(jié)點到子節(jié)點,以及每個中間節(jié)點基本都能夠拆分為若干個子節(jié)點的操作,且每個子節(jié)點的操作都和其頭節(jié)點操作一致。
所以我們針對二叉樹的操作都可以使用分治算+回溯/歸并算法進行
完整測試代碼見文末
創(chuàng)建二叉樹
二叉樹數(shù)據(jù)結(jié)構(gòu):
typedef struct tree
{char data;struct tree *left;struct tree *right;
}Tree,*TreeNode;
我們使用先序方式,創(chuàng)建如上二叉樹:
輸入如下: ABD***CE**FG***
創(chuàng)建過程
/*創(chuàng)建二叉樹*/
void createTree(TreeNode *root) {char val = 0;cin >> val; //持續(xù)輸入,直到完成一個二叉樹的構(gòu)建if (val == '*') {//輸入為*則代表當前節(jié)點為空(*root) = NULL;} else {(*root) = (Tree *)malloc(sizeof(tree));if ((*root) == NULL) {cout << "create node failed " << endl;exit(-1);} else {(*root)->data = val;//為輸入的節(jié)點賦值createTree(&(*root)->left);//分治左孩子節(jié)點createTree(&(*root)->right);//分治右孩子節(jié)點}}
}
先序遍歷
先序遍歷二叉樹指:先遍歷二叉樹的根節(jié)點,再遍歷當前根節(jié)點所有左子樹,再遍歷當前根節(jié)點所有右子樹
因為這個過程針對子節(jié)點的遍歷和根節(jié)點是沒有任何區(qū)別的,所以可以使用分治進行處理
/*遞歸先序遍歷*/
void preOrder(Tree *root) {if (root == NULL) {return;}cout << root->data;preOrder(root->left);preOrder(root->right);
}
同樣可以使用棧進行非遞歸的先序遍歷,即
棧可以保存遍歷過程中的左節(jié)點,因為先序遍歷是先訪問根節(jié)點,其次就是左節(jié)點
while(p) {cout << p ->data; //訪問根節(jié)點s.push(p); //保存左子節(jié)點p = p->left;
}
接著再彈棧,直到獲取一個右節(jié)點
while(!s.empty()) {p = s.top();s.pop();p = p -> right;
}
接著再重復對右節(jié)點進行同樣的訪問操作,具體過程如下
/*非遞歸先序遍歷*/
void preOrderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;while(!s.empty() || p) {while(p) {cout << p ->data;s.push(p);p = p->left;}while(!s.empty()) {p = s.top();s.pop();p = p -> right;}}cout << endl;
}
中序遍歷
中序遍歷二叉樹是指:先訪問左節(jié)點,中間訪問根節(jié)點,最后訪問右節(jié)點
分治過程如下:
void inorder(Tree *root) {if (root == NULL) {return;}inorder(root -> left);cout << root -> data;inorder(root -> right);
}
中序遍歷二叉樹的非遞歸方式和先序類似,支持訪問的時機是在先訪問第一輪所有的左節(jié)點,再獲取右節(jié)點之前進行根節(jié)點的訪問,實現(xiàn)過程如下:
/*非遞歸中序遍歷*/
void inorderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;while(!s.empty() || p) {while(p) {s.push(p);p = p ->left;}while(!s.empty()) {p = s.top();cout << p->data;s.pop();p = p->right;}}cout << endl;
}
后序遍歷
后序遍歷二叉樹是指:先訪問左節(jié)點,再訪問右節(jié)點,最后訪問根節(jié)點
分治過程如下:
/*遞歸后序遍歷*/
void lastorder(Tree *root) {if (root == NULL) {return;}lastorder(root -> left);lastorder(root -> right);cout << root -> data;
}
非遞歸的訪問過程和先序/中序遍歷有差異,因為后序遍歷需要優(yōu)先訪問完左節(jié)點、右節(jié)點
所以根節(jié)點的訪問前提是:
- 右子節(jié)點為空
- 右子節(jié)點已經(jīng)訪問過
所以實現(xiàn)的過程中需要保存已經(jīng)訪問過的右子節(jié)點
void lastorderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;Tree *lastvisit = NULL;//保存已經(jīng)訪問過的右子節(jié)點/*先獲取到左子節(jié)點*/while(p) {s.push(p);p = p ->left;}while(!s.empty()) {p = s.top();s.pop();/*右節(jié)點已經(jīng)為空或者已經(jīng)訪問過,那么認為右節(jié)點已經(jīng)訪問完,可以訪問根節(jié)點了*/if (p -> right == NULL || p ->right == lastvisit) {cout << p->data;lastvisit = p;} else {//否則,將右節(jié)點以及右節(jié)點的子節(jié)點入棧從而繼續(xù)訪問s.push(p);p = p -> right;/*每獲取到一個非空右節(jié)點,就將該右節(jié)點的左節(jié)點放入棧中*/while(p) {s.push(p);p = p -> left;}}}cout << endl;
}
獲取葉子節(jié)點個數(shù)
葉子節(jié)點的條件就是:左右子樹都為空
此時返回值應(yīng)該為1
分治+歸并獲取葉子節(jié)點的個數(shù)
int getLeavesNode(Tree *root) {if (root == NULL) {return 0;} else {if (root -> left == NULL && root ->right == NULL) {return 1;}return getLeavesNode(root -> left) + getLeavesNode(root -> right);}
}
獲取樹的高度
樹的高度為左右子節(jié)點的 層數(shù)較大的一個數(shù)值
實現(xiàn)過程如下:
int heightTree(Tree *root) {int height = 0;if (root == NULL) {return 0;} else {int l_height = heightTree(root -> left);int r_height = heightTree(root -> right);height = l_height > r_height? l_height +1 :r_height+1;}return height;
}
測試代碼
#include <iostream>
#include <stack>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>using namespace std;typedef struct tree
{char data;struct tree *left;struct tree *right;
}Tree,*TreeNode;/*創(chuàng)建二叉樹*/
void createTree(TreeNode *root) {char val = 0;cin >> val;if (val == '*') {(*root) = NULL;} else {(*root) = (Tree *)malloc(sizeof(tree));if ((*root) == NULL) {cout << "create node failed " << endl;exit(-1);} else {(*root)->data = val;createTree(&(*root)->left);createTree(&(*root)->right);}}
}/*遞歸先序遍歷*/
void preOrder(Tree *root) {if (root == NULL) {return;}cout << root->data;preOrder(root->left);preOrder(root->right);
}/*非遞歸先序遍歷*/
void preOrderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;while(!s.empty() || p) {while(p) {cout << p ->data;s.push(p);p = p->left;}while(!s.empty()) {p = s.top();s.pop();p = p -> right;}}cout << endl;}/*遞歸中序遍歷*/
void inorder(Tree *root) {if (root == NULL) {return;}inorder(root -> left);cout << root -> data;inorder(root -> right);
}/*非遞歸中序遍歷*/
void inorderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;while(!s.empty() || p) {while(p) {s.push(p);p = p ->left;}while(!s.empty()) {p = s.top();cout << p->data;s.pop();p = p->right;}}cout << endl;
}/*遞歸后序遍歷*/
void lastorder(Tree *root) {if (root == NULL) {return;}lastorder(root -> left);lastorder(root -> right);cout << root -> data;
}void lastorderNoRecur(Tree *root) {if (root == NULL) {return;}stack<TreeNode> s;Tree *p = root;Tree *lastvisit = NULL;while(p) {s.push(p);p = p ->left;}while(!s.empty()) {p = s.top();s.pop();/*右節(jié)點已經(jīng)為空或者已經(jīng)訪問過,那么認為右節(jié)點已經(jīng)訪問完,可以訪問根節(jié)點了*/if (p -> right == NULL || p ->right == lastvisit) {cout << p->data;lastvisit = p;} else {//否則,將右節(jié)點以及右節(jié)點的子節(jié)點入棧從而繼續(xù)訪問s.push(p);p = p -> right;while(p) {s.push(p);p = p -> left;}}}cout << endl;
}int getLeavesNode(Tree *root) {if (root == NULL) {return 0;} else {if (root -> left == NULL && root ->right == NULL) {return 1;}return getLeavesNode(root -> left) + getLeavesNode(root -> right);}
}int heightTree(Tree *root) {int height = 0;if (root == NULL) {return 0;} else {int l_height = heightTree(root -> left);int r_height = heightTree(root -> right);height = l_height > r_height? l_height +1 :r_height+1;}return height;
}int main(int argc, char const *argv[])
{/* code */TreeNode root;cout << "construct the tree " << endl;createTree(&root);cout << "previous order recursion " << endl;preOrder(root);cout << "\nprevious order no recursion " << endl;preOrderNoRecur(root);cout << "inorder recursion " << endl;inorder(root);cout << "\ninorder no recursion " << endl;inorderNoRecur(root);cout << "lastorder recursion " << endl;lastorder(root);cout << "\nlastorder no recursion " << endl;lastorderNoRecur(root);cout << "height of the tree is " << heightTree(root) << endl;cout << "num leaves of the tree is " << getLeavesNode(root) << endl;return 0;
}
輸出如下:
#輸入
construct the tree
ABD***CE**FG***
#輸出
previous order recursion
ABDCEFG
previous order no recursion
ABDCEFG
inorder recursion
DBAECGF
inorder no recursion
DBAECGF
lastorder recursion
DBEGFCA
lastorder no recursion
DBEGFCA
height of the tree is 4
num leaves of the tree is 3
總結(jié)
以上是生活随笔為你收集整理的二叉树(C++):创建,前中后序遍历(递归+非递归),获取叶子节点个数,获取树的高度的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大家知道那有鸬鹚(鱼鹰或是水老鸦)卖,我
- 下一篇: 二叉树:路径之和 Path Sum