数据结构(第三章)

树(上)
什么是树?
客观世界中许多事物存在层次关系。
1.人类社会家谱。
2.社会组织结构。
3.图书信息管理。
查找:根据某个给定的关键字K,从集合R中找出关键字与K相同的记录。
1.静态查找:集合中记录是固定的。(没有插入和删除操作,只有查找)
2.动态查找:集合中记录是动态变化的。(除查找,还可能发生插入和删除)
静态查找
方法1:顺序查找

//顺序查找
typedef struct LNode *List;
struct LNode
{
	ElementType Element[MAXSIZE];
	int Length;
};
int SequentialSearch(List Tb1,ElementType K)//在Element[1]-Element[n]中查找关键字为K的数据元素
{
	int i;
	Tb1->Element[0]=K;//建立哨兵
	for(i=Tb1->Length;Tb1->Element[i]!=K;i--)
	{
		return i;//查找成功返回单元下标,否则返回0
	}
}

时间复杂度为O(n),有没有一种查找方式时间复杂度比O(n)更低呢?
提示:分层次组织在管理上具有更高的效率!
方法2:二分查找
前提:假设n个数据元素的关键字满足有序(比如:小到大),并且是存放(数组),那么可以进行二分查找。

//二分查找
int BinartSearch(List Tb1,ElementType K)//在表Tb1中查找关键字为K的数据元素
{
	int left,mid,right,NotFound=-1;
	left=1;//初始左边界
	right=Tb1->Length;//初始右边界
	while(left<=right)
	{
		mid=(left+right)/2;//计算中间元素坐标
		if(k<Tb1->Element[mid])
			right=mid-1;//调整右边界
		else if(K>Element[mid])
			right=mid+1;//调整左边界
		else
			return mid;//查找成功,返回数据元素的下标
	}
	return NotFound;//查找不成功,返回-1
}

二分查找算法具有对数的时间复杂度O(logN)。
树的定义
Tree):n(n>=0)个结点构成的有限集合。
当n=0时,称为空树
对于任一棵非空树(n>0),它具备以下性质:
1.树中有一个称为“Root)”的特殊结点,用r表示;
2.其余结点可分为m(m>0)个互不相交的有限集T1,T2…Tm,其中每个集合本身又是一棵树,称为原来树的“子树SubTree)”
树与非树?
1.子树是不相交的。
2.除了根结点外,每个结点有且仅有一个父结点
3.一个N个结点的树有N-1条边
树的一些基本术语
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层,其他的任一结点的层数是其父结点的层数加1.
11.树的深度(Depth):树中所有结点中的最大层次是这棵树的深度。
二叉树的定义
二叉树T:一个有穷的结点集合。
这个集合可以为空
若不为空,则它是由根结点和称为其左子树Tl,和右子树Tr的两个不相交的二叉树组成。
二叉树具有五种基本形态;在这里插入图片描述
二叉树有左右顺序之分。
特殊二叉树
1.斜二叉树(Skewed Binary Tree)
2.完美二叉树(Perfect Binary Tree)
3.完全二叉树(Complete Binary Tree)
性质
1.一个二叉树第i层的最大结点数为:2^i-1,i>=1;
2.深度为k的二叉树有最大结点总数为:2^k-1,k>=1;
3.对任何非空二叉树T,若n0表示叶结点的个数,n2是度为2的非叶结点个数,那么两者满足关系n0=n2+1。
二叉树的存储结构
1.顺序存储结构(数组)
完全二叉树:按从上至下,从左至右顺序存储n个结点的完全二叉树的结点父子关系
非根结点(序号>1)的父结点的序号是[i/2];
结点(序号为i)的左孩子结点的序号是2i,右孩子的是2i+1.若2i<=n(2i+1<=n)则没有左孩子(右孩子)
2.链式存储结构(链表)
在这里插入图片描述
在这里插入图片描述

//初始化
typedef struct TreeNode *BinTree;
typedef BinTree Position;
struct TreeNode
{
	ElementType data;
	BinTree Left;
	BinTree Right;
}

二叉树的遍历
先序:根——左——右。
中序:左——根——右。
后序:左——右——根。
层序:从上到下,从左到有。
1.先序遍历
遍历过程为:
(1)访问根结点;
(2)先序遍历其左子树;
(3)先序遍历其右子树。

void PreOderTraversal(BinTree BT)
{
	if(BT)
	{
		printf("%d",BT->data);
	    PreOderTraversal(BT->Left);
	    PreOderTraversal(BT->Right);
	}
}

2.中序遍历
遍历过程为:
(1)先序遍历其左子树;
(2)访问根结点;
(3)先序遍历其右子树。

void PreOderTraversal(BinTree BT)
{
	if(BT)
	{
	    PreOderTraversal(BT->Left);
	    printf("%d",BT->data);
	    PreOderTraversal(BT->Right);
	}
}

3.后序遍历
遍历过程为:
(1)先序遍历其左子树;
(2)先序遍历其右子树;
(3)访问根结点。

void PreOderTraversal(BinTree BT)
{
	if(BT)
	{
	    PreOderTraversal(BT->Left);
	    PreOderTraversal(BT->Right);
	    printf("%d",BT->data);
	}
}

总结:先序,中序,后序遍历过程,遍历过程中经过结点的路线是一样的,只是访问各结点的时机不同。
4.层序遍历:
队列实现:遍历从根结点开始,首先将根结点入队,然后开始执行循环:结点出队,访问该结点,其左右儿子入队。
层序基本过程:
从队列中取出第一个元素
访问该元素所指结点;
若该元素所指结点的左,右孩子结点非空,则将其左,右孩子的指针顺序入队。

void LevelOrderTraversal(BinTree BT)
{
	Queue Q;
	BinTree T;
	if(!BT)
		return;
	Q=CreateQueue(MAXSIZE);
	AddQ(Q,BT)
	while(!IsEmptyQ(Q))
	{
		T=DeleteQ(Q);
		printf("%d",T->data);
		if(T->Left)
			AddQ(Q,T->Left);
		if(T->Right)
			AddQ(Q,T->Right);
	}
}

遍历二叉树,输出其子叶结点

void PreOrderPrintLeaves(BinTree BT)
{
	if(BT)
	{
		if(!BT->Left&&!BT->Right)
			printf("%d",BT->data);
		 PreOrderPrintLeaves(BT->Left);
		 PreOrderPrintLeaves(BT->Right);
	}
}

求树的高度

int PostOrderGetHeight(BinTree BT)
{
	int HL,HR,MAXSH;
	if(BT)
	{
		HL=PostOrderGetHeight(HL->Left);
		HR=PostOrderGetHeight(HR->Right);
		MAXH=(HL>HR)?HL:HR;
		return MAXH+1;
	}
	else
		return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值