二叉树详解-第四篇 二叉树链式结构的实现


目录

​编辑

1.二叉树的遍历

1.1前序遍历:

1.2 中序遍历:

1.3 后序遍历:

2.二叉树链式结构的实现

2.1 Tree.h

2.2 Tree.cpp

2.2.1 前序遍历 void PreOrder(TNode* Root)

2.2.2 中序遍历 void InOrder(TNode* Root)

2.2.3 后序遍历 void BacOrder(TNode* Root)

2.2.4 求树的总节点数 int Treesize(TNode* root)

2.2.5 求叶子结点数 int Leafsize(TNode* root)

2.2.6 求树的高度 int Treeheight(TNode* root)

2.2.7 求二叉树第K层节点数 int Knum(TNode* root,int k)

2.2.8 查找节点为x值所在节点指针 TNode* Treefind(TNode* root, TreeType x)

2.2.9 二叉树的销毁 void TreeDestory(TNode* root)

2.2.10 层序遍历 void TreeLeveorder(TNode* root)

2.2.11 判断一棵树是否为完全二叉树 bool JudgeTree(TNode* root)


1.二叉树的遍历

前序遍历:根 左子树 右子树

中序遍历:左子树 根 右子树

后序遍历:左子树 右子树 根

1.1前序遍历:

(根左右)

                                

                        图1                                                                              图2

首先我们要把所有子树空的地方写上N(代表NULL),如图2。

1.首先从1开始出发,1作为根,2是1的左子树,4是1的右子树,输出1,然后进入2。

遍历序列:1 

2. 进入2后,2作为根,3作为2的左子树,N作为2的右子树,输出2,然后进入3。

遍历序列:1 2

3.进入3后,3作为根,N为3的左子树,N为3的右子树,输出3,然后进入左子树的N。

遍历序列:1 2 3

4.进入N后,遇到了N,就输出N,并返回到根(3)。

遍历序列:1 2 3 N

5.返回3后,根和左子树都已经输出,进入右子树的N。同时遇到了N打印并返回。

遍历序列:1 2 3 N N

6.再次返回到了3,根 左子树 右子树 都已经输出了,所以再次返回3的根(2)。返回2后,2作为根,2的左子树已经输出,所以进入2的右子树(N),因为右子树为N,所以输出N即可。

遍历序列:1 2 3 N N N

7. 2作为根,2的左子树右子树有已经输出了,返回2的根(1)。返回1后,1作为根,1的左子树已经输出,直接进入1的右子树(4)即可,进入4后,4作为根,先输出4,然后在进入4的左子树。

遍历序列:1 2 3 N N N 4

8.进入5后,5作为根,所以先输出5,然后进入5的左子树,左子树为N,输出N,然后进入5的右子树,右子树也为N,输出N。

遍历序列:1 2 3 N N N 4 5 N N 

9. 5和他的左子树右子树都已经输出,此时返回到5的根(4),4作为根,4的左子树已经输出,此时进入4的右子树(6) ,进入6后,6作为根,先输出6;输出6后进入6的左子树,左子树为N,输出N。然后进入6的右子树,右子树为N,输出N。

遍历序列:1 2 3 N N N 4 5 N N 6 N N

1.2 中序遍历:

(左根右)

                                 

                        图1                                                                              图2

1.首先进入1,1作为根,由于是左跟右,所以还不能输出1,要先进入1的左子树(2),进入2后,2作为根,还要进入2的左子树(3),进入3后,3作为根,要先进入3的左子树(N),3的左子树为N,直接输出N,输出N后,左子树已经输出,3作为根,此时可以输出3,3输出后,在进入3的右子树,3的右子树为N,输出N即可。

遍历序列:N 3 N 

2. 3作为根的子树已经全部输出,此时返回到3的根(2),2作为根,2的左子树(3)已经输出,此时输出根(2),输出根后,再输出2的右子树(N),右子树为N,直接输出N。

遍历序列:N 3 N 2 N 

3. 2作为根的子树已经全部输出,此时返回到2的根(1),1作为根,1的左子树(2)已经输出,此时输出根(1),输出根后,再进入右子树(4),4作为根,要先进入4的左子树(5),5作为根,5的左子树为N,直接输出N,输出N后再输出根(5),输出5,输出5后再进入5的右子树(N),输出N;

遍历序列:N 3 N 2 N 1 N 5 N 

4.  5的子树全部输出,此时返回到5的根(4),4作为根,4的左子树(5)输出,此时可以输出根(4),输出根后,再进入根的右子树(6),6作为根,要先进入6的左子树,左子树为N,输出N,然后返回到根(6),此时输出根(6),输出根后,进入6的右子树,右子树为N,输出N。

遍历序列:N 3 N 2 N 1 N 5 N 4 N 6 N

1.3 后序遍历:

(左右根)

                                 

                        图1                                                                              图2

1.首先进入1,1作为根,先进入1的左子树(2),2作为根,先进入2的左子树(3),3作为根,先进入3的左子树(N),输出N并返回到根(3),再进入3的右子树(N),输出N并返回到根(3),3作为根,3的左子树和右子树都已经输出,所以此时输出3,输出3后返回到3的根(2)。

遍历序列:N N 3

2. 进入2后,2作为根,2的左子树已经输出,再进入2的右子树,2的右子树为N, 输出N并且返回到根,2作为根,2的左子树和右子树都已经输出,此时可以输出根(2),输出2并且返回2的根(1)。

遍历序列:N N 3 N 2 

3.进入1后,1作为根,1的左子树已经输出,再进入1的右子树(4),4作为根,先进入4的左子树(5),5作为根,先进入5的左子树(N),左子树为N,输出N并且返回到根(5),5作为根,再进入5的右子树,5的右子树为N,输出N并返回到根,5的左子树和右子树都已经输出,此时输出5并且返回到5的根(4)。

遍历序列:N N 3 N 2 N N 5

4. 进入4后,4作为根,4的左子树已经输出,进入4的右子树(6),6左右根,先进入6的左子树N,输出N并返回到根,再进入6的右子树N,输出N并返回到根。6作为根,其左子树和右子树都已经输出,此时输出6并且返回到6的根(4),4作为根,4的左子树和右子树都已经输出,此时输出4并且返回到4的根(1)。

遍历序列:N N 3 N 2 N N 5 N N 6 4

5.进入1后,1作为根,1的左子树和右子树都已经输出,此时输出1。

遍历序列:N N 3 N 2 N N 5 N N 6 4 1


2.二叉树链式结构的实现

2.1 Tree.h

源码:

#define _CRT_SECURE_NO_WARNINGS 1

#pragma once
#include<iostream>
#include<algorithm>
using namespace std;

typedef int TreeType;

typedef struct Tree
{
	TreeType val;
	struct Tree* left;
	struct Tree* right;
}TNode;

void PreOrder(TNode* root);//前序遍历
void InOrder(TNode* Root);//中序遍历
void BacOrder(TNode* Root);//后序遍历
int Treesize(TNode* root);//求节点数
int Leafsize(TNode* root);//求叶子节点数
int Treeheight(TNode* root);//求树高度
int Knum(TNode* root, int k);//第K层结点数
TNode* Treefind(TNode* root, TreeType x);//查找节点为x值所在节点指针

2.2 Tree.cpp

源码:

#include"Tree.h"




void PreOrder(TNode* Root)
{
	if (Root == NULL)
	{
		cout << "N ";
		return;
	}
	cout << Root->val << " ";
	PreOrder(Root->left);
	PreOrder(Root->right);

}



void InOrder(TNode* Root)
{
	if (Root == NULL)
	{
		cout << "N ";
		return;
	}
	InOrder(Root->left);
	cout << Root->val << " ";
	InOrder(Root->right);

}


void BacOrder(TNode* Root)
{
	if (Root == NULL)
	{
		cout << "N ";
		return;
	}
	BacOrder(Root->left);
	BacOrder(Root->right);
	cout << Root->val << " ";
}


int Treesize(TNode* root)//求节点数
{
	if (root == NULL)
	{
		return 0;
	}
	else
	{
		return Treesize(root->left) + Treesize(root->right) + 1;
	}

}

int Leafsize(TNode* root)//求叶子节点数
{
	if (root == NULL) {
		return 0;
	}
	if (root->left == root->right == NULL) {
		return 1;
	}
	return Leafsize(root->left) + Leafsize(root->right);

}

int Treeheight(TNode* root)//求树高度
{
	if (root == NULL) {
		return 0;
	}
	int leftnum = Treeheight(root->left);
	int rightnum = Treeheight(root->right);


	return leftnum > rightnum ? leftnum + 1 : rightnum + 1;

}

int Knum(TNode* root,int k)//二叉树第k层节点个数
{

	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}

	return Knum(root->left,k-1) + Knum(root->right,k-1);

}


TNode* Treefind(TNode* root, TreeType x)//查找节点为x值所在节点指针
{
	if (root == NULL) {
		return NULL;
	}
	if (root->val == x) {
		return root;
	}

	TNode* ret1 = Treefind(root->left, x);
	if (ret1) {
		return ret1;
	
	}

	TNode* ret2 = Treefind(root->right, x);
	if (ret2) {
		return ret2;

	}
	return NULL;

}

2.2.1 前序遍历 void PreOrder(TNode* Root)

void PreOrder(TNode* Root)
{
	if (Root == NULL)
	{
		cout << "N ";
		return;
	}
	cout << Root->val << " ";
	PreOrder(Root->left);
	PreOrder(Root->right);

}

1.先输出节点的值,再进行左子树遍历和右子树遍历

2.2.2 中序遍历 void InOrder(TNode* Root)

void InOrder(TNode* Root)
{
	if (Root == NULL)
	{
		cout << "N ";
		return;
	}
	InOrder(Root->left);
	cout << Root->val << " ";
	InOrder(Root->right);

}

1.先递归左子树,在输出节点值,再递归右子树。

2.2.3 后序遍历 void BacOrder(TNode* Root)

void BacOrder(TNode* Root)
{
	if (Root == NULL)
	{
		cout << "N ";
		return;
	}
	BacOrder(Root->left);
	BacOrder(Root->right);
	cout << Root->val << " ";
}

1.先递归左子树和右子树,最后输出节点值。

2.2.4 求树的总节点数 int Treesize(TNode* root)

int Treesize(TNode* root)//求节点数
{
	if (root == NULL)
	{
		return 0;
	}
	else
	{
		return Treesize(root->left) + Treesize(root->right) + 1;
	}

}

1.如果遇到空节点(N),就返回0,其余情况返回左右子树递归+1。

2.2.5 求叶子结点数 int Leafsize(TNode* root)

int Leafsize(TNode* root)//求叶子节点数
{
	if (root == NULL) {
		return 0;
	}
	if (root->left == root->right == NULL) {
		return 1;
	}
	return Leafsize(root->left) + Leafsize(root->right);

}

1.遇到空节点就返回0。

2.叶子节点的特点是其左右孩子都为空,则当if (root->left == root->right == NULL)成立时,返回1.

3.其余情况返回左子树递归+右子树递归。

2.2.6 求树的高度 int Treeheight(TNode* root)

int Treeheight(TNode* root)//求树高度
{
	if (root == NULL) {
		return 0;
	}
	int leftnum = Treeheight(root->left);
	int rightnum = Treeheight(root->right);


	return leftnum > rightnum ? leftnum + 1 : rightnum + 1;

}

1.当为空节点时,返回0。

2.用leftnum存储左子树的层数,用rightnum存储右子树的层数,两者返回最大者+1.

2.2.7 求二叉树第K层节点数 int Knum(TNode* root,int k)

int Knum(TNode* root,int k)//二叉树第k层节点个数
{

	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}

	return Knum(root->left,k-1) + Knum(root->right,k-1);

}

1.如果时空节点,则返回0。

2.当k==1时,则此时在第K层的某个节点上,则返回1即可。

3.其余情况返回Knum(root->left,k-1) + Knum(root->right,k-1)。

2.2.8 查找节点为x值所在节点指针 TNode* Treefind(TNode* root, TreeType x)

TNode* Treefind(TNode* root, TreeType x)//查找节点为x值所在节点指针
{
	if (root == NULL) {
		return NULL;
	}
	if (root->val == x) {
		return root;
	}

	TNode* ret1 = Treefind(root->left, x);
	if (ret1) {
		return ret1;
	
	}

	TNode* ret2 = Treefind(root->right, x);
	if (ret2) {
		return ret2;

	}
	return NULL;

}

1.如果当前节点的值等于要查找的值,则返回该节点的地址。

2.用ret1和ret2接收Treefind(root->left, x)的返回值和Treefind(root->right, x)的返回值,如果其中有一个不为空指针,则说明找到了,就立马返回这个地址。

3.其余情况返回NULL即可。

2.2.9 二叉树的销毁 void TreeDestory(TNode* root)

void TreeDestory(TNode* root)//二叉树的销毁
{

	if (root == NULL) {
		return;
	}
	TreeDestory(root->left);
	TreeDestory(root->right);
	free(root);

}

1.必须遍历左右子树,再释放空间,否则释放节点后就会导致找不到左右子树。

2.2.10 层序遍历 void TreeLeveorder(TNode* root)

void TreeLeveorder(TNode* root)//层序遍历
{
	queue<TNode*>q;

	if (root) {
		q.push(root);
	}

	while (q.size())
	{
		TNode* cur = q.front();
		q.pop();

		cout << cur->val << " ";
		if (cur->left)
		{
			q.push(cur->left);
		}

		if (cur->right)
		{
			q.push(cur->right);
		}

	}

}

2.2.11 判断一棵树是否为完全二叉树 bool JudgeTree(TNode* root)

bool JudgeTree(TNode* root)
{
	queue<TNode*>q;

	if (root) {
		q.push(root);
	}

	while (q.size())
	{
		TNode* cur = q.front();
		q.pop();

		if (cur == NULL)//出现第一个空
		{
			break;//退出
		}
		if (cur->left)
		{
			q.push(cur->left);
		}

		if (cur->right)
		{
			q.push(cur->right);
		}

	}

	while (q.size())
	{
		if (q.front() != NULL) {
			return false;
		}
		q.pop();
	}

	return true;

}

1.首先层序遍历,遇到队列中第一个空就退出循环,然后判断队列中是否还有非空节点,如果还有非空节点,则不是完全二叉树,反之则为完全二叉树。

2.不可能出现,遇到空时,后面还有非空没进队列,后面非空,一定前面非空的孩子。当层序到空时,前面的非空都出完了,那他的孩子一定进队列了。


本篇完

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mike!

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值