主要講解二叉樹的遍歷問題:
前序遍歷:訪問根結點的操作發生在遍歷其左右子樹之前。
中序遍歷:訪問根結點的操作發生在遍歷其左右子樹中。
後序遍歷:訪問根結點的操作發生在遍歷其左右子樹之後。
層序遍歷:設二叉樹的根結點所在層數爲1,層序遍歷就是從所在二叉樹根結點出發,首先訪問第一層的樹根結點,然後從左到右訪問第2層上的節點,接着是第三層的節點,以此類推,自上而下,自左而右逐層訪問樹的節點的過程就是層序遍歷。
代碼實現:分別採用遞歸和非遞歸的思想實現前中後序遍歷。
遞歸實現:
# pragma once
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int val;
struct Node* left;
struct Node* right;
} Node;
typedef struct Result{
Node* node; //創建好的書的根結點
int used; //創建樹的過程中用掉的val個數
} Result;
//創建二叉樹
//BC##DE#G##F###
//""
Result CreateTree(char preorder[], int size)
{
if (size <= 0){
Result result;
result.node = NULL;
result.used = 0;
return result;
}
if (preorder[0] == '#'){
Result result;
result.node = NULL;
result.used = 1;
return result;
}
//創建根結點
Node* root = (Node*)malloc(sizeof(Node));
root->val = preorder[0];
//創建左子樹
Result left = CreateTree(preorder + 1, size - 1);
//創建右子樹
Result right = CreateTree(preorder + 1 + left.used, size - 1 - left.used);
root->left = left.node;
root->right = right.node;
Result result;
result.node = root;
//1是根用掉的,left.used是左子樹用掉的
//right.nsed是右子樹用掉的
result.used = 1 + left.used + right.used;
return result;
}
//利用遞推的方式寫二叉樹
//前序遍歷二叉樹
void PreorderTraversal(Node* root)
{
//終止條件
if (root == NULL)
{
return;
}
printf("%d ", root->val);
PreorderTraversal(root->left);
PreorderTraversal(root->right);
}
//中序遍歷二叉樹
void MiddleOrderTraversal(Node* root)
{
if (root == NULL)
{
return;
}
MiddleOrderTraversal(root->left);
printf("%d ", root->val);
MiddleOrderTraversal(root->right);
}
//後序遍歷二叉樹
void EpilogueTraversal(Node* root)
{
if (root == NULL)
{
return;
}
EpilogueTraversal(root->left);
EpilogueTraversal(root->right);
printf("%d ", root->val);
}
//結點的個數遞推的思路
int GetNodeCount(Node* root)
{
if (root == NULL)
{
return 0;
}
return GetNodeCount(root->left) + GetNodeCount(root->right) + 1;
}
//遍歷的思路
int n = 0;
void GetNodeCount1(Node *root)
{
if (root == NULL){
return;
}
GetNodeCount1(root->left);
n++;
GetNodeCount1(root->right);
}
//葉子結點的個數遞推的思路
int GetLeafSize(Node* root)
{
if (root == NULL){
return 0;
}
if (root->left == NULL && root->right == NULL){
return 1;
}
return GetLeafSize(root->left) + GetLeafSize(root->right);
}
//遍歷的思路
int leaf_n = 0;
void GetLeafSize2(Node *root)
{
if (root == NULL){
return;
}
if (root->left == NULL && root->right == NULL){
leaf_n++;
}
GetLeafSize2(root->left);
GetLeafSize2(root->right);
}
//第k層結點的個數
int LevelK(Node* root, int k)
{
if (root == NULL){
return 0;
}
if (k == 1){
return 1;
}
return LevelK(root->left, k - 1) + LevelK(root->right, k - 1);
}
//在樹中查找val的值,樹的val一定不重複
//查找次序,有序判斷根,根不是,去左子樹找,左子樹沒找到,繼續右子樹
//返回包含val的結點地址,沒有找到返回NULL
Node *Find(Node *root, char val)
{
if (root == NULL){
return;
}
//先判斷根
if (root->val == val){
return root;
}
//去左子樹找
Node *r = Find(root->left, val);
if (r != NULL){
return r;
}
//右子樹找到了返回地址,沒有找到返回NULL
return Find(root->right, val);
}
//求二叉樹的高度
int GetHeight(Node* root)
{
if (root == NULL)
{
return 0;
}
int left = GetHeight(root->left);
int right = GetHeight(root->right);
return (left > right ? left : right) + 1;
}
非遞歸實現:
#include <queue>
#include <stack>
#include <stdio.h>
//層序遍歷
typedef struct Node
{
int val;
struct Node* left;
struct Node* right;
} Node;
typedef struct Result{
Node* node; //創建好的書的根結點
int used; //創建樹的過程中用掉的val個數
} Result;
//層序遍歷二叉樹
void LevelOrderTraversal(Node *root)
{
if (root == NULL){
return;
}
//來個隊列,隊列中存的數據類型是Node*
//命名空間
//模板
std::queue<Node *> q;
q.push(root);
while (!q.empty()){
Node *node = q.front(); //去隊首結點
q.pop(); //彈出隊首結點
printf("%c ", node->val);
if (node->left != NULL){
q.push(node->left);
}
if (node->right != NULL){
q.push(node->right);
}
}
}
//判斷一棵樹是否是完全二叉樹
bool isCompleteTree(Node *root)
{
if (root == NULL){
return true;
}
//來個隊列,隊列中存的數據類型是Node*
//命名空間
//模板
std::queue<Node *> q;
q.push(root);
while (1){
Node *node = q.front(); //取隊首結點
q.pop();
if (node == NULL){
//在層序遍歷的過程中遇到空結點
break;
}
q.push(node->left);
q.push(node->right);
}
//檢查剩下結點中有沒有非結點
while (!q.empty()){
Node *node = q.front();
q.pop();
if (node != NULL){
return false;
}
}
return true;
}
//前序遍歷非遞歸
void PreorderTraversalNoR(Node *root)
{
std::stack<Node *> s; //棧
Node *cur = root;
Node *top = NULL;
while (cur != NULL || !s.empty()){
//一路向左的過程
while (cur != NULL){
printf("%c ", cur->val);
s.push(cur);
cur = cur->left;
}
//一定是向左遇到NULL
//利用棧處理剩餘的右子樹
top = s.top();
s.pop();
cur = top->right;
}
}
//中序遍歷非遞歸
void InorderTraversalNoR(Node *root)
{
std::stack<Node *> s;
Node *cur = root;
Node *top = NULL;
//一路向左的過程
while (cur != NULL || !s.empty()){
//第一次遇到的結點的位置
s.push(cur);
cur = cur->left;
}
//一定是向左遇到NULL
//利用棧處理剩餘的右子樹
top = s.top;
s.pop();
//第二次遇到的地方
printf("%c ", top->val);
cur = top->right;
}
//後序遍歷非遞歸
void PostorderTraversalNoR(Node *root)
{
std::stack<Node *> s;
Node *cur = root;
Node *top = NULL;
Node *last = NULL;
while (cur != NULL || !s.empty()){
//一路向左的過程
while (cur != NULL){
//第一次遇到的結點的位置
s.push(cur);
cur = cur->left;
}
//一定是向右遇到NULL
//利用棧處理剩餘的右子樹
top = s.top();
if (top->right == NULL){
printf("%c ", top->val);
s.pop();
last = top;
}
else if (top->right == last){
printf("%c ", top->val);
s.pop();
last = top;
}
else{
cur = cur->right;
}
}
}