数据结构 第六章 树和二叉树

知识点——满k叉树的重要性质:

1.标号从1开始到n
2.编号为 i 的结点的父节点(若存在)的编号是 i 2 k + 1 \lfloor \frac{i-2}{k} \rfloor +1
3.编号为 i 的结点的第 m 个孩子结点(若存在)的编号是 k × ( i 1 ) + m + 1 k×(i-1)+m+1
4.编号为 i 的结点有有兄弟的条件是 ( i 1 ) m o d k 0 (i-1)\bmod k≠0

Part1:

练习3在这里插入图片描述
思路:生成index的父节点序号数组

#include<bits/stdc++.h>
using namespace std;
const int MAXSIZE = 110;
int a[MAXSIZE];
int k, n, q;
void func(int index, int p, int now) {//p记录index的父节点,now记录index在父节点下的序号
	a[index] = p;
	if (index == n) return;
	func(index + 1, p + now / k, now % k + 1);
}
int main() {
	cin >> n >> k >> q;
	func(2, 1, 1);//生成每个index的父节点数组
	cout << a[q] << endl;
	/*int sign = 0;//结尾空格敏感
	for (int i = 1; i <= n; i++)
		if (a[i] == q) {
			if (sign != 0) cout << " ";
			sign = 1;
			cout << i;
		}*/
	for (int i = 1; i <= n; i++)
		if (a[i] == q)
			cout << i << " ";
}

Part2:

练习2
在这里插入图片描述
在这里插入图片描述
样例2
输入:
7
1 2 3 4 5 6 7
1 3 2 4 6 5 7
7
输出:
3 6 7 5 4 2 1
1 2 3 4 5 6 7
1 2 4 5 7
思路:先将前序和中序遍历转换为顺序存储的二叉树

#include<bits/stdc++.h>
using namespace std;
const int MAXSIZE = 110;
struct BiTNode {
	int data, lchild, rchild;
}B[MAXSIZE];
int pre_order[MAXSIZE], in_order[MAXSIZE];
int n;
queue<int>p;
int decode(int b1, int e1, int b2, int e2) {//b1,e1为前序左右界限,b2,e2为中序左右界限
	assert(e1 - b1 == e2 - b2);
	if (e1 < b1)return 0;
	int r = pre_order[b1];//先根遍历
	int p;
	for (p = b2; in_order[p] != r; p++);
	B[r].data=r;
	B[r].lchild = decode(b1 + 1, b1 + p - b2, b2, p - 1);
	B[r].rchild = decode(b1 + p - b2 + 1, e1, p + 1, e2);
	return r;
}
void AfterOrder(int i) {//后序遍历
	if (B[i].data != 0) {
		AfterOrder(B[i].lchild);
		AfterOrder(B[i].rchild);
		cout << B[i].data;
		if (i != 1)cout << ' ';
	}
}
void FloorOrder() {//层序遍历
	p.push(B[1].data);
	int t = 0;
	while (!p.empty()) {
		t = p.front(); p.pop();
		cout << B[t].data;
		if (t != n)cout << ' ';
		if (B[t].lchild)p.push(B[t].lchild);
		if (B[t].rchild)p.push(B[t].rchild);
	}
}
void Path(int q) {//找根节点到子叶路径
	int q_path[MAXSIZE] = { q };
	int i, j = 1;
	while (q != 1) {
		for (int i = 1; i <= n; i++)
			if (B[i].lchild == q || B[i].rchild == q) {
				q = q_path[j++] = i; break;
			}
	}
	for (i = j - 1; i >= 0; i--) {
		cout << q_path[i];
		if (i != 0)cout << ' ';
	}
}
int main()
{
	int i, j, k; cin >> n;
	for (i = 1; i <= n; i++)cin >> pre_order[i];
	for (i = 1; i <= n; i++)cin >> in_order[i];
	for (i = 1; i <= n; i++)B[i].data = i;
	decode(1, n, 1, n);
	/*for (i = 1; i <= n; i++)
		cout << B[i].data << ' ' << B[i].lchild << ' ' << B[i].rchild << endl;*/
	AfterOrder(1); cout << endl;
	FloorOrder(); cout << endl;
	int Q; cin >> Q; Path(Q);
	return 0;
}

后序中序建树:顺便求深度,在树结构体中增加dep元素,并在遍历中计算dep最大值

int decode(int b1, int e1, int b2, int e2,int dep) {//b1,e1为后序左右界限,b2,e2为中序左右界限
	assert(e1 - b1 == e2 - b2);
	if (e1 < b1)return 0;
	int r = after_order[e1];
	int p;
	for (p = b2; in_order[p] != r; p++);
	B[r].data=r;
	B[r].dep=dep;
	B[r].lchild = decode(b1, b1+p - b2-1, b2, p - 1,dep+1);
	B[r].rchild = decode(b1+p - b2, e1-1, p + 1, e2,dep+1);
	return r;
}
int mx=-0x3f3f3f3f;
void pre_order(int i){
	if(!B[i].data)return;
	cout<<B[i].data<<' ';
	mx=max(mx,B[i].deep);
	if(B[i].lchild)pre_order(B[i].lchild);
	if(B[i].rchild)pre_order(B[i].rchild);
}

deep_tree函数:求树深度

int tree_deep(int i) {
	int left=0, right=0, deep = 0;
	if (!B[i].data)return 0;
	if (B[i].lchild)
		left = tree_deep(B[i].lchild);
	if(B[i].rchild)
		right = tree_deep(B[i].rchild);
	deep = left > right ? left : right;
	return deep + 1;
}

链表求前序和深度:不用计算下标

#include<bits/stdc++.h>
using namespace std;
int a[110],b[110];
int n;
struct tree{
	int data;
	tree *lchild,*rchild;
};
tree *creat(){
	tree *t=(tree *)malloc(sizeof(tree));
	t->lchild=NULL;
	t->rchild=NULL;
	return t;
}
tree *decode(int s1,int e1,int s2,int e2){
	tree *t=creat();
	t->data=b[e2];
	int rootnum;
	for(int i=s1;i<=e1;i++)
		if(a[i]==b[e2])	{
			rootnum=i;break;
		}
	if(rootnum!=s1)
		t->lchild=decode(s1,rootnum-1,s2,s2+rootnum-s1-1);
	if(rootnum!=e1)
		t->rchild=decode(rootnum+1,e1,e2-(e1-rootnum),e2-1);
	return t;
}
void post(tree *t){
	if(!t)return;
	cout<<t->data<<" ";
	if(t->lchild)
		post(t->lchild);
	if(t->rchild)
		post(t->rchild);
}
int findtree(tree *t){
	int left=0,right=0,dep;
	if(!t)return 0;
	if(t->lchild)
		left=findtree(t->lchild);
	if(t->rchild)
		right=findtree(t->rchild);
	dep=left>right?left:right;
	return dep+1;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	for(int i=1;i<=n;i++)
		cin>>b[i];
	tree *t=decode(1,n,1,n);
	post(t);cout<<endl;
	cout<<findtree(t);
    return 0;
}

练习3在这里插入图片描述
思路:先生成赫夫曼树,再计算每个叶子结点的深度。

#include<bits/stdc++.h>
using namespace std;
const int MAXSIZE = 110;
struct BiTNode {
	double lchild, rchild, data;
}B[MAXSIZE];
int main()
{
	int n;
	cin >> n;
	double w[MAXSIZE],a[MAXSIZE];
	for (int i = 0; i < n; i++)	cin >> w[i];
	for (int i = 0; i < n; i++) a[i] = B[i].data=w[i];
	double t=0;
	int i = 0, j = n;
	while (fabs(t - 1) > 1e-6) {//生成赫夫曼树
		sort(a, a + n);
		t = a[0] + a[1];
		B[j].data = t; B[j].lchild = a[0]; B[j++].rchild = a[1];
		a[0] = t, a[1] = 1;
		i++;
	}
	double p;
	int cnt;
	for (i = 0; i < n; i++) {
		cnt = 0;
		p = B[i].data;
		while (fabs(p - 1) > 1e-6) {//计算深度
			for (j = 0; j < 2*n-1; j++) 
				if (B[j].lchild == p || B[j].rchild == p) {
					p = B[j].data; cnt++;
				}
		}
		w[i] *= cnt;
	}
	double result = 0;
	for (i = 0; i < n; i++)	result += w[i];
	cout << fixed << setprecision(2) << result;
	return 0;
}

优化思路:外路径权重=除根节点外所有结点数值和,并用优先队列进行排序

#include <bits/stdc++.h>
using namespace std;
priority_queue<double, vector<double>, greater<double> > q;//从小到大的优先队列;从大到小为默认方式,也可用less<double>
int main()
{
	int n;cin >> n;
	double tmp;
	for (int i = 1; i <= n; i++)cin >> tmp, q.push(tmp);//结点进队列
	double sum = 0;
	if (q.size() == 1)
		cout << fixed << setprecision(2) << q.top();
	while (q.size() > 1){
		double q1 = q.top();q.pop();
		double q2 = q.top();q.pop();
		sum += q1 + q2;
		q.push(q1 + q2);
	}
	cout << fixed << setprecision(2) << sum;
	return 0;
}
发布了99 篇原创文章 · 获赞 44 · 访问量 5530

猜你喜欢

转载自blog.csdn.net/weixin_44413191/article/details/102596182