IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 西电数据结构上机题第三次机考练习题部分题目题解 -> 正文阅读

[数据结构与算法]西电数据结构上机题第三次机考练习题部分题目题解

Problem318二叉树遍历

题面

给定一棵二叉树的先序遍历和中序遍历序列,求其后序遍历序列。

解答

用递归的方式进行求解。
显而易见,任何一个子树的先序遍历序列的首字母一定是该子树的树根。而在中序遍历中,该树根左侧是左子树,右侧是右子树,那么我们只需要不断的递归分解左右子树,即可求出原树。
需要注意的是,由于我们需要求后序遍历序列,因此对于每一棵子树,都需要在它左右子树分别递归分解完成之后再输出树根结点。

code

void getnxt (string pre, string mid, int len) {
	if (len == 0) return ;//如果当前子树为空
	if (len == 1) {//如果当前是叶子结点
		cout << pre;//直接输出
		return ;
	}
	int k = mid.find (pre[0]);//找到中序遍历中根节点的位置
	getnxt (pre.substr (1, k), mid.substr (0, k), k);//遍历左子树
	getnxt (pre.substr (k + 1, len - 1 - k), mid.substr (k + 1, len - 1 - k), len - k - 1);//遍历右子树
	cout << pre[0];
}

这里的string的substr函数共有两个参数,例如pre.substr(1,k),意思是在取string类型pre的子串[1…k](从下标1处开始,长度为k)

Problem319将满二叉树转化为求和树

题面

在这里插入图片描述

解答

大致思路和Problem318一样,细节处理上需要花一些功夫。
这里,我们getnxt函数设置为int类型,以返回当前结点的左右子树之和。我们需要知道的是,对于每一个结点,它的求和树上对应的结点数值是它左右子树之和(不包括它本身),因此我们这里需要先把它本身的数值记录下来,再赋予它新值。特别地,对于每一个叶子结点,在将它的值返回上一层函数之前,需要将它赋零。
经过我们的操作,原中序遍历序列就成了答案要求的求和树中序遍历序列。

code

int find (int L, int R, int x) {
	for (int i = L;i <= R;i ++)
		if (b[i] == x) return i;
}
int getnxt (int l, int r, int L, int R) {
	
	int len = r - l + 1;//利用l和r算出当前子树的大小
	if (len == 0) return 0;//如果子树为空
	if (len == 1) {//如果是叶子结点
		int tmp = a[l];//先记录下当前叶子结点的数
		a[l] = b[L] = 0;//将前序遍历和中序遍历的叶子结点赋零
		return tmp;//返回叶子结点的值
	}
	int k = find (L, R, a[l]);//在中序遍历序列中找到根节点的位置
	int t1 = getnxt (l + 1, l + k - L, L, k - 1);//遍历左子树
	int t2 = getnxt (l + k - L + 1, r, k + 1, r);//遍历右子树
	int tmp = a[l];//先记录下当前结点的值
	a[l] = b[k] = t1 + t2;//将先序遍历序列和中序遍历序列中该结点赋值为两个子树值之和
	return tmp + a[l];//整个子树的值应为当前左右子树值、根节点值之和
}

Problem320二叉树的不同形态

题面

在这里插入图片描述

解答

这道题相对前两道题较复杂。一共分为两个步骤

  1. 根据层次遍历序列和中序遍历序列求出先序遍历序列
  2. 根据先序遍历序列和中序遍历序列求出后序遍历序列

第二步是前面介绍过的算法。这里着重介绍第一步的算法。
直观暴力思想
还是同之前一样,利用递归的手段进行左右子树拆解。但是不同的是,层次遍历序列不像先序遍历序列那样,可以非常容易得知每一棵子树的根节点。但是我们可以发现两个性质:

  1. 在层次遍历序列中,父亲结点永远出现在儿子节点的前面。
  2. 在层次遍历序列中,在父亲结点后出现的第一个存在于左子树的结点,就是该父亲节点的左子树根节点;右子树根节点亦然。

所以我们可以改进之前的算法:
若左子树不为空,当遍历左子树前,我们可以通过查找层次遍历序列中,父亲节点后,第一个出现的存在于左子树的结点,作为左子树的根节点,以它为依据划分中序遍历序列,继续拆解二叉树。

if (k - l > 0) {
		int t = root + 1;
		while (find (l, k - 1, dep[t]) == -1) t ++;
		getpre (l, k - 1, t);
	}

但是我们发现了一个问题,在寻找一个父亲节点的两个孩子结点时候,需要对层次遍历序列中,父亲孩子之间的所有结点都进行while (find (l, k - 1, dep[t]) == -1) t ++;的操作,粗略估计下时间复杂度大约是 O ( n ) = n 3 O(n)=n^3 O(n)=n3级别,算法还需要改进。我们很容易意识到一个特性:

  • 当一个结点在拆解过程中被作为父亲结点使用后,一定不会使用第二次。

因此我们可以设置一个新函数(其实就是一个bool类型的标记数组)used[x]。当x没有被当做父亲节点使用时,我们让他为0,代表它需要被查找;一旦被使用后让他为1,代表他不需要再被查找。于是代码可以改为:

if (k - l > 0) {
		int t = root + 1;
		while (used[t] || find (l, k - 1, dep[t]) == -1) t ++;
		used[t] = 1;
		getpre (l, k - 1, t);
	}

该算法在满二叉树的情况下效果最差,但是在题目的数据范围下经过自造数据的多次检验,可以在1s内完美跑完。

code

int find (int l, int r, int x) {
	for (int i = l;i <= r;i ++)
		if (mid[i] == x) return i;
	return -1;
}
int pre[maxn], top = 0;
int used[maxn];
void getpre (int l, int r, int root) {
	int len = r - l + 1;//当前子树大小
	if (len == 0) return;//如果子树为空
	if (len == 1) {//叶子节点
		printf ("%d ", mid[l]);
		pre[++ top] = mid[l];//在先序遍历序列中记录叶子结点
		return ;
	}
	int k = find (l, r, dep[root]);
	pre[++ top] = mid[k];//先序遍历序列,需要先记录根结点
	if (k - l > 0) {
		int t = root + 1;
		while (used[t] || find (l, k - 1, dep[t]) == -1) t ++;
		used[t] = 1;
		getpre (l, k - 1, t);
	}
	if (r - k > 0) {
		int t = root + 1;
		while (used[t] || find (k + 1, r, dep[t]) == -1) t ++;
		used[t] = 1;
		getpre (k + 1, r, t);
	}
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-15 18:33:00  更:2021-12-15 18:33:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 16:46:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码