【数据结构】二叉树

(一) 基础知识

在这里插入图片描述

树的深度:任意节点到根节点的唯一路径长
树的高度:从某一叶节点数到它的根节点的最长路径长;

(二) 相关存储结构

① 数组存储(需要数学关系确定数据之间的关系)
在这里插入图片描述

② 链式存储

1.二叉链式存储
在这里插入图片描述

2.三叉链式存储
在这里插入图片描述

③静态存储
在这里插入图片描述

以下目录需要

头文件:

#include<iostream>
using namespace std;
#include<stack>
#include<queue>
#include<stdlib.h>

二叉树节点结构体:

typedef struct BtNode
{
    struct BtNode* leftchild;
    struct BtNode* rightchild;
    int data;
}BtNode,*BinartTree;

构建一个二叉树节点

BtNode* BuyNode()
{
	BtNode* s=(BtNode*)malloc(sizeof(BtNode));
	if(s==NULL) {exit(1);}
	memset(s,0,sizeof(BtNode));
	return s;
}

(三) 递归遍历二叉树

1.先序递归遍历

先序遍历:根左右----->先根再左子树再右子树
例如:
在这里插入图片描述

void PreOrder(BtNode *ptr)
{
	if(ptr!=NULL)
	{
		cout<<" "<<ptr->data;
		PreOrder(ptr->leftchild);
		PreOrder(ptr->rightchild);
	}
}

2.中序递归遍历

中序遍历:左根右----->先左子树再根再右子树
例如:
在这里插入图片描述

void InOrder(BtNode *ptr)
{
	if(ptr!=NULL)
	{
		InOrder(ptr->leftchild);
		cout<<" "<<ptr->data;
		InOrder(ptr->rightchild);
	}
}

3.后序递归遍历

后序遍历:左右根----->先左子树再右子树再根
例如:
在这里插入图片描述

void PastOrder(BtNode *ptr)
{
    if(ptr!=NULL)
	{
		PastOrder(ptr->leftchild);
		PastOrder(ptr->rightchild);
		cout<<" "<<ptr->data;
	}
}

(四) 构建二叉树

1.字符串构建

BtNode* CreateBtStr(const char*& str)
{
	BtNode* s = NULL;
	if (*str != '#')
	{
		s = BuyNode();
		s->data = *str;
		s->leftchild = CreateBtStr(++str);
		s->rightchild = CreateBtStr(++str);
	}
	return s;
}

BtNode* CreateTreeStr(const char* str)
{
	if (str == NULL || strlen(str) <= 0)
	{
		cout << "无字符串来构建二叉树" << endl;
		return NULL;
	}
	else
	{
		return CreateBtStr(str);
	}
}

主函数:

int main()
{
	const char* str = "ABC##DE##F##G#H##";
	BinaryTree root = CreateTreeStr(str);
	cout << " 先序:";
	PreOrder(root);
	cout << endl;

	cout << " 中序:";
	InOrder(root);
	cout << endl;

	cout << " 后序:";
	PastOrder(root);
	cout << endl;
	return 0;
}

运行结果:
在这里插入图片描述

注意:CreateBtStr(const char * &str)中参数str前一定要加&符,如果不加结果如下
在这里插入图片描述

造成这样结果的原因是:
在这里插入图片描述

总结:如果不加&每一次递归时 都会有不一样的str,因此无法将字符串全部遍历;加了&后 每次递归的str都是同一个值

2.用先序中序构建(面试常考)

在这里插入图片描述

int FindPos(const char* istr,const char ch)
{
	int len = strlen(istr);
	int pos = -1;
	for (int i = 0; i < len; i++)
	{
		if (istr[i] == ch)
		{
			pos = i;
			break;
		}
	}
	return pos;
}

BtNode* CreateBTreePI(const char* pstr, const char* istr, int n)
{
	BtNode* s = NULL;
	if (n > 0)
	{
		s = BuyNode();
		s->data = pstr[0];
		int pos = FindPos(istr, pstr[0]);
		s->leftchild = CreateBTreePI(pstr + 1, istr, pos);
		s->rightchild = CreateBTreePI(pstr + pos + 1, istr + pos + 1, n - pos - 1);
	}
	return s;
}

主函数:

int main()
{
	const char* pstr = { "ABCDEFGH" };
	cout << " pstr = " << pstr;
	cout << endl;
	const char* istr = { "CBEDFAGH" };
	cout << " istr = " << istr;
	cout << endl;
	BinaryTree root = CreateBTreePI(pstr, istr, strlen(pstr));
	if (root != NULL)
	{
		cout << " (二叉树构建完成) " << endl;
	}
	cout << " 先序遍历结果: ";
	PreOrder(root);
	cout << endl;
	cout << " 中序遍历结果: ";
	InOrder(root);
	cout << endl;
	return 0;
}

运行结果:
在这里插入图片描述

2.用中序后序构建

在这里插入图片描述

int FindPos(const char* istr,const char ch)
{
	int len = strlen(istr);
	int pos = -1;
	for (int i = 0; i < len; i++)
	{
		if (istr[i] == ch)
		{
			pos = i;
			break;
		}
	}
	return pos;
}

BtNode* CreateBTreeIL(const char* istr, const char* lstr, int n)
{
	BtNode* s = NULL;
	if (n > 0)
	{
		s = BuyNode();
		s->data = lstr[n-1];
		int pos = FindPos(istr, lstr[n-1]);
		s->leftchild = CreateBTreeIL(istr, lstr, pos);
		s->rightchild = CreateBTreeIL(istr + pos + 1, lstr + pos, n - pos - 1);
	}
	return s;
}

主函数:

int main()
{
	const char* istr = { "CBEDFAGH" };
	cout << " istr = " << istr;
	cout << endl;
	const char* lstr = { "CEFDBHGA" };
	cout << " lstr = " << lstr;
	cout << endl;
	BinaryTree root = CreateBTreeIL(istr, lstr, strlen(lstr));
	if (root != NULL)
	{
		cout << " (二叉树构建完成) " << endl;
	}
	cout << " 中序遍历结果: ";
	InOrder(root);
	cout << endl;
	cout << " 后序遍历结果: ";
	PastOrder(root);
	cout << endl;
	return 0;
}

运行结果:
在这里插入图片描述

(五) 非递归遍历二叉树

1.先序非递归遍历

(需要使用栈)
注意:需要先入右孩子再入左孩子,这样出栈才能达到先左后右(先进后出)
在这里插入图片描述

void NicePreOrder(BtNode* ptr)
{
	if (ptr == NULL)
	{
		cout << "二叉树为空";
		return;
	}
	std::stack<BtNode*> st;
	st.push(ptr);
	while (!st.empty())
	{
		ptr = st.top();
		cout << " " << ptr->data;
		st.pop();
		if (ptr->rightchild != NULL)
		{
			st.push(ptr->rightchild);
		}
		if(ptr->leftchild!=NULL)
		{
			st.push(ptr->leftchild);
		}
	}
}

主函数:

int main()
{
	const char* str = "ABC##DE##F##G#H##";
	BinaryTree root = CreateTreeStr(str);
	cout << " 非递归先序:";
	NicePreOrder(root);
	cout << endl;
	return 0;
}

运行结果:
在这里插入图片描述

2.中序非递归遍历

第一种方法

在这里插入图片描述

(需要使用栈)

void NiceInOrder(BtNode* ptr)
{
	if (ptr == NULL)
	{
		cout << "二叉树为空";
		return;
	}
	std::stack<BtNode*> st;
	while (!st.empty() || ptr != NULL)
	{
		while (ptr != NULL)
		{
			st.push(ptr);
			ptr = ptr->leftchild;
		}
		ptr = st.top();
		cout << " " << ptr->data;
		st.pop();
		ptr = ptr->rightchild;
	}
}

主函数:

int main()
{
	const char* str = "ABC##DE##F##G#H##";
	BinaryTree root = CreateTreeStr(str);
	cout << " 非递归中序:";
	NiceInOrder(root);
	cout << endl;
	return 0;
}

运行结果:
在这里插入图片描述

第二种方法

(需要使用栈)

需要额外定义一个结构体来存放指向二叉树节点的指针和保存出栈次数的整数
在这里插入图片描述

struct StkNode
{
	BtNode* pnode;
	int popnum;
};
void NiceInOrder_2(BtNode* ptr)
{
	if (ptr == NULL)
	{
		cout << "二叉树为空" << endl;
	}
	std::stack<StkNode> st;
	st.push(StkNode{ ptr,0 });
	while (!st.empty())
	{
		StkNode node = st.top();
		st.pop();
		int t = ++node.popnum;
		if (t == 2)
		{
			cout << " " << node.pnode->data;
			if (node.pnode->rightchild != NULL)
			{
				st.push(StkNode{ node.pnode->rightchild,0 });
			}
		}
		else
		{
			st.push(node);
			if (t == 1 && node.pnode->leftchild != NULL)
			{
				st.push(StkNode{ node.pnode->leftchild,0 });
			}
		}
	}
}

主函数:

int main()
{
	const char* str = "ABC##DE##F##G#H##";
	BinaryTree root = CreateTreeStr(str);
	cout << " 第二种 非递归中序:";
	NiceInOrder_2(root);
	cout << endl;
	return 0;
}

运行结果:
在这里插入图片描述

3.后序非递归遍历

第一种方法

(需要使用栈)
在这里插入图片描述

void NicePastOrder(BtNode* ptr)
{
	if (ptr == NULL)
	{
		cout << "二叉树为空";
		return;
	}
	std::stack<BtNode*> st;
	BtNode* tag=NULL;
	while (ptr != NULL || !st.empty())
	{
		while (ptr != NULL)
		{
			st.push(ptr);
			ptr = ptr->leftchild;
		}
		ptr = st.top();
		st.pop();
		if (ptr->rightchild == NULL || ptr->rightchild == tag)
		{
			cout << " " << ptr->data;
			tag = ptr;
			ptr = NULL;
		}
		else
		{
			st.push(ptr);
			ptr = ptr->rightchild;
		}
	}
}

主函数:

int main()
{
	const char* str = "ABC##DE##F##G#H##";
	BinaryTree root = CreateTreeStr(str);
	cout << " 第一种 非递归后序:";
	NicePastOrder(root);
	cout << endl;
	return 0;
}

运行结果:
在这里插入图片描述

第二种方法

需要额外定义一个结构体来存放指向二叉树节点的指针和保存出栈次数的整数

在这里插入图片描述

struct StkNode
{
	BtNode* pnode;
	int popnum;
};
void NicePastOrder_2(BtNode* ptr)
{
	if (ptr == NULL)
	{
		cout << "二叉树为空";
		return;
	}
	std::stack<StkNode> st;
	st.push(StkNode{ ptr,0 });
	while (!st.empty())
	{
		StkNode node = st.top();
		st.pop();
		int t = ++node.popnum;
		if (t == 3)
		{
			cout << " " << node.pnode->data;
		}
		else
		{
			st.push(node);
			if (t == 1 && node.pnode->leftchild != NULL)
			{
				st.push(StkNode{ node.pnode->leftchild,0 });
			}
			else if (t == 2 && node.pnode->rightchild != NULL)
			{
				st.push(StkNode{ node.pnode->rightchild,0 });
			}
		}
	}
}

主函数:

int main()
{
	const char* str = "ABC##DE##F##G#H##";
	BinaryTree root = CreateTreeStr(str);
	cout << " 第二种 非递归后序:";
	NicePastOrder_2(root);
	cout << endl;
	return 0;
}

运行结果:
在这里插入图片描述

(六)层次遍历二叉树

(需要使用队列)
在这里插入图片描述

void LevelOrder(BtNode* ptr)
{
	if (ptr == NULL)
	{
		cout << "二叉树为空" << endl;
	}
	std::queue<BtNode*> qu;
	qu.push(ptr);
	while (!qu.empty())
	{
		ptr = qu.front();
		cout << " " << ptr->data;
		qu.pop();
		if (ptr->leftchild != NULL)
		{
			qu.push(ptr->leftchild);
		}
		if (ptr->rightchild != NULL)
		{
			qu.push(ptr->rightchild);
		}
	}
}

主函数:

int main()
{
	const char* str = "ABC##DE##F##G#H##";
	BinaryTree root = CreateTreeStr(str);
	cout << " 层次遍历:";
	LevelOrder(root);
	return 0;
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

逐梦的白鹰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值