1.0-1-2树
这题我之前单独发过了,懒得再发一遍。
2.二叉树的带权路径长度
【问题描述】
树的路径长度是从树根到树中每一叶子结点的路径长度之和.在结点数目相同的二叉树中,完全二叉树的路径长度最短。
结点的权:赋予二叉树树中结点的一个有某种意义的实数。
结点的带权路径长度:结点到树根之间的路径长度与该结点上权的乘积。
树的带权路径长度(Weighted Path Length of Tree):定义为树中所有叶结点的带权路径长度之和,通常记为:
T=∑ W i × l i {W_i \times l_i} Wi×li i=1,2,……,n i表示叶子节点的编号。
其中:n表示叶子结点的数目Wi和li分别表示叶结点i的权值和根到结点i之间的路径长度。树的带权路径长度亦称为树的代价。
现在给定n个叶子节点的权值,求出一颗二叉树,使得这棵二叉树的带权路径长度WPL最小,并且求出这个最小带权路径长度。
比如3个叶子节点的权值是1,2,3,其最小带权路径长度 W P L {W_{PL}} WPL=1×2+2×2+3×1=9。
【输入形式】
有多组测试数据,每组测试数据占两行,第一行是一个正整数n,表示叶子节点个数, n=0意味着输入结束并且不需要处理。
第二行是n个正整数,表示每个叶子节点的权值 W i {W_i} Wi,所有的 W i {W_i} Wi≤10000。
40%的测试数据3 ≤ n≤ 10
30%的测试数据3 ≤ n≤
1
0
2
{10^2}
102
20%的测试数据3 ≤ n≤
1
0
3
{10^3}
103
10%的测试数据3 ≤ n≤
1
0
4
{10^4}
104
【输出形式】
对于每组测试数据,输出一行,包含一个正整数,表示最小带权路径长度WPL。测试数据保证正确的结果不超过 2 31 {2^{31}} 231。
【思路分析】
此题就是哈夫曼树的经典问题,使用哈夫曼树即可轻松解决,不过出于练习目的,此处自建小根堆实现哈夫曼树,可以用优先队列代替自定义的minheap类。
【代码】
#include<iostream>//huffman树的简略版本
using namespace std;
int Left[100005];
int Right[100005];
int num[100005];
struct node{
int id;
int weight;
}heap[10005];
class minheap{
private:
int cnt;
public:
minheap(int n){cnt=n;}
void buildheap();
void siftdown(int index);
void push(node a);
void pop();
node& front();
bool Comp(const node& a,const node& b);
void swap(node& a,node& b);
int size();
};
void inital(int n)
{
for(int i=0;i<=n;i++)
Left[i]=Right[i]=0;
return ;
}
int ans=0;
void solve(int index,int depth)
{
if(Left[index]==0 && Right[index]==0)
{
ans+=(depth*num[index]);
return ;
}
solve(Left[index],depth+1);
solve(Right[index],depth+1);
return ;
}
int main()
{
while(1)
{
int n;
cin>>n;
if(n==0)
return 0;
for(int i=1;i<=n;i++)
{
cin>>heap[i].weight;
heap[i].id=i;
num[i]=heap[i].weight;
}
inital(n);
minheap q(n);
q.buildheap();
int size=n;
node tmp1,tmp2,tmp3;
while(q.size()>1)
{
tmp1=q.front();
q.pop();
tmp2=q.front();
q.pop();
tmp3.weight=tmp1.weight+tmp2.weight;
tmp3.id=++size;
Left[size]=tmp1.id;
Right[size]=tmp2.id;
num[size]=tmp3.weight;
q.push(tmp3);
}
tmp1=q.front();
ans=0;
solve(tmp1.id,0);
cout<<ans<<'\n';
}
return 0;
}
void minheap::buildheap()
{
for(int i=cnt/2;i>=1;i--)
siftdown(i);
return ;
}
void minheap::pop()
{
heap[1]=heap[cnt--];
siftdown(1);
return ;
}
void minheap::push(node a)
{
heap[++cnt]=a;
int root=cnt;
int father=root/2;
while(root!=1)
{
if(Comp(heap[root],heap[father]))
swap(heap[root],heap[father]);
else return ;
root=father;
father=root/2;
}
return ;
}
node& minheap::front()
{
return heap[1];
}
bool minheap::Comp(const node& a,const node& b)
{
return a.weight<b.weight;
}
void minheap::swap(node& a,node& b)
{
int index=a.id,wgt=a.weight;
a.id=b.id,a.weight=b.weight;
b.id=index,b.weight=wgt;
return ;
}
void minheap::siftdown(int index)
{
int root=index;
int l=root<<1,r=root<<1|1;
while(l<=cnt)
{
if(r<=cnt && Comp(heap[r],heap[l]))
l=r;
if(Comp(heap[root],heap[l]))
return ;
swap(heap[root],heap[l]);
root=l;
l=root<<1,r=root<<1|1;
}
return ;
}
int minheap::size()
{
return cnt;
}
3.二叉树遍历,从前序、中序到后序
【问题描述】
二叉树是一种非常重要的数据结构,非常多其他数据结构都是基于二叉树的基础演变而来的。对于二叉树,深度遍历有前序、中序以及后序三种遍历方法。
三种基本的遍历思想为:
前序遍历:根结点 —> 左子树 —> 右子树
中序遍历:左子树—> 根结点 —> 右子树
后序遍历:左子树 —> 右子树 —> 根结点
比如,求以下二叉树的各种遍历
前序遍历:1 2 4 5 7 8 3 6
中序遍历:4 2 7 5 8 1 3 6
后序遍历:4 7 8 5 2 6 3 1
需要你编写程序解决的问题是:已知一个二叉树的前序遍历和中序遍历的结果,给出该二叉树的后序遍历的结果。
【输入形式】
有多组测试数据,每组测试数据三行,每组测试数据第一行只有一个正整数n,表示二叉树节点的数目,n=0意味着输入结束并且不需要处理。
每组测试数据第二行是二叉树的前序遍历的结果,是一个长度为n的字符串,每个节点由一个字符表示,字符是大小写英文字母及10个数字,不同的节点用不同的字符表示,也即无论前序遍历和中序遍历的字符串中没有重复的字符。
每组测试数据第二行是二叉树的中序遍历的结果,也是一个长度为n的字符串。
40%的测试数据1 ≤ n≤ 10;
30%的测试数据1 ≤ n≤ 20;
20%的测试数据1 ≤ n≤ 40;
10%的测试数据1 ≤ n≤ 62;
【输出形式】
对于每组测试数据,输出一行,是一个长度为n的字符串,表示二叉树后序遍历的结果。
【思路分析】
此题即利用前序遍历和中序遍历的特殊性来确定整棵树,我们知道前序遍历是根结点 —> 左子树 —> 右子树,中序遍历是左子树—> 根结点 —> 右子树,后序遍历是左子树 —> 右子树 —> 根结点,因此只要根据前序遍历序列即可一直得到子树的根节点,利用根节点即可将中序遍历序列拆分为左右子树两个序列,然后再递归地拆分中序遍历序列即相当于再进行一遍前序遍历,我们先递归后记录每一次的根节点即为后序遍历。
【代码】
#include<iostream>
using namespace std;
string postOrder;
void GetRoot(string& a,string& b)
{
if(b.size()<1)
return ;
char root=a[0];
string b1,b2;
int division=b.find(root);
for(int i=0;i<division;i++)
b1.push_back(b[i]);
for(int i=division+1;i<(int)b.size();i++)
b2.push_back(b[i]);
a.erase(a.begin());
GetRoot(a,b1);
GetRoot(a,b2);
postOrder.push_back(root);
}
int main()
{
string a, b;
while(1)
{
int n;
cin>>n;
if(n==0)
return 0;
cin>>a>>b;
postOrder.clear();
GetRoot(a,b);
cout<<postOrder<<'\n';
}
return 0;
}