算法思想:(二叉树)
给定n个权值构造一个huffman树,将n个权值节点从小到大进行排列,建立一个单链表,然后每次选择表头最小的两个节点,把他们作为一个新节点的儿子,头节点的权值为左右儿子权值之和,然后断绝原来两个节节点和原有序链表的关系并将新建节点插入有序链表,不断进行这个过程,知道只有一个根节点。
若建立m叉Huffman树,有n个权值节点,要插入x个全值为零的点,使得(n-k+1)%(k-1)为0。
证明:
X1,X2,X3,X4......Xn n个节点建立k叉树,先取出X1,X2,X3.....Xk这K个节点,用一个根节点连接他们,并把这新的节点X加入有序表,假设为X,Xk+1,Xk+2.....Xn,不断进行这个操作,又取K个节点,直到最后剩余k-1个节点和一个新的节点,则恰好能够取完。
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
struct Tree
{
int data;
Tree *l,*r,*next;
Tree(){l=r=next=NULL;}
};
Tree *Insert(Tree *t,Tree *q) //将新产生的节点插入升序表中使其仍然有序
{
Tree *p=t,*pre=NULL;
if(t==NULL) t=q; //原表为空,插入节点作为表头
while(p&&q->data>p->data) pre=p,p=p->next; //不为空,找到第一个比它大的节点
q->next=p; //插在该节点的前面
if(pre==NULL) t=q; //插在头节点前面,改变表头
else pre->next=q; //插在中间
return t;
}
Tree *create(Tree *t) //huffman二叉树的建立
{
Tree *t1,*t2,*t3,*root=t;
while(t&&t->next) //
{
t1=t;
t2=t->next;
root=t2->next;
t3=new Tree();
t3->data=t1->data+t2->data; //每次将有序列表表头最小的两个值合并,作为新建节点的左右儿子
t3->l=t1,t3->r=t2;
t1->next=t2->next=NULL;//与原升序链表分离
t=root=Insert(root,t3);//将新建的节点插入有序链表中,返回新的根节点
}
return root;
}
Tree *createlist() //将输入的权值从小到大排序
{
int x;
Tree *t=NULL,*p,*q,*pre=NULL;
cin>>x;
while(x!=-1)
{
pre=NULL;
p=t;
q=new Tree();
q->data=x;
q->next=NULL;
if(t==NULL) t=q;
while(p&&q->data>p->data) pre=p,p=p->next;
q->next = p;
if(pre==NULL) t=q;
else pre->next=q;
cin>>x;
}
return t;
}
void display(Tree *t) //打印升序链表
{
Tree *p=t;
while(p)
{
cout<<p->data<<" ";
p=p->next;
}
}
void preorder(Tree *t) //将huffman树以前序遍历输出
{
if(t==NULL) return ;
cout<<t->data<<' ';
preorder(t->l);
preorder(t->r);
}
int main()
{
Tree *t;
t=createlist();
display(t);
cout<<endl;
t=create(t);
preorder(t);
return 0;
}