文章目录
1.二叉树
1.1主要性质
-
① n 0 = n 2 + 1 ( 推 导 过 程 : ① n = n 0 + n 1 + n 2 , ② 总 节 点 数 = 总 分 支 数 + 1 即 , n = n 1 + 2 n 2 + 1 ) ①n_0=n2+1(推导过程:①n=n_0+n_1+n_2,②总节点数=总分支数+1即,n=n_1+2n_2+1) ①n0=n2+1(推导过程:①n=n0+n1+n2,②总节点数=总分支数+1即,n=n1+2n2+1)
-
② 第 i 层 最 多 有 2 i − 1 个 节 点 ②第i层最多有2^{i-1}个节点 ②第i层最多有2i−1个节点
-
③ 高 度 为 h , 则 最 多 2 k − 1 个 节 点 ③高度为h,则最多2^k-1个节点 ③高度为h,则最多2k−1个节点
-
④ C a t a l a n ( ) : 给 定 n 个 节 点 , 能 构 成 h ( n ) = C 2 n n n + 1 种 不 同 的 二 叉 树 ④Catalan():给定n个节点,能构成h(n)=\frac{C_{2n}^n}{n+1}种不同的二叉树 ④Catalan():给定n个节点,能构成h(n)=n+1C2nn种不同的二叉树
-
⑤ 完 全 二 叉 树 高 度 : h = ⌊ l o g 2 n ⌋ + 1 ⑤完全二叉树高度:h=\lfloor log_2n\rfloor+1 ⑤完全二叉树高度:h=⌊log2n⌋+1
-
⑥ 节 点 编 号 ( 从 上 到 下 , 从 左 到 右 依 次 编 号 ) 关 系 ⑥节点编号(从上到下,从左到右依次编号)关系 ⑥节点编号(从上到下,从左到右依次编号)关系
PS:下表中除法不为整数时,均向下取整。i为某节点a的编号
条件 关系 i ≠ 1 i\neq1 i=1 ⌊ i / 2 ⌋ \lfloor i/2\rfloor ⌊i/2⌋ 2 i ≤ n 2i\le n 2i≤n a 左 孩 子 : 2 i a左孩子:2i a左孩子:2i 2 i > n 2i > n 2i>n a 无 左 孩 子 a无左孩子 a无左孩子 2 i + 1 ≤ n 2i +1\le n 2i+1≤n a 右 孩 子 : 2 i + 1 a右孩子:2i+1 a右孩子:2i+1 2 i + 1 > n 2i +1> n 2i+1>n a 无 右 孩 子 a无右孩子 a无右孩子
1.2存储结构
typedef struct BTNode{
char data;
struct BTNode * lchild;
struct BTNode * rchild;
}BTNode;
1.3遍历算法
//节点访问
void visit(BTNode *p)
{
if(p!=NULL)
cout<<p->data<<" ";
else
cout<<"NULL POINTER!"<<endl;
}
1.3.1先序(根)遍历
void preorder(BTNode *p)
{
if(p!=NULL)
{
visit(p);
preorder(p->lchild);
preorder(p->rchild);
}
}
1.3.2中序(根)遍历
void inorder(BTNode *p)
{
if(p!=NULL)
{
inorder(p->lchild);
visit(p);
inorder(p->rchild);
}
}
1.3.3后序(根)遍历
void postorder(BTNode *p)
{
if(p!=NULL)
{
postorder(p->lchild);
postorder(p->rchild);
visit(p);
}
}
1.3.4层次遍历
void levelTraversal(BTNode *p)
{
int front=0,rear=0;
BTNode * que[MAXN];
BTNode * top;
if(p!=NULL){
rear=(rear+1)%MAXN;
que[rear]=p;//入队
while(front!=rear){//队不空时
front=(front+1)%MAXN;//出队
top=que[front]; //访问出队节点
visit(top);
if(top->lchild!=NULL){
rear=(rear+1)%MAXN;
que[rear]=top->lchild;
}
if(top->rchild!=NULL){
rear=(rear+1)%MAXN;
que[rear]=top->rchild;
}
}
}
}
//层次遍历简化版本
void levelTraversal(BTNode *p)
{
int front=0,rear=0;
BTNode * que[MAXN];
BTNode * top;
if(p!=NULL){
que[++rear]=p;
while(front!=rear){
top=que[++front];//出队
visit(top);
if(top->lchild!=NULL){
que[++rear]=top->lchild;
}
if(top->rchild!=NULL){
que[++rear]=top->rchild;
}
}
}
}
1.4线索化
1.4.1中序线索化
typedef struct TBTNode
{
char data;
int ltag,rtag;
struct TBTNode * lchild;
struct TBTNode * rchild;
}TBNode;
//中序线索化
void inThread(TBTNode *p,TBTNode * &pre)
{
if(p!=NULL)
{
inThread(p->lchild,pre);//线索化左子树
if(p->lchild==NULL){
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL&&p->rchild!=NULL){
pre->rchild=p;
pre->rtag=1;
}
pre=p;
inThread(p->rchild,pre);
}
}
1.5完整代码
#include<bits/stdc++.h>
#define MAXN 100
using namespace std;
typedef struct BTNode{
char data;
struct BTNode * lchild;
struct BTNode * rchild;
}BTNode;//二叉树节点
typedef struct TBTNode
{
char data;
int ltag,rtag;
struct TBTNode * lchild;
struct TBTNode * rchild;
}TBNode;//线索二叉树节点
BTNode* create();//二叉树的创建
void visit(BTNode *p);//节点访问
void preorder(BTNode *p);//先序(根)遍历
void inorder(BTNode *p);//中序(根)遍历
void postorder(BTNode *p);//后序(根)遍历
void levelTraversal(BTNode *p);//层次遍历
//二叉树的创建
BTNode* create()
{
char root;
BTNode *p=NULL;
cin>>root;
if(root=='0')return p;
else {
p=new BTNode;
p->data=root;
cout<<"请输入"<<root<<"的左子节点(输入0表示空节点):";
p->lchild=create();
cout<<"请输入"<<root<<"的右子节点(输入0表示空节点):";
p->rchild=create();
}
return p;
}
//节点访问
void visit(BTNode *p)
{
if(p!=NULL)
cout<<p->data<<" ";
else
cout<<"NULL POINTER!"<<endl;
}
//先序(根)遍历
void preorder(BTNode *p)
{
if(p!=NULL)
{
visit(p);
preorder(p->lchild);
preorder(p->rchild);
}
}
//中序(根)遍历
void inorder(BTNode *p)
{
if(p!=NULL)
{
inorder(p->lchild);
visit(p);
inorder(p->rchild);
}
}
//后序(根)遍历
void postorder(BTNode *p)
{
if(p!=NULL)
{
postorder(p->lchild);
postorder(p->rchild);
visit(p);
}
}
//层次遍历
void levelTraversal(BTNode *p)
{
int front=0,rear=0;
BTNode * que[MAXN];
BTNode * top;
if(p!=NULL){
rear=(rear+1)%MAXN;
que[rear]=p;//入队
while(front!=rear){//队不空时
front=(front+1)%MAXN;//出队
top=que[front]; //访问出队节点
visit(top);
if(top->lchild!=NULL){
rear=(rear+1)%MAXN;
que[rear]=top->lchild;
}
if(top->rchild!=NULL){
rear=(rear+1)%MAXN;
que[rear]=top->rchild;
}
}
}
}
//层次遍历
void levelTraversal2(BTNode *p)
{
int front=0,rear=0;
BTNode * que[MAXN];
BTNode * top;
if(p!=NULL){
que[++rear]=p;
while(front!=rear){
top=que[++front];//出队
visit(top);
if(top->lchild!=NULL){
que[++rear]=top->lchild;
}
if(top->rchild!=NULL){
que[++rear]=top->rchild;
}
}
}
}
//中序线索化
void inThread(TBTNode *p,TBTNode * &pre)
{
if(p!=NULL)
{
inThread(p->lchild,pre);//线索化左子树
if(p->lchild==NULL){
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL&&p->rchild!=NULL){
pre->rchild=p;
pre->rtag=1;
}
pre=p;
inThread(p->rchild,pre);
}
}
int main()
{
cout<<"请输入根节点(输入0表示空节点):";
BTNode * root=create();
levelTraversal2(root);//层次遍历
return 0;
}
2.树
2.1存储结构
2.1.1双亲表示法
2.1.2孩子链表法
2.1.3孩子兄弟表示法
2.2树、森林、二叉树的转换
原理:由于树和二叉树都可以用二叉链表作存储结构,则以二叉链表作媒介可以导出树与二叉树之间的一个对应关系。
只需掌握一个实质:二叉树本质就是一个二叉链表,在表现形式上进行了一定角度的旋转。
在前面写二叉树时,我们通常这样定义
typedef struct BTNode{
char data;
BTNode * lchild;
BTNode * rchild;
}BTNode;
1.此时的指针域表示,左孩子和右孩子。
2.而在树、森林、二叉树的转换中,二叉树的指针域则为child和sibling(兄弟)。
之所以这样存储,是因为树、森林可能不止两个孩子,用上述左孩子、右孩子方法存储不了,故使用左孩子、右兄弟的存储方法。但他们的本质都是二叉链表。