数据结构MOOC浙大笔记

第三讲 树(上)

什么是树

树的定义

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

树的一些基本术语

1.结点的度(Degree):结点的子树个数
2.树的度:树的所有结点中最大的度数
在这里插入图片描述3.叶结点(Leaf):度为0的结点
4.父结点(Parent):有子树的结点是其子树的根节点的父结点
5.子结点(Child):若A结点是B结点的父结点,则称B结点是A结点的子结点,子结点也称孩子结点
6.兄弟结点(Sibling):具有同一父结点的彼此是兄弟的结点
7.路径和路径长度:从结点n1到nk的路径为一个结点序列n1,n2,- - -,nk,ni是ni+1的父结点。路径所包含边的个数为路径的长度
8.祖先结点(Ancestor):沿树根到某一结点路径上的所有结点都是这个结点的祖先节点
9.子孙节点(Descendant):某一结点的子树中的所有结点是这个结点的子孙
10.结点的层次(Level):规定根节点在1层,其它任一结点的层数是其父结点的层数加一
11.树的深度(Depth):树中所有结点中最大层次是这棵树的深度

树的表示

初步想法如下:
在这里插入图片描述
但是每个结点的结构(指针域个数)不同,如果不统一结构,就会给程序实现带来困难;如果统一结构,就会造成空间的浪费

什么是二叉树

儿子-兄弟表示法

在这里插入图片描述
在这里插入图片描述
二叉树:一个有穷的结点的集合
这个集合可以为空
若不为空,则它是由根节点喝称其为左子树TL和右子树TR的两个不相交的二叉树组成

  • 二叉树具体有五种基本形态
    在这里插入图片描述

特殊二叉树

  • 斜二叉树
  • 完美二叉树/满二叉树
  • 完全二叉树

在这里插入图片描述

二叉树的几个重要性质

  • 一个二叉树的第i层的最大结点树为2i-1,i>=1
  • 深度为k的二叉树有最大的结点总数为2k-1,k>=1
  • 对任何非空二叉树T,若n0表示叶节点的总数(子结点为0),n1表示子节点为1的结点的总数,n2表示子节点为2的结点的总数,则存在关系n0=n2+1

    在这里插入图片描述

验证(利用边数)

  • 边数=总的节点数-1
    边数=n0+n1+n2-1
  • 边数=每个结点的个数✖它对边的贡献
    边数=n0✖0 + n1✖1 + n2✖2
    两便同时约掉n1,再约掉一个n2,得出结论

二叉树的抽象数据类型定义

类型名称:二叉树
数据对象集:一个又穷的结点的集合
若不为空,则由根节点和其左、右二叉树组成
操作集
1.Boolean IsEmpty(BinTree BT):判别BT是否为空
2.void Traversal(BinTree BT):遍历,按某顺序访问每个结点
3.BinTree CreateBin():创建一个二叉树

二叉树的存储结构

1.顺序存储

完全二叉树
在这里插入图片描述
一般二叉树
在这里插入图片描述

2.链表存储
  1. 定义树的数据结构
typedef struct TreeNode *BinTree;
typedef BinTree Position;
struct TreeNode{
	ElementType Data;
	BinTree Left;
	BinTree Right; 
};

二叉树的遍历(数组实现)

常用的遍历方法由:
void PreOrderTraversal(BinTree BT):**先序—**根、左子树、右子树
void InOrderTraversal(BinTree BT):**中序—**左子树、根、右子树
void PostOrderTraversal(BinTree BT):**后序—**左子树、右子树、根
void LevelOrderTraversal(BinTree BT):层次遍历,从上到下、从左到右

  • (1)先序遍历
  • (取访问到的第一次)
    • ①访问根节点
    • ②先序遍历其左子树
    • ③先序遍历其右子树
void PreOrderTraversal(BinTree BT)
{
	if(BT){								//判断是否为空 
		printf("%d", BT->Data);			//访问根节点 
		PreOrderTraversal(BT->Left);	//对左子树递归
		PTrOrderTraversal(BT->Right);	//对右子树递归
	}
 } 

在这里插入图片描述
在这里插入图片描述

  • (2)中序遍历
  • (取访问到的第二次)
    • ①中序遍历其左子树
    • ②访问根节点
    • ③中序遍历其右子树
void PreOrderTraversal(BinTree BT)
{
	if(BT){								//判断是否为空 
		PreOrderTraversal(BT->Left);	//对左子树递归
		printf("%d", BT->Data);			//访问根节点 
		PTrOrderTraversal(BT->Right);	//对右子树递归
	}
 } 

在这里插入图片描述

  • (3)后序遍历
  • (取访问到的第三次)
    • ①后序遍历其左子树
    • ②后序遍历其右子树
    • ③访问根节点
void PreOrderTraversal(BinTree BT)
{
	if(BT){								//判断是否为空 
		PreOrderTraversal(BT->Left);	//对左子树递归
		PTrOrderTraversal(BT->Right);	//对右子树递归
		printf("%d", BT->Data);			//访问根节点 
	}
 } 

在这里插入图片描述
在这里插入图片描述

二叉树的非递归遍历(堆栈实现)

以中序为例

中序遍历非递归遍历算法

基本思路:使用堆栈

  • 当遇到一个结点就把它压堆栈,并去遍历它的左子树
  • 当左子树遍历结束后,从栈顶弹出这个结点并访问它
  • 然后按其右指针再去中序遍历该结点的右子树
void InOrderTraversal(BinTree BT)
{
	BinTree T=BT;	//把BT赋给临时变量T
	Stack S=CreateSatck(MaxSize);	//创建并初始化堆栈S
	while(T || !IsEmpty(S)){			//树不空并且堆栈不空
		while(T){					//一直向左并将沿途结点压入堆栈
			Push(S, T);
			T=T->Left; 				//往左边走 
		//T为NULL时退出循环 
		} 
		if(!IsEmpty(S)){			//堆栈不空 
			T=Pop(S);				//结点弹出栈 
			printf("%5d", T->Data);	//打印结点
			T=T->Right;				//转向右子树 
		} 
			
	} 
	
} 

在这里插入图片描述

二叉树的层序遍历(队列实现)

二叉树遍历的核心问题:二维结构的线性化

  • 从结点访问其左、右儿子结点
  • 访问左儿子后,右儿子的结点怎么办?
    • 需要一个存储结构保存暂时不访问的结点
    • 存储结构:堆栈、队列

队列实现

遍历从根节点开始,首先将根节点入队,然后开始执行循环:结点出队、访问该结点、其左、右儿子入队

层序基本过程:先根节点入队,然后:
①从队列中取出一个元素
②访问该元素所指结点
③若该元素所指的结点的左、右孩子结点非空,则将其左、右儿子的指针顺序入队

void LevelOrderTraversal(BinTree BT)
{
	Queue Q;
	BinTree T;
	if(!BT){
		return ;	//若是空树则直接返回 
	}
	Q=CreatQueue(MaxSize);	//创建并初始化队列Q 
 } 

查找

查找:根据某个给定关键字K,从集合R中找出关键字与K相同的记录

  • 静态查找
  • 没有插入和删除操作,只有查找
  • 动态查找
  • 除了查找,还可能发生插入和删除

静态查找

  • 方法1:顺序查找
    时间复杂度O(n)
    Tbl是一个一个指针的结构,有两个变量
typedef struct LNode *List;
struct LNode{
	ElementType Element[MAXSIZE];	//数组Element 
	int length;						//数组大小length 
}; 
//方法1:顺序查找
int SequentialSearch(List Tbl, ElementType K)
{//在Element[1]~Element[n]中查找关键字为K的数据元素 
	 int i;
	 Tb1->Element[0]=K;		//建立哨兵K
	 for(i=Tb1->Length; Tb->Elemnet[i]!=K; i--){
	 	//没有执行语句 
	 } 
	 return i;//查找成功返回所在单元下标,不成功返回0(初始哨兵的位置) 
 } 

在这里插入图片描述

  • 方法2:二分查找(Binary Search)
    时间复杂度O(log2n)
    假设n个数据元素的关键字满足有序(比如:从小到大),k1<k2<- - - <kn并且是连续存放 (数组),那么可以进行二分查找
//二分法查找算法
int BinarySearch(List Tbl, ElementType K)
{//在Tbl表中查找关键字为K的数据元素
	int left, right, mid, NoFound=-1;
	left=1;							//初始左边界
	right=1;						//初始有边界
	while(left<=right)				//判断该数组里面是否有元素存在
	{
		mid=(left+right)/2;			//计算中间元素坐标 
		if(K<Tbl->Element[mid]){
			right=mid-1;			//调整右边界 
		}else if(K>Tbl->Element[mid]){
			left=mid+1;				//调整左边界 
		}else{	
			return mid;				//查找成功,返回元素的下标 
		}
	 } 
	 return NotFound;				//查找不成功,返回-1 
	
 } 

在这里插入图片描述

动态查找

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值