SSL1407【树】哈夫曼树(一)

SSL1407【树】哈夫曼树(一)

题目

假设用于通信的电文仅由8个字母组成,字母在电文中出现的频率分别为7、19、2、6、32、3、21、10。试为这8个字母设计哈夫曼编码。如果用二进制数表示这8个字母的编码方案.(请按照左子树根节点的权小于等于右子树根节点的权的次序构造)

题解

这道题应该用哈弗曼编码来做,要设计哈弗曼编码就要先构造一棵哈弗曼树。
哈夫曼树是权大的叶子离根最近的二叉树,最主要的特点是带权的二叉树的路径长度最小。
具体构造方法:
   (1)根据给定的n个权值{w1,w2,…,wn},构造n棵二叉树的集合F={T1,T2,…,Tn},其中每棵二叉树中均只含一个权值为wi的根结点,其左、右子树为空树;
   (2)在F中选取其根结点的权值最小的两棵二叉树,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和;
   (3)从F中删去这两棵树,同时加入刚生成的新树;
   (4)重复(2)和(3)两步,直到F中只含一棵树为止。
利用哈夫曼树进行编码称为哈夫曼编码。我们约定在二叉树中用叶结点表示字符。从根结点到叶子的路径中,左分支表示“0”,右分支表示“1”,从根结点到叶结点上的路径分支所组成的字符串作为该叶结点字符的编码。
哈夫曼算法的实现与实际问题所采用的存储结构有关。现假设用数组F来存储哈夫曼树,其中第i个数组元素F[i]是哈夫曼树中的一个结点,其地址为i,有3个域,data域存放该结点的权值,lchild域和rchild域分别存放该结点左、右子树的根结点的地址。在初始状态下: F[i].data=Wi,F[i].lchild=F[i].rchild=0,i=1,2,…,n。
   即先构造了n个叶子。在以后每步构造一棵新二叉树时,都需要对森林中所有二叉树的根结点进行排序,因此可用数组a作为排序暂存空间,其中第i个数组元素a[i]是森林F中第i棵二叉树的根结点,有2个域,data是根结点所对应的权值,addr是根结点在F中的地址。在初始状态下:a[i].data=Wi,a[i].addr=i,i=1,2,…n。
最后依次输出就可以了。

代码

type
  arr=record
       data:integer;
       lchild,rchild:integer;
       addr:integer;
      end;
var
  i,j,t,n:longint;
  s:string;
  a,f:array[0..100]of arr;

procedure sort(k:longint);//排序
var
  i,j:longint;
  t:arr;
begin
  for i:=1 to k-1 do
    for j:=i+1 to k do
      if a[i].data>a[j].data then
        begin
          t:=a[i];a[i]:=a[j];a[j]:=t;
        end;
end;

procedure visit(k:longint;s:string);
begin
  if f[k].data=0 then exit;
  visit(f[k].lchild,s+'0');
  inc(i);
  if i mod 2=0 then//这样可以刚好输出答案
  writeln(f[k].data,':',s);
  visit(f[k].rchild,s+'1');
end;

begin
  readln(n);
  for i:=1 to n do
    begin
      readln(a[i].data);
      f[i].data:=a[i].data;
      a[i].addr:=i;
    end;
  t:=n+1;i:=n;
  while i>1 do
    begin
      sort(i);
      f[t].data:=a[1].data+a[2].data;
      //最小的两棵树组成新树
      f[t].lchild:=a[1].addr; //因为排了序,所以a[1]的权值比a[2]小,a[1]作为左子树
      f[t].rchild:=a[2].addr;
//更新a[1]和a[2]的值
      a[1].addr:=t;
      a[2].data:=a[i].data;
      a[2].addr:=a[i].addr;
      inc(t);
      dec(i);
    end;
  i:=1;
  visit(t-1,s);//输出
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值