数据结构和算法4(树)

树的定义

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结点的层次从根开始定义,根是第一层,根的孩子是第二层。树中结点的最大层次称为树的深度或高度。
如果将树中结点的各子树看成从左至右是有次序的,不可互换的,那该树就是有序树,否则为无序树。
森林是m(m>=0)棵互不相交的树的集合。

树的存储结构

双亲表示法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
孩子表示法
由于树中每个结点都有可能有多棵子树,可以考虑用多重链表实现
在这里插入图片描述
方案一:根据树的度,声明足够的空间存放子树指针(浪费)
在这里插入图片描述
方案二:
在这里插入图片描述
虽然解决了空间浪费问题,但初始化和维护太麻烦
方案三
在这里插入图片描述
对于孩子表示法,查找某个结点的某个孩子,或者找某个结点的兄弟,只需要查找这个结点的孩子单链表即可。但是当要寻找某个结点的双亲时,就不是那么方便了。所以可以将双亲表示法和孩子表示法结合,形成双亲孩子表示法
方案四:
在这里插入图片描述
在这里插入图片描述

孩子兄弟表示法

任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟存在也是唯一的。因此,设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟。

/* 树的孩子兄弟表示法结构定义*/
#define MAX_TREE_SIZE 100
typedef int  ElemeType;

typedef struct CSNode{
    ElemeType data;
    struct CSNode * firstchild;
    struct CSNode * rightsib;
    
}CSNode, *CSTree;

二叉树

在这里插入图片描述
特殊二叉树
斜树
在这里插入图片描述
满二叉树
在一棵二叉树中,如果所有分支节点都存在左子树和右子树,并且所有的叶子都在同一层上,这样的二叉树称为满二叉树。
特点:叶子只能在最下面那一层;非叶子节点的度一定是2;
在同样深度的二叉树中,满二叉树的结点个数一定最多,同时叶子也最多。
完全二叉树
在这里插入图片描述
在这里插入图片描述
二叉树的性质
性质一:在二叉树的第i层上至多有2^(i-1)个结点,i >= 1
性质二:深度为k的二叉树至多有(2^k) - 1个结点,k >=1
性质三:
在这里插入图片描述
性质四:具有n个结点的完全二叉树的深度为 下限【log2n】+1
性质五:
在这里插入图片描述
二叉树的存储结构
二叉树是一种特殊的树,顺序存储和链式存储结构都能简单实现。二叉树的顺序存储结构就是用一维数组存储二叉树中的各个结点,并且结点的存储位置能体现结点之间的逻辑关系。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二叉树的遍历

前序遍历
若二叉树为空,则空操作返回,否则先访问根节点,然后前序遍历左子树,再前序遍历右子树。ABDH IEJC FKG
在这里插入图片描述
中序遍历
若树为空,则空操作返回,否则从根节点开始(不是先访问根节点),中序遍历根节点的左子树,然后访问根节点,最后中序遍历右子树。
在这里插入图片描述
后序遍历
若树为空, 则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后访问根节点。
在这里插入图片描述
层序遍历
ABCDEFG…

二叉树的建立和遍历代码
在这里插入图片描述

typedef char ElemType;
typedef strut BiTNode{
	char data;
	struts BiTNode *lchild, *rchild;
} BiTNode, *BiTree;

//创建一棵二叉树;按照前序遍历的方式输入数据
CreateBiTree(BiTree *T){
	char c;
	scanf("%c", c);
	if('' == c){
		*T = NULL;
	} else {
		*T = (BiTNode *)malloc(sizeof(BiTNode));
		(*T) -> data = c;
		CreateBiTree(&(*T) -> lchild);
		CreateBiTree(&(*T) -> rchild);
	}
}

// 访问二叉树结点的具体操作
visit(char c, int level){
	printf("%c位于第%d层\n", c , level);
}

// 前序遍历
PreOrderTraverse(BiTree T, int level) {
	if(T) {
		visit(T->data, level);
		PreOrderTraverse(T->lchild, level + 1);
		PreOrderTraverse(T->rchild, level + 1);
	}
}

int main(){
	int level = 1;
	BiTree T = NULL;
	CreateBiTree(&T);
	PreOrderTraverse(T, level);
	return 0;
}

线索二叉树

利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前驱和后继结点的指针(这种附加的指针称为"线索")。
在这里插入图片描述
现将二叉树的结点结构重新定义如下:
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>

typedef char ElemType;

//线索存储标志位
//Link(0)表示指向左右孩子的指针
//Thread(1)表示指向前驱后继的线索
typedef enum {Link, Thread} PointerTag;

typedef struct BiThrNode{
	char data;
	struct BiThrNode *lchild,*rchild;
	PointerTag ltag;
	PointerTag rtag;
} BiThrNode, *BiThrTree;

// 全局变量,始终指向刚刚访问过得结点
BiThrTree pre;

//创建二叉树,约定用户遵照前序遍历的方式输入数据
CreateBiThrTree(BiThrTree *T){
	char c;

	scanf("%c", &c);
	if('' == c){
		*T = NULL;
	} else {
		*T = (BiThrNode *)malloc(sizeof(BiThrNode));
		(*T) -> data = c;
		(*T) -> ltag = Link;
		(*T) -> rtag = Link;

		CreateBiThrTree(&(*T) -> lchild);
		CreateBiThrTree(&(*T) -> rchild);
	}
}

// 中序遍历线索化
InThreading(BiThrTree T){
	if(T){
		InThreading(T -> lchild); //递归使左孩子线索化

		if(!T -> lchild){
			T -> ltag = Thread;
			T -> lchild = pre;
		}

		if(!pre -> rchild){
			pre -> rtag = Thread;
			pre -> rchild = T;
		}

		pre = T;

		InThreading(T -> rchild); //递归使you孩子线索化
	}
}

InOrderThreading(BiThrTree *p, BiThrTree T){
	*p = (BiThrTree)malloc(sizeof(BiThrNode));
	(*p) -> ltag = Link;
	(*p) -> rtag = Thread;
	(*p) -> rchild = *p;
	if(!T){
		(*p) -> lchild = *p;
	} esle {
		(*p) -> lchild = T;
		pre = *p;
		InThreading(T);
		pre->rchild = *p;
		pre->rtag = Thread;
		(*p)->rchild = pre;
	}
}

int main(){
	BiThrTree P, T = NULL;
	CreateBiThrTree(&T);
	InOrderThreading(&P, T);
	return 0;
}

树,森林,二叉树的转换

树到二叉树的转换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
森林到二叉树的转换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
二叉树到树、森林的转换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
判断一棵二叉树能够转换成一棵树还是森林,要看这个二叉树的根节点有没有右孩子,有就是森林,没有就是一棵树。

树与森林的遍历

树的遍历有两种方式,先根遍历和后根遍历。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值