DS二叉树--赫夫曼树的构建与编码(不含代码框架)
#include <iostream>
#include<string>
#include<cstring>
using namespace std;
//创建哈夫曼树节点
class hfmnode
{
public:
int left; // 左孩子下标
int right; // 右孩子下标
int parents; //双亲结点下标
int weight; // 权值
hfmnode():left(0),right(0),parents(0),weight(0){}
};
class hfm
{
public:
int num; //权值个数即叶子数量
int leaf; //树的节点
hfmnode*tree; //数组哈夫曼树
string *code; //每个字符对应的哈夫曼编码
void create(int n,int a[]) //建树,参数是叶子节点数量和叶子权值
{
num=n;
leaf=2*n-1; //有n个结点构成哈夫曼树则会生成2n-1个结点
tree=new hfmnode[2*n]; //由于数组访问是从位置1开始,所以真正要申请的空间为2n个
code=new string [num+1]; //实质是个二维字符数组,第i行表示第i个字符对应的编码
for(int i=1;i<=n;i++)
{
tree[i].weight=a[i-1]; //第0个不用,从1开始编号
}
for(int i=1;i<=leaf;i++)
{
if(i>n){
tree[i].weight=0; //前n个结点是叶子,已经设置了权值
}
tree[i].parents=0; //全部设0
tree[i].left=0;
tree[i].right=0;
}
int s1,s2;
//构造n-1个非叶子结点
for(int i=num+1;i<=leaf;i++)
{
//找出权值最小的两个点 //因为hufftree位置从1开始weight位置从0开始所以是i-1
select(i-1, &s1, &s2);
tree[s1].parents=i;
tree[s2].parents=i;
tree[i].weight=tree[s1].weight+tree[s2].weight;
tree[i].left=s1;
tree[i].right=s2;
}
}
void select(int pos,int *s1,int *s2)//从1到pos的位置找出权值最小的两个点,把这两个点存到s1和s2里
{
// 找出最小的两个权值的下标
// 函数采用地址传递的方法,找出两个下标保存在 s1 和 s2 中
int d1=10001,d2=10001;
*s1=*s2=0;
for(int i=1;i<=pos;i++)
{
if(tree[i].parents==0&&tree[i].weight<d1)
{
d2=d1;
*s2=*s1;
d1=tree[i].weight;
*s1=i; //第一最小值
}
else if(tree[i].weight<d2&&tree[i].parents==0)
{
d2=tree[i].weight;
*s2=i; //第二最小值
}
}
}
void createcode()
{
char *g;
int start;
//求n个叶结点的哈夫曼编码
g=new char[num]; //分配空间
g[num-1]='\0'; //结束符
int c,f,i;
for(i=1;i<=num;++i)
{
start = num- 1; //编码结束位置
c=i;
for(f=tree[i].parents;f!=0;c=f,f=tree[f].parents)
{
if(tree[f].left==c)
{
g[--start]='0';
}
else
{
g[--start]='1';
}
}
code[i] = new char[num-start];
code[i].assign(&g[start]); // 把cd中从start到末尾的编码复制到huffCode中
}
delete[]g; // 释放工作空间
}
};
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin>>n;
int p[1000];
for(int i=0;i<n;i++)
{
cin>>p[i]; //输入权值
}
hfm myhuff;
myhuff.create(n,p);
myhuff.createcode();
for(int j=1;j<=n;j++)
{
cout<<myhuff.tree[j].weight<<"-";
cout<<myhuff.code[j]<<endl;
}
}
}
E. DS树--带权路径和
#include <iostream>
#include<string>
#include<cstring>
#define ok 1
#define error -1
using namespace std;
class hfmnode
{
public:
char data;
hfmnode *left; // 左孩子
hfmnode *right; // 右孩子
int weight; // 权值
int height; //高度
hfmnode():left(0),right(0),weight(0),height(0){}
};
class hfm
{
public:
int len;
hfmnode*root; //huffman树,用数组表示
string str;
int pos; //记录位置
int sum;
int apl;
//创造结点
hfmnode*create(int *w,int h) //记录权值的数组和高度
{
hfmnode *p;
char ch;
ch=str[pos]; //字符
pos++; //位置++
if(ch=='0') //空树
{
p=NULL;
}
else
{
p=new hfmnode();
p->data=ch;
p->height=h+1;//高度加一(根是0)
if(p->data>='A'&&p->data<='Z') //如果是叶子
{
p->weight=w[sum];//记录权值的数组
sum++;
}
//递归
p->left=create(w,p->height);
p->right=create(w,p->height);
}
return p;
}
void preorder() //先序
{
root->height=1;
preorder(root);
cout<<apl<<endl;
}
void preorder(hfmnode*p)
{
if(p)
{
apl+=p->weight*p->height; //只有叶子结点是有权值
preorder(p->left);
preorder(p->right);
}
}
hfm(){apl=0;}
//创建树
void create(string q,int *w) //传入二叉树的字符和叶子权值数组
{
pos=0;
sum=0;
str.assign(q); //拷贝字符串
root=create(w, -1);
}
};
int main()
{
int t;
cin >> t;
while (t--)
{
string tree;
int p[1000];
int n;
hfm t;
cin>>tree>>n;
for(int i=0;i<n;i++)
{
cin>>p[i];
}
t.create(tree, p);
t.preorder();
}
}
F. DS树--二叉树之最大路径
#include <iostream>
#include<string>
#include<queue>
#include<cstring>
#define ok 1
#define error -1
using namespace std;
class bitnode
{
public:
char data;
bitnode *left; // 左孩子
bitnode *right; // 右孩子
int weight; // 权值
int height; //高度
bitnode():left(0),right(0),weight(0),height(0){}
};
class bittree
{
public:
int len;
bitnode*root;
string str;
int pos;
int sum;
int road;
queue<int>ro; //权值队列
bitnode*create(int *w,int h)
{
bitnode *p;
char ch;
ch=str[pos];
pos++;
if(ch=='0') //空树
{
p=NULL;
}
else
{
p=new bitnode();
p->data=ch;
p->height=h+1;//高度加一
p->left=create(w,p->height);
p->right=create(w,p->height);
}
return p;
}
//获取路径最大值
void getroad()
{
getroad(root,0);
cout<<road<<endl;
}
void getroad(bitnode*p,int roa)
{
if(p)
{
p->weight=ro.front()+roa; //修改权值为队列头权值加当前路径
ro.pop();
getroad(p->left,p->weight);
getroad(p->right,p->weight);
if(!p->left&&!p->right) //如果是叶子节点
{
if(p->weight>road) //如果权值大于当前总路径则更新
{
road=p->weight;
}
}
}
}
bittree(){road=0;}
void create(string q,int *w,queue<int>r)
{
pos=0;
road=0;
sum=0;
str.assign(q); //拷贝字符串
ro=r;
root=create(w, -1);
}
};
int main()
{
int t;
cin >> t;
while (t--)
{
string tree;
int p[1000];
queue<int> weights;
int n;
bittree t;
cin>>tree>>n;
for(int i=0;i<n;i++)
{
cin>>p[i];
weights.push(p[i]);
}
t.create(tree, p,weights);
t.getroad();
}
}
G. 二叉树的中后序遍历构建及求叶子
#include <iostream>
using namespace std;
class bitnode
{
public:
int data;
bitnode* left; //左孩子
bitnode* right; //右孩子
int weight;
bitnode()
{
left=NULL;
right=NULL;
}
};
class tree
{
public:
bitnode* root;
int *inoder;
int *postorder;
int len;
int min=99999;
//创建树
void create()
{
create(root,inoder, postorder, len);
}
void create(bitnode *&d,int *p,int *q,int n) //创建树
{
if(n==0)
{
d=NULL;
}
else
{
d=new bitnode();
d->data=q[n-1]; //后序
int i,j;
for(i=0;i<n;i++)
{
if(p[i]==q[n-1]) //找到根节点
{
break;
}
}
int num1=i; //正着根
int num2=n-i-1; //逆着根
int in1[num1],in2[num2];
for(j=0;j<n;j++)
{
if(j<i) //传入
{
in1[j]=p[j];
}
else if(j>i)
{
in2[j-i-1]=p[j];
}
}
int post1[num1], post2[num2];
for(j=0; j<n; j++)
{
if(j<i)
{
post1[j] = q[j];
}
else if(j>=i && j<n-1)
{
post2[j-i] = q[j];
}
}
create(d->left, in1, post1,num1); //左子树
create(d->right, in2,post2, num2); //右子树
}
}
tree(int n,int *p,int *q)
{
len=n; //结点数
min=99999;
inoder=new int [n];
postorder=new int [n];
for(int i=0;i<n;i++)
{
inoder[i]=p[i];
postorder[i]=q[i];
}
}
void getmin()
{
getmin(root);
}
void getmin(bitnode*t)
{
if(t)
{
if(!t->left&&!t->right) //如果是叶子
{
if(t->data<min)
{
min=t->data;
}
}
getmin(t->left);
getmin(t->right);
}
}
};
int main()
{
int n;
while (cin>>n)
{
int *io=new int [n];
int *po=new int [n];
for(int i=0;i<n;i++)
{
cin>>io[i]; //中序
}
for(int i=0;i<n;i++)
{
cin>>po[i]; //后序
}
tree mytree(n,io,po);
mytree.create();
mytree.getmin();
cout<<mytree.min<<endl;
}
}