深夜爆肝:万字长文3种语言实现Huffman树(强烈建议三连)
Posted 刘一哥GIS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深夜爆肝:万字长文3种语言实现Huffman树(强烈建议三连)相关的知识,希望对你有一定的参考价值。
文章目录
一、C语言能干大事
1. C语言下Huffman树的计算过程分析
例1 有权重集合分别是:5、29、7、8、14、23、3、11,计算Huffman树。
这个题目的计算过程如下:
(1)首先是把数据填写在以下表格里:
这个在编程中一定注意:空白格子里是NULL,这点不要搞错。
首先是寻找到两个最小权重的结点,找到的是第7、1号结点,权重合计是8,我们先标记这两个结点s=1(代表已经处理过了),并生成第9号结点,权重是8,并让第7、1号结点的父结点是9,第9号结点的左、右孩子分别是第7、1结点,就是如下表:
重复上面的过程,从头寻找s=0的结点里、权重最小的两个结点、就是第3、4号结点,权重合计是15,这样,标记这两个结点s=1,并生成第10号结点,权重是15,而第7、8的父结点是第10号结点,第10号结点的左右孩子是第3、4号结点,就是下表:
重复这个过程,处理到第15个结点,使其权重合计为100,就是:
最终这个树的计算到此结束,在这样的表中计算出的过程以及结果,就是我们下面编程的主要依据。
2. C语言下Huffman树的编程
针对前面介绍的表格,用C语言描述这样的表就是:
struct Huffman
{
int W,Parent,lChild,rChild,S;
};
对Huffman树,由于它是正则二叉树,所以有n个权重数据则必然有2*n-1个树结点。
有了表的C语言定义,则首先是寻找未标记的、权重最小的结点,如果这个表是H,则全部代码就是:
int FindMinNode(struct Huffman *H,int N)
{
int i,W,Node;
W=100;Node=0;
if(H==NULL) return -1;
for(i=0;i<N;i++)
{
if(H[i].W>0&&H[i].W<W&&H[i].S==0)
{
W=H[i].W;Node=i;
}
}
H[Node].S=1;
return Node;
}
第6至第12行,是一个典型的数组中求最小值的算法,在第13行,则必须标记这个结点的S=1,说明该结点已经使用过,最后则返回这个结点的编号。
有了这个函数后,首先要对H表进行两次求最小值的操作,就是:
min1=FindMinNode(H,N); min2=FindMinNode(H,N);
如第i行是新增的一个结点,则让该表第i行的权重为:
H[i].W=H[min1].W+H[min2].W;
然后,就是设置这个结点的左右孩子结点为min1、min2,就是:
H[i].Parent=-1; H[i].lChild=min1; H[i].rChild=min2;
最后,就是设置编号min1、min2的结点的父结点是第i个结点。
H[min1].Parent=i; H[min2].Parent=i;
全部就是:
int ConstructHuffmanTree(struct Huffman *H,int n)
{
int i;
int min1,min2,N;
if(n==0) return -1;
if(H==NULL) return -2;
N=2*n-1;
for(i=n;i<N;i++)
{
min1=FindMinNode(H,N);min2=FindMinNode(H,N);
H[i].W=H[min1].W+H[min2].W;
H[min1].Parent=i;H[min2].Parent=i;
H[i].Parent=-1;
H[i].lChild=min1;H[i].rChild=min2;
}
return 0;
}
注意这个函数第8行,它是从第n个结点开始循环的。
有了这两个函数后,用一个测试的main()来测试它们:
main()
{
int n,N,i,*D;
struct Huffman *H;
n=8;//组织scanf()输入
N=2*n-1;
D=(int *)malloc(sizeof(int)*n);
//组织scanf()输入。
D[0]=5;
D[1]=29;
D[2]=7;
D[3]=8;
D[4]=14;
D[5]=23;
D[6]=3;
D[7]=11;
H=(struct Huffman *)malloc(sizeof(struct Huffman)*N);
for(i=0;i<N;i++)
{
H[i].W=0;
H[i].Parent=0;
H[i].lChild=0;
H[i].rChild=0;
H[i].S =0;
}
for(i=0;i<n;i++)
H[i].W =D[i];
ConstructHuffmanTree(H,n);
printf("ID\\tW\\tP\\tL\\tR\\n");
for(i=0;i<N;i++)
printf("%d\\t%d\\t%d\\t%d\\t%d\\n",i,H[i].W,H[i].Parent,H[i].lChild,H[i].rChild);
}
运行结果如下图所示:
Huffman树的C语言程序到此为止。
二、C#语言也不赖
1. C#下Huffman类的设计
仅仅针对前面C语言中的计算方法,设计一个类来完成计算过程,这个类就是:
class Huffman
{
public int W, pChild, lChild, rChild, s;
public Huffman()
{
W = pChild = lChild = rChild = -1;
s =0;
}
public Huffman(int Weight, int PChild, int LChild, int RChild, int Select)
{
W = Weight; PChild = pChild; lChild = LChild; rChild = RChild; s = Select;
}
}
2. C#中界面设计
有了这个类以后,我们可以在界面设计上拖进两个命令按钮button1,button2,然后再拖进一个treeView1控件和imageList1控件,然后开始以下设置:
(1) 选择imageList1控件,找到属性images,加入文件夹MyIcon中的两个小图标;
(2) 选择treeView1控件,让imageList属性选中imageList1控件;
(3) 选择treeView1控件,让SelectImageIndex=1(打开书的图标);
(4) 选择treeView1控件,让ImageIndex=0(关闭书的图标);
(5) 选择button1控件,修改text属性为:”简单测试”;
(6) 选择button2控件,修改text属性为:”结束”
3. 建立测试数据并显示Huffman树
设有权重数据为:5,29,7,8,14.23.3.11,注意权重数据和必须是100。首先是编写从Huffman类数组中取得最小权重结点的函数,这个函数编写在Form1程序中,鼠标双击button1,注意在button1_click()前面补充这样的函数,就是:
在这个函数中,H是Huffman结点对象数组,而N是这个数组的数据个数,如果是上例,则N=15。
现在开始补充代码如下:
int FindMinNode(Huffman[] H,int N)
{
int i,W,Node;
W=100;Node=0;
if(H==null) return -1;
for(i=0;i<N;i++)
{
if(H[i].W>0&&H[i].W<W&&H[i].s==0)
{
W=H[i].W;Node=i;
}
}
H[Node].s=1;
return Node;
}
这个函数同C的几乎没什么差别,同样返回这个结点的下标。有这个函数后,就可以构造Huffman树,跟随着上面的函数,继续输入就是:
int ConstructHuffmanTree(Huffman[] H,int n)
{
int i;
int min1,min2,N;
if(n==0) return -1;
if(H==null) return -2;
N=2*n-1;
for(i=n;i<N;i++)
{
min1=FindMinNode(H,N);
min2=FindMinNode(H,N);
H[i].W=H[min1].W+H[min2].W;
H[min1].pChild=i;
H[min2].pChild=i;
H[i].pChild=-1;
H[i].lChild=min1;
H[i].rChild=min2;
}
return 0;
}
其基本算法和C语言的也没什么差别。
但这个Huffman类的树是不能显示在treeView1中的,控件treeView1只能显示TreeNode类型的树,所以要按这个表格的内容构造TreeNode类对象的树。
在treeView1控件中,显示的结点个数同Huffman类的结点个数是一致的,而每个TreeNode类结点的Text内容则是权重,于是紧跟着上面的函数,写以下函数就是:
void dTree(Huffman[] H)
{
int i,n,a,b;
n = H.Count();
TreeNode[] T = new TreeNode[n];
for(i=0;i<n;i++)
T[i]=new TreeNode(H[i].W.ToString());
for (i = 0; i <n; i++)
{
a = H[i].lChild;
b = H[i].rChild;
if (a >= 0) T[i].Nodes.Add(T[a]);
if (b >= 0) T[i].Nodes.Add(T[b]);
}
treeView1.Nodes.Add(T[n-1]);
}
最后,就是补充button1下的程序,按实验数据有:
这组数据一共8个,所以Humman树一共将有2*8-1=15个结点,鼠标双击button1,写进以下程序:
private void button1_Click(object sender, EventArgs e)
{
Huffman[] H = new Huffman[15];
H[0] = new Huffman(5, -1, -1, -1, 0);
H[1] = new Huffman(29, -1, -1, -1, 0);
H[2] = new Huffman(7, -1, -1, -1, 0);
H[3] = new Huffman(8, -1, -1, -1, 0);
H[4] = new Huffman(14, -1, -1, -1, 0);
H[5] = new Huffman(23, -1, -1, -1, 0);
H[6] = new Huffman(3, -1, -1, -1, 0);
H[7] = new Huffman(11, -1, -1, -1, 0);
for (int i = 8; i < 15; i++) H[i] = new Huffman();
ConstructHuffmanTree(H, 8);
dTree(H);
}
到此,简单的Huffman树的测试程序设计完成。最后在button2_click()中补充代码:this.close()
;让程序能正常结束。
4. 输入任意一组数据,完成构造Huffman树
为完成这个要求,首先要在界面设计中再补充控件,有:
(1) 补充listBox1控件;
(2) 补充button3控件,修改Text属性为:“输入确认”;
(3) 补充button4控件,修改Text属性为:”生成Huffman树”;
(4) 补充button5控件,修改Text属性为:”清除”;
(5) 补充textBox1控件;
有了上述控件后,我们首先设计操作过程是:
在textBox1控件中输入数据,按下button3按钮“输入确认”,则输入的数据显示在listBox1控件中,直到所有数据输入完成,于是这样的操作要求的程序就是:
private void button3_Click(object sender, EventArgs e)
{
listBox1.Items.Add(textBox1.Text);
}
listBox1控件是个数据容器,你可以不断追加进很多数据,这些数据全部可以保存在这个控件中。直到按下button4”生成Huffman树”,才开始计算。所以button4的程序就是:
private void button4_Click(object sender, EventArgs e)
{
int n = listBox1.Items.Count;
Huffman[] H = new Huffman[2*n-1];
for (int i = 0; i < 2 * n - 1; i++)
H[i] = new Huffman();
for(int i=0;i<n;i++)
{
int w=int.Parse( listBox1.Items[i].ToString()) ;
H[i].W = w;
}
ConstructHuffmanTree(H, n);
dTree(H);
}
表7中第3行,相当于从listBox1控件中获得数据项的个数,在第9行,就是逐个取得每个数据项,并转换成int类型、赋值给Huffman类对象数组中每个对象的权重W。最后按同样的方式计算并显示在treeView1中。
注意这个程序实际很不理想,没判断输入的数据是否有负值、是否是非数字的字符串、是否和为100等等,这些详细的判断留给同学们自己去完成。
对于button5”清除”的编程非常简单,就是:
private void button5_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
treeView1.Nodes.Clear();
textBox1.Text = "";
}
程序运行效果:
三、JavaScript语言不爱听了
1. JavaScript下Huffman类的设计
针对前面C语言中的计算方法,设计一个类来存储数据,如果你使用的Ext系统,则强烈建议直接使用Ext.data.ArrayStore类对象直接构造它,这样的好处是显示在表格里非常方便,于是说明对象tstore为:
var tstore = new Ext.data.ArrayStore({
data:[
[0,5 ,-1, -1,-1,0],
[1,29,-1, -1,-1,0],
[2,7 ,-1, -1,-1,0],
[3,8 ,-1, -1,-1,0以上是关于深夜爆肝:万字长文3种语言实现Huffman树(强烈建议三连)的主要内容,如果未能解决你的问题,请参考以下文章
坚持原创 绝不注水爆肝万字长文Java 语言的基本特性(喂饭式教程)
与学妹深夜互动,熬夜肝出Java类万字长文,才满足于她...
ChatGPT为啥这么强:万字长文详解 by WolframAlpha之父