算法笔记第九章 树

在这里插入图片描述
根据树的后序遍历与中序遍历求解树的层序遍历。
代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100;
int a[maxn], b[maxn];
int N;
struct node {
	int data;
	node* lchild;
	node* rchild;
};	
node* create(int a1,int a2,int b1,int b2) {
	if (a1 > a2) {
		return NULL;
	}
	node* n= new node;
	n->data = a[a2];
	int i;
	for (i = b1; i <= b2; i++) {
		if (b[i] == a[a2]) {
			break;
		}
	}
	int num = i - b1;
	n->lchild = create(a1, a1+num-1, b1, num-1);
	n->rchild = create(a1+num, a2-1, num+1, b2);
	return n;
}
int flag = 0;
void leorder(node* n) {
	queue<node*>q;
	q.push(n);
	while (!q.empty()) {
		node* tem = q.front();
		q.pop();
		printf("%d", tem->data);
		flag++;
		if (flag < N)printf(" ");
		if (tem->lchild != NULL) {
			q.push(tem->lchild);
		}
		if (tem->rchild != NULL) {
			q.push(tem->rchild);
		}
	}
}
int main() {
	scanf("%d", &N);
	for (int i = 0; i < N; i++) {
		scanf("%d", &a[i]);
	}
	for (int j = 0; j < N; j++) {
		scanf("%d", &b[j]);
	}
	int f = N - 1;
	node* k=create(0, f, 0, f);
	leorder(k);
	return 0;
}

不知道啥问题最后还会多输出一些奇怪的东西。。
后序遍历的最后一个结点是根节点,然后在中序遍历中找到根节点,中序遍历的根节点前面那一段是左子树,后面是右子树。然后中序遍历中找到的根节点的左边的结点数就是左子树的数目,从头以该数目数后序遍历,这些数就是后序遍历中的左子树,这些数最后一个就是左子树的根节点进行递归。

在这里插入图片描述
输出与要求的数相等的树的路径。大的优先,实现代码如下:

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 100;
int N, M, S;
int tem, k;
int jilu[maxn];
struct node {
	int data;
	vector<int>child;
}Node[maxn];
bool cmp(int a, int b) {
	return Node[a].data > Node[b].data;
}
void DFS(int index, int nodenum, int sum) {
	if (sum > S)return;
	if (sum == S) {
		if (Node[index].child.size() != 0) {
			return;
		}
		else {
			for (int i = 0; i < nodenum; i++) {
				printf("%d", Node[jilu[i]].data);
				if (i < nodenum - 1)printf(" ");
				else printf("\n");
			}
			return;
		}
	} 
	for (int i = 0; i < Node[index].child.size(); i++) {
		jilu[nodenum] = Node[index].child[i];
		DFS(Node[index].child[i], nodenum + 1, sum + Node[jilu[nodenum]].data);
	}
}
int main() {
	int count;
	scanf("%d%d%d", &N, &M, &S);
	for (int i = 0; i < N; i++) {
		scanf("%d", &Node[i].data);
	}
	for (int i = 0; i < M; i++) {
		scanf("%d%d", &tem,&count);
		for (int j = 0; j < count; j++) {
			scanf("%d", &k);
			Node[tem].child.push_back(k);
		}
		sort(Node[tem].child.begin(), Node[tem].child.end(), cmp);
	}
	jilu[0] = 0;
	DFS(0, 1, Node[0].data);
	return 0;
}

以数组的形式实现树,是树的静态实现。
读入数据后首先使用sort函数进行排序,把结点的孩子较大的那个放在前面,这样在输出时就会优先输出大的那个孩子的路径,满足题目的要求。使用sort函数记得添加algorithm头文件。递归的过程为输入某结点与添加了该结点后的路径值,若路径值大于要求的数了则return,若等于但是还有孩子结点就return,若没有的话就将jilu数组中的路径打印出来并return。不然就进行递归操作,循环将该结点的孩子结点进行递归,加入jilu数组,总和记得改变。

在这里插入图片描述
判断是不是二叉查找树或者镜像二叉查找树。二叉查找树是左子树小于根节点,右子树大于根节点的树。所以读入数据后可以根据数据自己建立一个二叉查找树(插入过程记得根节点添加引用符号),然后自己对其进行先序遍历,与镜像先序遍历(镜像先序遍历就是在遍历子树时先遍历右子树)。若输入的序列与其存在对应的,就使用对应 的后序遍历打印出来。

在这里插入图片描述
并查集。实现代码如下:

#include<cstdio>
const int maxn = 100;
int n, m;
int a, b;
int father[maxn];
bool isroot[maxn];
void init(int n) {
	for (int i = 1; i <= n; i++) {
		father[i] = i;
		isroot[i] = false;
	}
}
int findfather(int x) {
	if (x == father[x]) {
		return x;
	}
	else {
		int F = findfather(father[x]);
		father[x] = F;
		return F;
	}
}
void uni(int a, int b) {
	int xi = findfather(a);
	int yi = findfather(b);
	if (xi != yi)father[xi] = yi;
}
int main() {
	scanf("%d%d", &n, &m);
	init(n);
	for (int i = 0; i < m; i++) {
		scanf("%d%d", &a, &b);
		uni(a, b);
	}
	for (int i = 1; i <= n; i++) {
		isroot[findfather(i)] = true;
	}
	int count = 0;
	for (int i = 1; i <= n; i++) {
		count += isroot[i];
	}
	printf("%d", count);
	return 0;
}

递归寻找根节点的过程是,如果一个结点它的父节点不是自己,那么不是根节点,然后寻找它的父节点的根节点,找到后同时将它的父节点赋值为根节点(这是为了压缩路径,优化查找时间),对所有的数据进行union函数合并后就找到了几个集合,遍历所有的数将根节点对应的isroot数组值赋值为true(hash)。然后输出这个数组的总和就是组数。

堆:父亲结点大于(大顶堆)或小于(小顶堆)子节点的完全二叉树。
哈夫曼树:树的带权路径长度最小。
哈夫曼编码:长度唯一,编码不唯一,左子树路径上为零右子树为一,叶子结点的编码唯一且组合不会混淆。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值