【数据结构】树

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+1n=n0+n1+n2,=+1n=n1+2n2+1

  • ② 第 i 层 最 多 有 2 i − 1 个 节 点 ②第i层最多有2^{i-1}个节点 i2i1

  • ③ 高 度 为 h , 则 最 多 2 k − 1 个 节 点 ③高度为h,则最多2^k-1个节点 h2k1

  • ④ 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()nhn=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 2in a 左 孩 子 : 2 i a左孩子:2i a2i
    2 i > n 2i > n 2i>n a 无 左 孩 子 a无左孩子 a
    2 i + 1 ≤ n 2i +1\le n 2i+1n a 右 孩 子 : 2 i + 1 a右孩子:2i+1 a2i+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(兄弟)。

之所以这样存储,是因为树、森林可能不止两个孩子,用上述左孩子、右孩子方法存储不了,故使用左孩子、右兄弟的存储方法。但他们的本质都是二叉链表。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值