1. 程式人生 > >【樹】二叉樹的各種操作

【樹】二叉樹的各種操作

BinaryTree.h

#ifndef BINARYTREE_H
#define BINARYTREE_H

#include<iostream>
#include<stack>
#include<queue>
//binary tree node
struct binary_tree_node{
	char data;
	binary_tree_node* lchild;
	binary_tree_node* rchild;
	binary_tree_node() :lchild(NULL), rchild(NULL){}
	binary_tree_node(char ch) :data(ch), lchild(NULL), rchild(NULL){}
};
//BinaryTree
class BinaryTree{
public:
	typedef binary_tree_node node_value;
	typedef binary_tree_node* node_pointer;
	BinaryTree();
	~BinaryTree();
	node_pointer get_root();
	void create_preorder(node_pointer& p);

	void preorder_recursive(node_pointer p);
	void inorder_recursive(node_pointer p);
	void postorder_recursive(node_pointer p);

	void preorder_no_recursive(node_pointer p);
	void preorder_no_recursive2(node_pointer p);
	void inorder_no_recursive(node_pointer p);
	void postorder_no_recursive(node_pointer p);

	void levelorder(node_pointer p);
	void tree_depth(node_pointer p, int& depth, int level);
	int leaf_count(node_pointer p);
	int node_count(node_pointer p);
private:
	void destroy(node_pointer p);
private:
	node_pointer root;
};

BinaryTree::BinaryTree() :root(NULL){}
BinaryTree::~BinaryTree(){
	destroy(root);
	root = NULL;
}
void BinaryTree::destroy(node_pointer p){
	if (p == NULL)
		return;
	destroy(p->lchild);
	destroy(p->rchild);
	delete p;
}
BinaryTree::node_pointer BinaryTree::get_root(){
	return root;
}
void BinaryTree::create_preorder(node_pointer& p){
	char ch;
	std::cin >> ch;
	if (ch == '#')
		p = NULL;
	else{
		p = new node_value(ch);
		create_preorder(p->lchild);
		create_preorder(p->rchild);
	}
}
void BinaryTree::preorder_recursive(node_pointer p){
	if (p == NULL)
		return;
	std::cout << p->data << ' ';
	preorder_recursive(p->lchild);
	preorder_recursive(p->rchild);
}
void BinaryTree::inorder_recursive(node_pointer p){
	if (p == NULL)
		return;
	inorder_recursive(p->lchild);
	std::cout << p->data << ' ';
	inorder_recursive(p->rchild);
}
void BinaryTree::postorder_recursive(node_pointer p){
	if (p == NULL)
		return;
	postorder_recursive(p->lchild);
	postorder_recursive(p->rchild);
	std::cout << p->data << ' ';
}
/*
先讓根進棧,只要棧不為空,就可以做彈出操作,
每次彈出一個結點,就把它的右孩子和左孩子依次入棧,這樣可以保證右子樹在棧中總處於左子樹的下面。
*/
void BinaryTree::preorder_no_recursive(node_pointer p){
	if (p == NULL)
		return;
	std::stack<node_pointer> stk;
	stk.push(p);
	while (!stk.empty()){
		node_pointer cur = stk.top();
		std::cout << cur->data << ' ';
		stk.pop();
		if (cur->rchild)
			stk.push(cur->rchild);
		if (cur->lchild)
			stk.push(cur->lchild);
	}
}
/*
對於任一結點P:
1)訪問結點P,並將結點P入棧;
2)判斷結點P的左孩子是否為空,若為空,則取棧頂結點並進行出棧操作,並將棧頂結點的右孩子置為當前的結點P,迴圈至1);
若不為空,則將P的左孩子置為當前的結點P;
3)直到P為NULL並且棧為空,則遍歷結束。
*/
void BinaryTree::preorder_no_recursive2(node_pointer p){
	if (p == NULL)
		return;
	std::stack<node_pointer> stk;
	node_pointer cur = p;
	while (cur != NULL || !stk.empty()){
		while (cur != NULL){
			std::cout << cur->data << ' ';
			stk.push(cur);
			cur = cur->lchild;
		}
		if (!stk.empty()){
			cur = stk.top();
			stk.pop();
			cur = cur->rchild;
		}
	}
}
/*
對於任一結點P,
1)若其左孩子不為空,則將P入棧並將P的左孩子置為當前的P,然後對當前結點P再進行相同的處理;
2)若其左孩子為空,則取棧頂元素並進行出棧操作,訪問該棧頂結點,然後將當前的P置為棧頂結點的右孩子;
3)直到P為NULL並且棧為空則遍歷結束
*/
void BinaryTree::inorder_no_recursive(node_pointer p){
	if (p == NULL)
		return;
	std::stack<node_pointer> stk;
	node_pointer cur = p;
	while (cur != NULL || !stk.empty()){
		while (cur != NULL){
			stk.push(cur);
			cur = cur->lchild;
		}
		if (!stk.empty()){
			cur = stk.top();
			std::cout << cur->data << ' ';
			stk.pop();
			cur = cur->rchild;
		}
	}
}
/*
對於任一結點P,先將其入棧。如果P不存在左孩子和右孩子,則可以直接訪問它;
或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了,也可以直接訪問它。
若非上述兩種情況,則將P的右孩子和左孩子依次入棧,這樣就保證了
左孩子在右孩子前面被訪問,左孩子和右孩子都在根結點前面被訪問。
*/
void BinaryTree::postorder_no_recursive(node_pointer p){
	if (p == NULL)
		return;
	std::stack<node_pointer> stk;
	stk.push(p);
	node_pointer cur;
	node_pointer pre = NULL;
	while (!stk.empty()){
		cur = stk.top();
		if ((cur->lchild == NULL&&cur->rchild == NULL) || pre != NULL && (cur->lchild == pre || cur->rchild == pre)){
			std::cout << cur->data << ' ';
			stk.pop();
			pre = cur;
		}
		else{
			if (cur->rchild)
				stk.push(cur->rchild);
			if (cur->lchild)
				stk.push(cur->lchild);
		}
	}
}
/*
先讓根進佇列,只要佇列不為空,就可以做pop操作,
每次pop一個結點,就把它的左孩子和右孩子依次入佇列,這樣可以保證層次遍歷。
*/
void BinaryTree::levelorder(node_pointer p){
	if (p == NULL)
		return;
	std::queue<node_pointer> que;
	que.push(p);
	while (!que.empty()){
		node_pointer temp = que.front();
		std::cout << temp->data << ' ';
		if (temp->lchild)
			que.push(temp->lchild);
		if (temp->rchild)
			que.push(temp->rchild);
		que.pop();
	}
}
void BinaryTree::tree_depth(node_pointer p, int& depth, int level){
	if (p == NULL)
		return;
	if (level>depth)
		depth = level;
	tree_depth(p->lchild, depth, level + 1);
	tree_depth(p->rchild, depth, level + 1);
}
int BinaryTree::leaf_count(node_pointer p){
	if (p == NULL)
		return 0;
	else if (p->lchild == NULL&&p->rchild == NULL)
		return 1;
	else
		return (leaf_count(p->lchild) + leaf_count(p->rchild));
}
int  BinaryTree::node_count(node_pointer p){
	if (p == NULL)
		return 0;
	else
		return (1 + node_count(p->lchild) + node_count(p->rchild));
}

#endif
main.cpp
#include"BinaryTree.h"
using namespace std;

void menu(){
	cout << "========================================================================" << endl;
	cout << "1.輸入字元序列,以先序序列建立二叉樹!" << endl;
	cout << "2.先序、中序、後序遍歷二叉樹(遞迴演算法)!" << endl;
	cout << "3.先序、中序、後序遍歷二叉樹(非遞迴演算法)!" << endl;
	cout << "4.層次遍歷二叉樹!" << endl;
	cout << "5.求二叉樹的高度!" << endl;
	cout << "6.求二叉樹的葉子個數!" << endl;
	cout << "7.求二叉樹的節點個數!" << endl;
	cout << "0.退出程式!" << endl;
	cout << "========================================================================" << endl;
}

int main(){
	int choose;
	int depth;
	int level;
	bool flag = true;
	BinaryTree binary_tree;
	binary_tree_node* root = binary_tree.get_root();
	while (flag){
		menu();
		cout << "請輸入要選擇的功能:";
		cin >> choose;
		switch (choose){
		case 1:
			cout << "請輸入二叉樹中的元素,空的左右孩子以#替代:" << endl;
			binary_tree.create_preorder(root);
			break;
		case 2:
			cout << "先序遍歷:" << endl;
			binary_tree.preorder_recursive(root);
			cout << endl << "中序遍歷:" << endl;
			binary_tree.inorder_recursive(root);
			cout << endl << "後序遍歷:" << endl;
			binary_tree.postorder_recursive(root);
			cout << endl;
			break;
		case 3:
			cout << "先序遍歷:" << endl;
			cout << "方法一:";
			binary_tree.preorder_no_recursive(root);
			cout << endl << "方法二:";
			binary_tree.preorder_no_recursive2(root);
			cout << endl << "中序遍歷:" << endl;
			binary_tree.inorder_no_recursive(root);
			cout << endl << "後序遍歷:" << endl;
			binary_tree.postorder_no_recursive(root);
			cout << endl;
			break;
		case 4:
			cout << "層次遍歷:" << endl;
			binary_tree.levelorder(root);
			cout << endl;
			break;
		case 5:
			depth = 1;
			level = 1;
			binary_tree.tree_depth(root, depth, level);
			cout << "二叉樹的高度為:" << depth << endl;
			break;
		case 6:
			cout << "二叉樹的葉子個數為:" << binary_tree.leaf_count(root) << endl;
			break;
		case 7:
			cout << "二叉樹的節點個數為:" << binary_tree.node_count(root) << endl;
			break;
		case 0:
			flag = false;
			break;
		default:
			cout << "輸入錯誤,請重新輸入" << endl;
		}
	}

	return 0;
}

參考:

相關推薦

各種操作

BinaryTree.h #ifndef BINARYTREE_H #define BINARYTREE_H #include<iostream> #include<stack> #include<queue> //binary tr

遍歷算法(深度優先、廣度優先遍歷,前序、中序、後序、層次)及Java實現

order new link left 算法 很多 == 都是 off 二叉樹是一種非常重要的數據結構,很多其它數據結構都是基於二叉樹的基礎演變而來的。對於二叉樹,有深度遍歷和廣度遍歷,深度遍歷有前序、中序以及後序三種遍歷方法,廣度遍歷即我們平常所說的層次遍歷。因為樹的定義

遍歷總結

struct left else oot nor 節點 操作 preorder AC   節點定義如下 1 // Definition for a binary tree node. 2 struct TreeNode { 3 int val; 4 Tre

----

bec size 某個結點 vpd ima idt max-width usr oot 1 樹的基本概念(1)樹是由若幹結點組成的具有層次關系的集合,非空樹有且只有一個根結點(/)。(2)某個結點及其下面所有的結點並稱為以該結點為根的子樹(usr及其下的所有結點就是/的一顆

leetcode94的中序遍歷

寫在最前面: 很常規的一道二叉樹的基本操作,最偷懶的辦法是遞迴,不需要想那麼多。 給定一個二叉樹,返回它的中序 遍歷。 示例: 輸入: [1,null,2,3] 1 \ 2 / 3 輸出: [1,3,2] 進階: 遞

演算法 in python | 遍歷

二叉樹深度優先遍歷:先序遍歷,中序遍歷,後序遍歷的遞迴與非遞迴。 二叉樹廣度優先遍歷:層次遍歷。 class TreeNode: def __init__(self, x): self.val = x self.left = None

演算法前序、中序、後序遍歷相互求法(轉)

二叉樹前序、中序、後序遍歷相互求法 原文地址      今天來總結下二叉樹前序、中序、後序遍歷相互求法,即如果知道兩個的遍歷,如何求第三種遍歷方法,比較笨的方法是畫出來二叉樹,然後根據各種遍歷不同的特性來求,也可以程式設計求出,下面我們分別說明。  

演算法的遞迴和非遞迴遍歷(轉)

原文地址 【寫在前面】   二叉樹是一種非常重要的資料結構,很多其它資料結構都是基於二叉樹的基礎演變而來的。對於二叉樹,有前序、中序以及後序三種遍歷方法。因為樹的定義本身就 是遞迴定義,因此採用遞迴的方法去實現樹的三種遍歷不僅容易理解而且程式碼很簡潔。而對於樹的遍歷若採用非遞迴的方法,就要採

演算法的廣度遍歷

廣度優先遍歷的核心思想如下:從根節點開始遍歷,然後遍歷其子節點,再從左至右的,依次遍歷其孫子節點的,以此類推,直到完成整顆二叉樹的遍歷。          50    20        &nbs

數論的基礎知識

性質 在二叉樹的第i層上最多有2i-1個結點。 深度為k的二叉樹至多有2k-1個結點。 對於任意一棵二叉樹,如果其葉節點數為n0,度為2的結點數為n2,則一定滿足n0 = n2 + 1。 具有n個結點的完全二叉樹的深度為floor(log2n + 1)。 對於任意一棵具有n個結點

模板的遍歷

目錄   先序遍歷 中序遍歷 後序遍歷 按層遍歷     先序遍歷   先遍歷根結點,再遍歷左結點,最後遍歷右結點。 int n; int lt[MAX_N], rt[MAX_N]; // 如果沒有則為-1

LeetCode的前序遍歷

題目 給定一個二叉樹,返回它的 前序 遍歷。 示例: 輸入: [1,null,2,3] 1     \        2     / 3 public class Solution { p

leetcode的最大深度。

題目要求 二叉樹最大深度 給定一個二叉樹,找出其最大深度 二叉樹的深度為根節點到最遠葉子節點的最長路徑上的節點數 說明:葉子節點是指沒有子節點的節點 示例: 給定二叉樹:[3,9,20,null,null,15,7] 返回它的最大深度 3。

leetcode的遍歷。

題目要求 二叉樹的遍歷。 核心思想 利用佇列的特性來實現二叉樹的遍歷。 完整程式碼如下 import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.

c++的線索化

什麼是二叉樹的線索化?或者問什麼是線索二叉樹? 按照某種遍歷方式對二叉樹進行遍歷,可以把二叉樹中所有結點排序為一個線性序列。在改序列中,除第一個結點外每個結點有且僅有一個直接前驅結點;除最後一個結點外

模板合集

1501 二叉樹最大寬度和高度 時間限制: 1 s 空間限制: 128000 KB 題目等級 : 白銀 Silver 題解 題目描述 Description 給出一個二叉樹,輸出它的最大寬度和高度。 輸入描述 Input Descr

劍指offer題解C++24中和為某一值的路徑

題目描述 輸入一顆二叉樹和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。 解題思路 按照先序遍歷將結點加入路徑,如果當前結點是葉子結點則判斷當前路徑和是否為目標數,若滿足條件

證明—— 的相關證明

0. 簡單結論 對於堆,子樹的最大節點數為 2/3n;(樹的最底層恰好半滿) 0 層節點數:20=120=1 1層節點數:21=221=2 m-1 層節點數:2m−12m−1,一半有左右孩子,2m

LeetCodePython的最大深度

題目給定一個二叉樹,找出其最大深度。二叉樹的深度為根節點到最遠葉子節點的最長路徑上的節點數。說明: 葉子節點是指沒有子節點的節點。示例:給定二叉樹 [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7返

演算法的遞迴遍歷C語言實現

二叉樹是一種極其重要的資料結構,以下是二叉樹的結構定義 建立 和遞迴先序 中序 後序 遍歷的程式碼. #include<stdio.h> #include<stdlib.h> typedef char ElemType; /*二叉樹節點資料