二叉樹的先序、中序、後序遍歷等基本操作c++實現
二叉樹:樹的每個節點最多有兩個子節點。
1.實現二叉連結串列的結構:
//節點結構
template<class T>
struct BinaryTreeNode
{
BinaryTreeNode<T>* _left;//左子樹
BinaryTreeNode<T>* _right;//右子樹
T _data;//資料域
//建構函式
BinaryTreeNode(const T& x)
:_left(NULL)//左孩子指標
,_right(NULL)//右孩子指標
,_data(x)//資料域
{}
};
2.求二叉樹的葉子結點數_LeafSize:
葉結點:無後繼結點的結點。
方法一:設定一下全域性變數或者靜態變數的size,遍歷二叉樹,每次遇到一個節點就加加一次size;
方法二:遞迴實現,總葉結點數=左子樹葉結點個數+右子樹葉結點個數。
//方法1:後序遍歷統計葉子節點數
size_t _LeafSize(Node* root)
{
static int size = 0;
if (root == NULL)
{
return size;
}
if (root->_left == NULL&&root->_right == NULL)
{
size++;
return size;
}
_LeafSize(root->_left);
_LeafSize(root->_right);
}
//方法2:後序遞迴遍歷統計葉子節點數
size_t _LeafSize(Node* root)
{
if (root == NULL)
{
return 0;
}
else if (root->_left == NULL&&root->_right == NULL)
{
return 1;
}
else
{
return _LeafSize(root->_left) + _LeafSize(root->_right);
}
}
3.求二叉樹的深度_depth:
深度也稱作為高度,就是左子樹和右子樹深度的較大值。
size_t _Depth(Node* root)
{
if (root == NULL)
{
return 0;
}
int LeftDepth = _Depth(root->_left);
int RightDepth = _Depth(root->_right);
return (LeftDepth>RightDepth) ? LeftDepth + 1 : RightDepth + 1;
}
4.求二叉樹的結點個數_size:
總結點數=左子樹結點個數+右子樹結點個數+根結點個數1
size_t _Size(Node* root)
{
if (root == NULL)
{
return 0;
}
return _Size(root->_left) + _Size(root->_right) + 1;
}
5.求第k層節點數:(預設根節點為第1層)
方法與求葉結點同理。
size_t _kLevelSize(Node* root, int k)//預設根結點為第1層
{
assert(k > 0);
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return _kLevelSize(root->_left, k - 1) + _kLevelSize(root->_right, k - 1);
}
6.遍歷二叉樹:
6.1先序遍歷:訪問根結點->左子樹->右子樹
//先序遍歷:根結點->左子樹->右子樹
void _PrevOrder(Node* root)
{
if (root == NULL)
{
return;
}
cout << root->_data << " ";
_PrevOrder(root->_left);
_PrevOrder(root->_right);
}
6.2先序遍歷非遞迴寫法:
用棧模擬前序遍歷,棧的特點是後進先出,則將無條件地入棧根結點,在彈出根結點之前依次將根結點的右孩子結點和左孩子結點入棧。
//先序遍歷非遞迴,根結點->左子樹->右子樹,利用棧"後進先出"特點實現
void _PrevOrderNon_R(Node* root)
{
stack<Node*>s;
if (root == NULL)
{
return;
}
s.push(root);
while (!s.empty())
{
root = s.top();
cout << root->_data << " ";
s.pop();
if (root->_right)//注意要先壓入右結點,才能讓右結點後出
{
s.push(root->_right);
}
if (root->_left)
{
s.push(root->_left);
}
}
}
6.3中序遍歷:訪問左子樹->根結點->右子樹
//中序遍歷:左子樹->根結點->右子樹
void _InOrder(Node* root)
{
if (root == NULL)
{
return;
}
_InOrder(root->_left);
cout << root->_data << " ";
_InOrder(root->_right);
}
6.4中序遍歷非遞迴寫法:
二叉樹:
1
2 5
3 4 6
1、藉助棧實現,先順著二叉樹找到最左邊且最下邊的結點3(一邊找一邊入棧),此時入棧序列為1,2,3。
2、按照中序遍歷要彈出棧頂元素3,則彈出棧頂元素3。
3、接著是右子樹,判斷它的右子樹是否為空, 若為空,往回返,列印2,彈出棧頂元素2;若不為空, 該右子樹,指標指向右子樹結點,再重複之前的步驟1,2,3。
//中序遍歷非遞迴,最左結點cur是要訪問的第一個結點,先把左壓進去,然後把右樹當成子樹
void _InOrderNon_R(Node* root)
{
if (root == NULL)
{
return;
}
stack<Node*>s;
Node* cur = root;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
cur = s.top();//將棧頂元素儲存,以便後面判斷它是否有右孩子
cout << s.top()->_data << " ";
s.pop();
if (cur->_right == NULL)
{
cur = NULL;
}
else
{
cur = cur->_right;
}
}
}
6.5後序遍歷:訪問左子樹->右子樹->根結點
//後序遍歷:左子樹->右子樹->根結點
void _PostOrder(Node* root)
{
if (root == NULL)
{
return;
}
_PostOrder(root->_left);
_PostOrder(root->_right);
cout << root->_data << " ";
}
6.6後序遍歷非遞迴寫法:
1、後序遍歷同樣藉助棧實現,先找到最左邊且為最下面的結點3(一邊入棧一邊找);
2、結點3若沒有右孩子,列印節點3,之後彈出棧頂結點3;
3、結點3若有右孩子,繼續遍歷它的右子樹,等遍歷結束才可列印3。遍歷重複步驟1,2,3
//後序遍歷非遞迴:左子樹->右子樹->根結點,prev指向上一個剛剛訪問過的結點
void _PostOrderNon_R(Node* root)
{
if (root == NULL)
{
return;
}
stack<Node*>s;
Node* cur = root;
Node* prev = NULL;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
cur = s.top();//將棧頂元素儲存,以便後面判斷它是否有右孩子
//無右孩子和右孩子是剛剛被訪問過的結點,此時應該訪問根結點
if (cur->_right == NULL || cur->_right == prev)
{
cout << cur->_data << " ";
s.pop();
prev = cur;
cur = NULL;
}
else
{
cur = cur->_right;//除上面兩種情況,均不訪問根,繼續遍歷右子樹
}
}
}
6.7層序遍歷:
上一層遍歷結束,再遍歷下一層結點,如int arr1[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 }(#表示空),則層次遍歷就應為:1,2,5,3,4,6。
考慮用佇列解決該問題:首先先給佇列無條件入隊根結點,接著在出隊根結點之前先入隊它的子女結點2、5,則出隊1後,隊頭元素為2,在出隊它之前入隊它的根結點3,4……
//層序遍歷
void _LevelOrder(Node* root)
{
queue<Node*> q;
if (root == NULL)
{
return;
}
q.push(root);
while (!q.empty())
{
if (q.front()->_left != NULL)
{
q.push(q.front()->_left);
}
if (q.front()->_right != NULL)
{
q.push(q.front()->_right);
}
cout << q.front()->_data << " ";
q.pop();
}
}
完整程式碼實現:
#include<iostream>
using namespace std;
#include<assert.h>
#include<queue>
#include<stack>
//節點結構
template<class T>
struct BinaryTreeNode
{
BinaryTreeNode<T>* _left;//左子樹
BinaryTreeNode<T>* _right;//右子樹
T _data;//資料域
//建構函式
BinaryTreeNode(const T& x)
:_left(NULL)//左孩子指標
,_right(NULL)//右孩子指標
,_data(x)//資料域
{}
};
//二叉樹類
template<class T>
class BinaryTree
{
typedef BinaryTreeNode<T> Node;//Node結點結構
public:
BinaryTree()
:_root(NULL)
{}
//建構函式
BinaryTree(const T* arr, size_t size, const T& invalid)//arr為結點陣列,size為結點個數,invalid非法值
:_root(NULL)
{
size_t index = 0;//index指向結點的位置
_root = _CreateTree(arr, size, invalid, index);
}
//拷貝構造
BinaryTree<T>(const BinaryTree<T>& t)
: _root(NULL)
{
_root = _Copy(t._root);
}
////賦值運算子過載的傳統寫法
//BinaryTree<T>& operator=(const BinaryTree<T>& t)
//{
//if (&t != this)
//{
//_Copy(t._root);
//_Destroy(_root);
//}
//return *this;
//}
//賦值運算子過載的現代寫法
BinaryTree<T>& operator=(BinaryTree<T> t)
{
swap(this->_root, t._root);
return *this;
}
//解構函式
~BinaryTree()
{
if (_root)
{
_Destroy(_root);
}
}
//前序遍歷
void PreOrder()
{
_PrevOrder(_root);
cout << endl;
}
//前序遍歷非遞迴寫法
void PreOrderNon_R()
{
_PrevOrderNon_R(_root);
cout << endl;
}
//中序遍歷
void InOrder()
{
_InOrder(_root);
cout << endl;
}
//中序遍歷非遞迴寫法
void InOrderNon_R()
{
_InOrderNon_R(_root);
cout << endl;
}
//後序遍歷
void PostOrder()
{
_PostOrder(_root);
cout << endl;
}
//後序遍歷非遞迴寫法
void PostOrderNon_R()
{
_PostOrderNon_R(_root);
cout << endl;
}
//層序遍歷
void LevelOrder()
{
_LevelOrder(_root);
cout << endl;
}
//節點數
size_t Size()
{
return _Size(_root);
}
//深度(高度)
size_t Depth()
{
return _Depth(_root);
}
//葉子結點數(葉結點:沒有後繼的結點)
size_t LeafSize()
{
return _LeafSize(_root);
}
//第k層節點數
size_t kLevelSize(int k)
{
return _kLevelSize(_root, k);
}
//此處用protected和private都可,protected可被繼承,private不能被繼承,提高安全性
private:
Node* _CreateTree(const T* arr, size_t size, const T& invalid, size_t& index)
{
Node* root = NULL;
if (index < size&&arr[index] != invalid)
{
root = new Node(arr[index]);
root->_left = _CreateTree(arr, size, invalid, ++index);
root->_right = _CreateTree(arr, size, invalid, ++index);
}
return root;
}
Node* _Copy(Node* troot)
{
if (troot == NULL)
{
return NULL;
}
Node* root = new Node(troot->_data);
root->_left = _Copy(troot->_left);
root->_right = _Copy(troot->_right);
return root;
}
void _Destroy(Node* root)
{
if (root == NULL)
{
return;
}
if (root->_left == NULL&&root->_right == NULL)
{
delete root;
root = NULL;
return;
}
_Destroy(root->_left);
_Destroy(root->_right);
}
//方法1:後序遍歷統計葉子節點數
size_t _LeafSize(Node* root)
{
static int size = 0;
if (root == NULL)
{
return size;
}
if (root->_left == NULL&&root->_right == NULL)
{
size++;
return size;
}
_LeafSize(root->_left);
_LeafSize(root->_right);
}
////方法2:後序遞迴遍歷統計葉子節點數
//size_t _LeafSize(Node* root)
//{
//if (root == NULL)
//{
//return 0;
//}
//else if (root->_left == NULL&&root->_right == NULL)
//{
//return 1;
//}
//else
//{
//return _LeafSize(root->_left) + _LeafSize(root->_right);
//}
//}
size_t _Size(Node* root)
{
if (root == NULL)
{
return 0;
}
return _Size(root->_left) + _Size(root->_right) + 1;
}
size_t _Depth(Node* root)
{
if (root == NULL)
{
return 0;
}
int LeftDepth = _Depth(root->_left);
int RightDepth = _Depth(root->_right);
return (LeftDepth>RightDepth) ? LeftDepth + 1 : RightDepth + 1;
}
size_t _kLevelSize(Node* root, int k)//預設根結點為第1層
{
assert(k > 0);
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return _kLevelSize(root->_left, k - 1) + _kLevelSize(root->_right, k - 1);
}
//先序遍歷:根結點->左子樹->右子樹
void _PrevOrder(Node* root)
{
if (root == NULL)
{
return;
}
cout << root->_data << " ";
_PrevOrder(root->_left);
_PrevOrder(root->_right);
}
//先序遍歷非遞迴,根結點->左子樹->右子樹,利用棧"後進先出"特點實現
void _PrevOrderNon_R(Node* root)
{
stack<Node*>s;
if (root == NULL)
{
return;
}
s.push(root);
while (!s.empty())
{
root = s.top();
cout << root->_data << " ";
s.pop();
if (root->_right)//注意要先壓入右結點,才能讓右結點後出
{
s.push(root->_right);
}
if (root->_left)
{
s.push(root->_left);
}
}
}
//中序遍歷:左子樹->根結點->右子樹
void _InOrder(Node* root)
{
if (root == NULL)
{
return;
}
_InOrder(root->_left);
cout << root->_data << " ";
_InOrder(root->_right);
}
//中序遍歷非遞迴,最左結點cur是要訪問的第一個結點,先把左壓進去,然後把右樹當成子樹
void _InOrderNon_R(Node* root)
{
if (root == NULL)
{
return;
}
stack<Node*>s;
Node* cur = root;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
cur = s.top();//將棧頂元素儲存,以便後面判斷它是否有右孩子
cout << s.top()->_data << " ";
s.pop();
if (cur->_right == NULL)
{
cur = NULL;
}
else
{
cur = cur->_right;
}
}
}
//後序遍歷:左子樹->右子樹->根結點
void _PostOrder(Node* root)
{
if (root == NULL)
{
return;
}
_PostOrder(root->_left);
_PostOrder(root->_right);
cout << root->_data << " ";
}
//後序遍歷非遞迴:左子樹->右子樹->根結點,prev指向上一個剛剛訪問過的結點
void _PostOrderNon_R(Node* root)
{
if (root == NULL)
{
return;
}
stack<Node*>s;
Node* cur = root;
Node* prev = NULL;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
cur = s.top();//將棧頂元素儲存,以便後面判斷它是否有右孩子
//無右孩子和右孩子是剛剛被訪問過的結點,此時應該訪問根結點
if (cur->_right == NULL || cur->_right == prev)
{
cout << cur->_data << " ";
s.pop();
prev = cur;
cur = NULL;
}
else
{
cur = cur->_right;//除上面兩種情況,均不訪問根,繼續遍歷右子樹
}
}
}
//層序遍歷
void _LevelOrder(Node* root)
{
queue<Node*> q;
if (root == NULL)
{
return;
}
q.push(root);
while (!q.empty())
{
if (q.front()->_left != NULL)
{
q.push(q.front()->_left);
}
if (q.front()->_right != NULL)
{
q.push(q.front()->_right);
}
cout << q.front()->_data << " ";
q.pop();
}
}
private:
Node* _root;
};
void TestBinaryTree()
{
int arr1[10] = { 1,2,3,'#','#',4,'#','#',5,6 };
cout << "列印此二叉樹:"<<endl;
cout << " "<<arr1[0] <<endl;
cout << " " << arr1[1] << " " << arr1[8] << endl;
cout << arr1[2] << " " << arr1[5] << " " << arr1[9] << endl;
BinaryTree<int>t1(arr1, 10, '#');
cout << "先序遍歷:";
t1.PreOrder();
cout << "先序非遞迴遍歷:";
t1.PreOrderNon_R();
cout << "中序遍歷:";
t1.InOrder();
cout << "中序非遞迴遍歷:";
t1.InOrderNon_R();
cout << "後序遍歷:";
t1.PostOrder();
cout << "後序非遞迴遍歷:";
t1.PostOrderNon_R();
cout << "層序遍歷:";
t1.LevelOrder();
cout << "結點的總數:";
cout << t1.Size() << endl;
cout << "樹的深度:";
cout << t1.Depth() << endl;
cout << "葉結點的個數:";
cout << t1.LeafSize() << endl;
cout << "第3層結點的個數:";
cout << t1.kLevelSize(3) << endl;
}
int main()
{
TestBinaryTree();
system("pause");
return 0;
}
執行結果:
列印此二叉樹:
1
2 5
3 4 6
先序遍歷:1 2 3 4 5 6
先序非遞迴遍歷:1 2 3 4 5 6
中序遍歷:3 2 4 1 6 5
中序非遞迴遍歷:3 2 4 1 6 5
後序遍歷:3 4 2 6 5 1
後序非遞迴遍歷:3 4 2 6 5 1
層序遍歷:1 2 5 3 4 6
結點的總數:6
樹的深度:3
葉結點的個數:3
第3層結點的個數:3
請按任意鍵繼續. . .
相關推薦
二叉樹的先序、中序、後序遍歷等基本操作c++實現
二叉樹:樹的每個節點最多有兩個子節點。1.實現二叉連結串列的結構://節點結構template<class T>struct BinaryTreeNode{BinaryTreeNode<T>* _left;//左子樹BinaryTreeNode<
第六章樹和二叉樹作業1—二叉樹--計算機17級 7-1 根據後序和中序遍歷輸出先序遍歷 (25 分)
7-1 根據後序和中序遍歷輸出先序遍歷 (25 分) 本題要求根據給定的一棵二叉樹的後序遍歷和中序遍歷結果,輸出該樹的先序遍歷結果。 輸入格式: 第一行給出正整數N(≤30),是樹中結點的個數。隨後兩行,每行給出N個整數,分別對應後序遍歷和中序遍歷結果,數字間以空
劍指offer之求二叉樹的深度(非遞迴的層次遍歷)Java實現
劍指offer上一道比較基礎的題目,但這個解法不僅可以求二叉樹的深度同時可以求二叉樹的最大層數,某一層的某一個節點 是一種比較通用的方法! 先建立資料模型 package Binary_tree; public class Node {//二叉樹節點 priva
二叉樹的高度 java 利用遞迴和層次遍歷兩種方法
原文:http://blog.csdn.net/fangchao3652/article/details/53456468 ackage edu.lnu.fang.BiTree; import java.util.ArrayList; import java.util.L
二叉樹(建立,節點個數,高度,遍歷)
二叉樹的基礎 今天學習了二叉樹,有點膨脹,趕緊寫個部落格記下來,不然又忘記了。 直接在程式碼裡面解釋吧。。。 package BinaryTreeText; import java.util.Stack; /** * 二叉樹 * */ publi
二叉樹的構建,遍歷等基本操作
#include"stdio.h" #include"stdlib.h" #include"string.h" typedef struct BTNode { char data; struct BTNode *lchild,*rchild; }B
騰訊大牛教你如何使用Java實現二叉樹的添加,刪除,獲取以及遍歷
二叉樹的遍歷 測試結果 技術 boolean 代碼 tro parent 二叉樹 當前 一段來自百度百科的對二叉樹的解釋: 在計算機科學中,二叉樹是每個結點最多有兩個子樹的樹結構。通常子樹被稱作“左子樹”(left subtree)和“右子樹”(right subtree)
二叉樹先序遍歷、中序遍歷和後序遍歷
二叉樹 com size 基本 html 後序 href col spa 轉自:https://www.cnblogs.com/polly333/p/4740355.html 基本思想>> 先序遍歷:根——>左——>右 先序遍歷:左——>
數據結構 遞歸和非遞歸方式實現二叉樹先序、中序和後序遍歷
nor post 後序遍歷 order else 對象 二叉樹先序 bre print 二叉樹的先序遍歷順序是根、左、右;中序遍歷順序是左、根、右;後序遍歷順序是左、右、根。 遞歸方式實現如下: 1 public class TreeNode { 2
鏈式二叉樹 先序、中序、後序 遍歷(遞迴、非遞迴)
參考部落格:click here! 鏈式二叉樹儲存結構: typedef int DataType; typedef struct BiNode { DataType data; struct BiNode *lc, *rc; // 左右子節點指標 int depth; } B
二叉樹先序遍歷、中序遍歷、後序遍歷的遞迴演算法與非遞迴演算法
首先是二叉樹資料結構的定義: typedef struct TNode *Position; typedef Position BinTree; /* 二叉樹型別 */ struct TNode{ /* 樹結點定義 */ int Data; /* 結點資料 */ BinTre
3.1分別用遞迴和非遞迴方式實現二叉樹先序、中序和後序遍歷
題目 用遞迴和非遞迴方式,分別按照二叉樹先序、中序和後序列印所有的節點。 首先給出二叉樹節點結構定義: public class BinaryTreeNode { //二叉樹節點 private int data; private Bi
二叉樹先序、中序、後序遞迴&&非遞迴
這三種遍歷,遞迴方式都很簡單,大概就圍繞著這樣一個順序: 先序:根左右,中序:左根右,後序:左右根。 對於非遞迴方式:由於採用棧(先進後出)這種資料結構儲存結點,因此,結點入棧時需要考慮順序和原來相反。 先序和中序都比較簡單,後序相對較難,在程式碼中敘述。 先序:首先
學習筆記-二叉樹-先序、中序、後序、層次遍歷的實現(Python)
一、二叉樹類的Python實現及其函式:包括統計結點個數,用遞迴實現的先序遍歷,非遞迴實現的先序遍歷,以及非遞迴實現的後序遍歷。class StackUnderflow(ValueError): pass class SStack(): d
二叉樹先中後序遍歷(遞迴、非遞迴方法)、層序遍歷 Java實現
第一部分:二叉樹結點的定義 二叉樹結點有三個屬性:資料域、左結點、右結點。構造方法寫三個引數,這樣建立結點的時候程式碼更簡潔,且要從葉子結點開始建立(從底往上建立)。注:如果只寫一個賦值引數的構造器,那麼建立節點的順序就無所謂了,但是建立二叉樹時要多寫幾行程式碼。 pack
[C/C++] 先序建立二叉樹| 先序、中序、後序遍歷二叉樹| 求二叉樹深度、節點數、葉節點數 演算法實現
/* * BinTree.h */ #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #defi
用遞迴方式實現二叉樹先序、中序、後序遍歷
先序遍歷:中、左、右 中序遍歷:左、中、右 後序遍歷:左、右、中 比如下面這科樹 1 2 3 4 5 6 7 packag
PAT-A1020:Tree Traversal(二叉樹的重建及其中序、後序遍歷)
題目傳送門:https://pintia.cn/problem-sets/994805342720868352/problems/994805485033603072 目錄 題目解釋: 解題思路: ac程式碼: 題目解釋: 給出一棵二叉樹(binary tree)的後
二叉樹先序中序後序遍歷實現
一、遞迴實現 import java.util.*; /* public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int
非遞迴建立二叉樹 先序 中序 後序遍歷
思想:用”棧”來消除遞迴。 主要是建立的過程,剛開始卡到了如果遇到’#’,那麼在else中間出棧之後還需要讀一個元素,這樣在遇到連續的”#”之後,退棧並不能達到合適的位置,最後聽了“巔峰”的建議,還是設定了flag,解決了問題,下面解釋下建立過程的思想: