n4.树(上)

文章详细介绍了树与二叉树的表示方法,包括顺序查找和二分查找的区别,以及二叉树的定义、性质和存储结构,如完全二叉树和链式储存。
摘要由CSDN通过智能技术生成

一、树与树的表示

1.查找

在这里插入图片描述

静态查找,查找的对象集合本身不发生改变,例如查字典;动态查找,查找的对象集合本身是动态变化的。

顺序查找

在这里插入图片描述

将数据储存在数组里,按照顺序进行查找。此外需要一个结构指针Tbl,它的Data域是数组中元素的个数;指针域指向这个数组。需要存n个数据,就把数组大小设为a[n+1]。因为要设置一个哨兵a[0] = K,用来终止循环判断是否查找到K,a[1]到a[n]用来储存数据。

struct LNode{
	int length;
	int Arr[MaxSize];	
};
typedef struct LNode* List;//结构指针
Search(int K;List Tbl)//假设要找的元素是K
{
	List->Arr[0] = K;
	for(int i = List->Tbl;List->Arr[i] != K;i--);//注意是从索引大向着索引小的方向循环遍历查找K
	return i;
}

没有哨兵的话,循环结束,意味着找到了K或者超出了数组的边界。for(int i = List->length; List->Arr[i] != K && i>=0;i--)这样就会复杂些。
哨兵的作用就是我们再循环的时候不需要每次去判断他的下标,少写一个判断分支。而且只要循环结束,可以马上知道是否有元素K。返回0表示数组中没有元素K;返回其他的表示查找成功
注意循环是从大索引向小索引查找。
在这里插入图片描述
这样的查找方法效率不高

二分查找

在这里插入图片描述

  • 二分查找可以实现的前提
    1数据存放在数组里面
    2数据在数组中是有序排放的,降序或者升序。
  • 举例:
    在这里插入图片描述

因为mid = 100 < 444,所以就可以确定444在右半部分。所以舍弃左半部分,对右半部分重复进行操作。
在这里插入图片描述

代码

从a[0]开始储存数据,Search()函数查找K,并返回K所在的位置下标;Sort函数进行冒泡排序;

void Sort(int a[], int length);
int Search(int a[], int length, int K);
int main()
{
	int a[] = { 9,5,2,4,3, };
	int length = sizeof(a) / sizeof(a[0]);
	Sort(a, length);
	printf("排序之后的数组:\n");
	for (int i = 0; i < length; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	int four = Search(a, length, 4);
	int non = Search(a, length, 7);
	int nine = Search(a, length, 9);
	printf("4的下标在%d\n", four);
	printf("9的下标在%d\n", nine);
	printf("7的下标在%d\n", non);
	return 0;

}
void Sort(int a[],int length)//length 链表的长度
//由于冒泡排序的特殊性,无法对部分元素进行排序,要排就全都排
{
	int i, j;
	for (i = 0; i < length - 1; i++)
	{//第一次层循环控制冒泡排序 冒泡的轮数
	//length个数,需要冒泡length-1次,每次冒泡就会完成对一个数的排序
		for (j = 0; j < length - 1 - i; j++)
		{//第二次循环控制本轮冒泡需要比较的次数
	//这里i表示已经完成排序的元素的个数,每轮需要比较的元素个数依次减小;
			if (a[j] > a[j + 1])
			{//交换两个元素的值
				int temp = a[j];
				a[j] = a[j + 1];
				a[j + 1] = temp;
			}//完成升序排序
		}
	}
}
int Search(int a[], int length, int K)
{//二分查找的函数
	int left = 0,right = length -1;
	while (left <= right)//判定条件:不越界
	{
		int middle = (left + right) / 2;
		if (K > a[middle])//因为是升序排序,说明在右半部分,变left
		{
			left = middle + 1;
		}
		else if (K < a[middle])
		{
			right = middle - 1;
		}
		else
			return middle;
	}
	return -1;

}

时间复杂度:O(logN)

二分查找的判定树

11个元素,1到11进行查找,使用判定树进行模拟。第一次查找肯定是将K与6进行比较,判断是在左半部分还是在右半部分,依次进行下去…
第一次查找可找到6;第二次查找可找到3,9;第三次查找可找到1,4,7,10…
在这里插入图片描述

  • 这个树一共有四层(从上到下),如果要查找4,那么久需要查找3次,因为4在第三层;
  • ASL(平均寻找次数) = (需要找4次的数字个数 + 需要找3次的数字个数 + 需要找2次的数字个数+…)/ 数字总个数;
    使用层次化的结构储存数据:查找树的形式,原理类似二分查找,使得查找过程更加方便,当在树中查找节点、删除节点的时候,会比数组方便得多,可以更好地处理动态查找问题。

2.树的定义和术语

定义

在这里插入图片描述

类似递归的思路,一个树有多个子树组成,每个树都有根Root…

  • 每个子树之间互不相交
  • 除了根节点之外,每个节点有且只有一个父节点
  • 一棵有N个节点的树有N-1条边。因为除了根节点A,每个节点都只有向上的一条边。
  • 树是保证节点联通的边最少的一种连接方式。

术语

在这里插入图片描述

例如,右图中的树:

  • 节点的度为3,因为根节点A有三个子树;
  • 树的度为3,看最多的子树数目:A和D最大度数;
  • 叶节点,即没有子树的结点:FLH…
    在这里插入图片描述

右图中树的深度为4;

3.树的表示

使用数组实现起来相对困难;如果使用链表表示树,那么就需要每个节点的指针个数都是相同的,会造成较大的空间上的浪费。
在这里插入图片描述

那么就可以使用儿子兄弟表示法
在这里插入图片描述

将他旋转45度,可以看成一个树,每个节点都有两个指针,一个指向左边,一个指向右边。这种树叫做二叉树,度为2的一种数。
在这里插入图片描述

一般的树就可以使用二叉树链表的形式来实现。

二、二叉树及储存结构

1.二叉树的定义及性质

二叉树的定义

在这里插入图片描述

1.二叉树的左子树和右子树两不相交。
2.二叉树可以是空树,可以只有一个结点,可以只有左子树,可以只有右子树,可以有左右子树。
3.注意二叉树是一种度为2的树,子树有左右顺序之分。而一般的度为2的树,子树是没有左右之分的。

特殊二叉树

在这里插入图片描述

1.斜二叉树,就是单链表;
2.完美二叉树(满二叉树),对称完美,除了最后一层都有两个孩子结点。

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

如果一个完全二叉树有k层,那么它的前k-1层都是满的完美形态,它的最底层允许在右边缺少连续的结点。完美二叉树是完全二叉树的特例。

二叉树的性质

  • 1.二叉树第i层最多有2的i-1次方 个节点。
  • 2.深度为k层的二叉树具有的最大节点总数为2的k次方-1 个节点。
    在这里插入图片描述

完美二叉树即为结点最多的情况
最大节点总数,就是k层所有的节点等比求和

  • 3.对于非空的二叉树,叶节点个数比度为2(有两个儿子)的结点个数多1。
    在这里插入图片描述

n0表示叶节点的个数;n1表示只有一个儿子的结点个数;n2表示有两个儿子的结点。关系为n0 = n2 + 1。(可以简单的理解为度为2的节点提供了两个子节点的位置)
证明:使用两种对总数边的求法
在这里插入图片描述

  • 4.具有N个节点的完全二叉树的深度一定为[log2 N] +1。
    在这里插入图片描述

理解:最后一个叶节点的父节点一定是最后一个非叶节点(这个节点之后的节点全部都是叶节点

  • 5.如果深度为d的二叉树只有度为0和2的结点,那么这个二叉树的节点数至少为2d-1。
    理解:每层的节点只有一个度为2的结点,另一个节点为叶节点。也就是说,除了第一层的根节点,每一层只有两个节点。
    请添加图片描述

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

在这里插入图片描述

其中对二叉树的遍历是最基本的操作。常见的遍历方法有四种。

2.二叉树的存储结构

顺序储存结构

对于完全二叉树(比较适合):

在这里插入图片描述

使用数组来连续存储完全二叉树,即使用对结点编号的方式来对应数组元素的下标
a[n+1] 表示可以储存序号从1 到 n,已知任何一个结点,都可以进行访问操作:

  • 查找父节点:a[i] 的父节点为 a[i/2] ,注意i/2取整
  • 左孩子:a[i] 的左孩子是a[2i];
  • 右孩子: a[i] 的右孩子是a[2i + 1];
  • 如果下标索引超出n,表示越界,所找的节点不存在。
对于一般的二叉树(空间浪费):


索引访问的对应关系仍然适用!但是会造成空间浪费。比如这个例子,只有五个节点有数据,却需要使用13个数组空间来储存。

链式储存

在这里插入图片描述

节点不存在的情况使用NULL来表示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值