[Day15]程序菜鸟自学C++资料结构演算法 – 二元树的基本应用

前言:介绍完了二元树的建立和走访方式,紧接着要来介绍其他基本应用,一样用上一篇的程序码进行修改

可以先把之前的程序码改成T指针类型,後续的操作会比较方便,更改方式如图:
注意!!! BiTree()原本T的地方改成root,避免命名重复导致程序错误(一开始命名的不好是我的疏忽˃ʍ˂)
https://ithelp.ithome.com.tw/upload/images/20210929/20140187m6PnzUYGRJ.png
https://ithelp.ithome.com.tw/upload/images/20210929/20140187Ruwfy72tE8.png
接着就可以开始实作罗

1.求二元树的深度
https://ithelp.ithome.com.tw/upload/images/20210929/20140187p0edTYZPBC.png

可以看到树的深度如预期的一样为3
https://ithelp.ithome.com.tw/upload/images/20210929/20140187gTmmwRHEHi.png

2.计算树的叶节点数目
https://ithelp.ithome.com.tw/upload/images/20210929/20140187u9kFmP0NZX.png

可以看到叶节点的各数为4(DEFG)。
https://ithelp.ithome.com.tw/upload/images/20210929/20140187CEnWcn24Pq.png
也可以把判断式改成if (!T->Lchild && !T->Rchild || !T->Lchild && T->Rchild)则可以检查多余的节点,来判断是否为严格二元树。

3.利用空节点标记符号(#)来建立二元树
相信很多人不懂这题的意思,其实是在走访节点的下一个节点不存在时(没有子节点),输出一个#。

先修改之前的前序走访作为范例。
https://ithelp.ithome.com.tw/upload/images/20210929/20140187b6LnLZ9XZc.png

这样做的意义在哪呢?
这样做是方便还原二元树的样貌,如果没有这些符号,二元树会有多种可能,不只是人,连电脑也无法判断出这个二元树原本的样貌,来实际画画看就知道了。
https://ithelp.ithome.com.tw/upload/images/20210929/20140187hNAh84PDJo.png
左节点优先权大於右节点,所以都是先从左边开始画

接着我们现在要做的就是输入一串带有空节点符号的前序序列,来让电脑建立二元树
https://ithelp.ithome.com.tw/upload/images/20210929/20140187g1mHUFmAgm.png

接着输入前序串列
https://ithelp.ithome.com.tw/upload/images/20210929/20140187oWGikKPohl.png

如果有跑出结果就代表建立成功,顺便检查和第三行是不是一样
https://ithelp.ithome.com.tw/upload/images/20210929/20140187QiLhm8Voct.png
这种方法也可以用在另外三种走访方式,有兴趣的人可以自己操作看看

今日小结:今天讲了一些常见但实用的小技巧,尤其是第三个利用空节点符号转回二元树的方法,算是相当重要的必备技能,其实树还有非常多衍生跟应用,只不过也是会花太多篇幅,有机会再向大家介绍,树的部分先告一段落,明天也将要进入新的环节。

#include<iostream>
using T = char;
#include<queue>
using namespace std;

template<typename T>
class BiTree {
public:
	struct BiNode {
		T data;
		BiNode* Lchild{ 0 };
		BiNode* Rchild{ 0 };
	};

	BiNode* root;
	BiTree() {
		root = PreCreat(); //因为要建立新的二元树,所以原本的可以先注解掉
		/*
		root = new BiNode(); root->data = 'A';
		root->Lchild = new BiNode(); root->Lchild->data = 'B';
		root->Rchild = new BiNode(); root->Rchild->data = 'C';
		BiNode* P = root->Lchild;
		P->Lchild = new BiNode(); P->Lchild->data = 'D';
		P->Rchild = new BiNode(); P->Rchild->data = 'E';
		BiNode* S = root->Rchild;
		S->Lchild = new BiNode(); S->Lchild->data = 'F';
		S->Rchild = new BiNode(); S->Rchild->data = 'G';
		*/
	}
	void Inorder(BiNode* T) {
		if (!T)return;
		Inorder(T->Lchild);
		std::cout << T->data << " ";
		Inorder(T->Rchild);
	}

	void Preorder(BiNode* T) {
		if (!T) {
			std::cout << "#" << " ";
			return;
		} 
		std::cout << T->data;
		Preorder(T->Lchild);
		Preorder(T->Rchild);
	}

	void Postorder(BiNode* T) {
		if (!T)return;
		Postorder(T->Lchild);
		Postorder(T->Rchild);
		std::cout << T->data << " ";
	}
	void Level_order(BiNode* T) {
		queue<BiNode*> Q;
		Q.push(T);
		while (!Q.empty()) {
			BiNode* p = Q.front();
			Q.pop();
			std::cout << p->data << " ";
			if (p->Lchild) Q.push(p->Lchild);
			if (p->Rchild) Q.push(p->Rchild);
		}
	}
	void Inorder() {
		Inorder(root);
	}
	void Preorder() {
		Preorder(root);
	}
	void Postorder() {
		Postorder(root);
	}
	void Level_order() {
		Level_order(root);
	}
	int Depth(BiNode* T){
		if (!T) return 0;
		int L = Depth(T->Lchild);
		int R = Depth(T->Rchild);
		return L > R ? L + 1 : R + 1; //如果L>R,那麽树深将会是L的深度+1,否则是R的深度+1
	}
	int Depth() {
		return Depth(root);
}
	int Count(BiNode* T) {
		if (!T) return 0;
		int L = Count(T->Lchild);
		int R = Count(T->Rchild);
		if (!T->Lchild && !T->Rchild) //如果Lchild不为0且Rchild不为0
			return L + R + 1;
		else
			return L + R;
	}
	int Count() {
		return Count(root);
	}
	BiNode* PreCreat() {
		T e;
		std::cin >> e;
		if (e == '#') return 0;
		BiNode* J = new BiNode();
		J->data = e;
		J->Lchild = PreCreat();
		J->Rchild = PreCreat();
		return J;
	}
};

using T = char;
int main() {
	BiTree<char> bt;
	bt.Inorder(); std::cout << "\n";
	bt.Preorder(); std::cout << "\n";
	bt.Postorder(); std::cout << "\n";
	bt.Level_order(); std::cout << "\n";
	std::cout << std::endl;

	std:cout<<bt.Count()<< "\n";
}

<<:  SQL资料库基础实作

>>:  android studio 30天学习笔记-day 14-databinding 单向绑定

Day 0x15 UVa10056 What is the Probability ?

Virtual Judge ZeroJudge 题意 输入玩家数与成功机率,输出 I-th 玩家成...

Ruby on Rails CRUD 之 R(Read)

CRUD 之 R(Read) 从资料表里读取资料也是很常⾒的操作,在读取的⽅法就比写入来得多样化,有...

WSL2/ WSLg下使用snap store

更多会员限定文章可以到patreon观看 WSLg + Snap 如果清除/snap後还是不能mou...

CMoney工程师战斗营weekly5

鬼门关前走一遭生死一瞬间的一周 事情是这样的,由於一个月前的我刚进入战斗营,对物件导向的概念还是非常...

铁人赛 Day11-- PHP SQL基本语法(六) -- INSERT 基本语法

INSERT 基本语法 INSERT INTO '资料表名称'('栏位名称1','栏位名称2',.....