知识点——满k叉树的重要性质:
1.标号从1开始到n
2.编号为 i 的结点的父节点(若存在)的编号是
3.编号为 i 的结点的第 m 个孩子结点(若存在)的编号是
4.编号为 i 的结点有有兄弟的条件是
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;
}