哈夫曼树链式存储及简单哈夫曼编码VB实现

来源:互联网 发布:北大青鸟java课程表 编辑:程序博客网 时间:2024/05/18 01:55
 

一.哈夫曼树链式存储

首先做如下定义:

Typedef struct HuffNode{

   Int data;/*权值*/

   Struct HuffNode *LChild;

   Struct HuffNode *RChild;

}HuffNode,*HuffTree;

我们在构造时,先建议叶子结点,用一组HuffNode型的指针数组(HuffNode *    S

­­)表示:

Void createHuffTree(HuffTree *ht,int a[],int n)

S[i]=(HuffTree)malloc(sizeof(HuffNode));

S[i]->data=a[i];

S[i]->LChild=NULL;s[i]->RChild=NULL;

然后,找到s[i]->data 的两个结点,设为s[x1],s[x2];定义临时结点 HuffNode* temp;temp=(HuffTree)malloc(sizeof(HuffTree));

Temp->data=s[x1]->data+s[x2]->data;

temp->LChild=s[x1];Temp->RChild=s[x2];

s[x1]=temp;//将temp结点加入到数组s中。删除s[x1];

S[x2]=NULL;//删除s[x2];

接着再找最小的,后面过程是重复的,对于n个叶子结点的哈夫曼树,该循环体其实只用执行n-1次。

最后一步,直接赋值:*ht=temp;

其实上面过程中的指针 temp,完全可以用*ht代替,那样的话,最后一步就赘余了。

代码如下:

#include<stdio.h>

#include<stdlib.h>

#include<malloc.h>

#define M 20

#define INF 100

 

typedef struct HuffNode{

   int data;

   struct HuffNode *LChild;

   struct HuffNode *RChild;

}HuffNode,*HuffTree;

 

void CreateHuffTree(HuffTree *ht){

   int min1,min2,mid;

   HuffNode *s

­­,*temp;

   int i,n,m;

   for(i=0;i<M;i++) s

­­=NULL;/*初始化。。*/

 

   printf("请输入叶子结点的个数\n");

   scanf("%d",&n);

   printf("请输入权值\n");

   for(i=0;i<n;i++){

     s[i]=(HuffNode *)malloc(sizeof(HuffNode));

     scanf("%d",&(s[i]->data));

     s[i]->LChild=NULL;

     s[i]->RChild=NULL;

   }/*创建叶子结点*/

 

   m=n-1;

   do{

     m--;

     mid=INF;

     for(i=0;i<n;i++)

        if((s[i]!=NULL)&&(mid>s[i]->data)) {mid=s[i]->data;min1=i;}

     mid=INF;

     for(i=0;i<n;i++)

        if((s[i]!=NULL)&&(i!=min1)&&(mid>s[i]->data)) {mid=s[i]->data;min2=i;}/*找最小的2个结点*/

 

     temp=(HuffTree)malloc(sizeof(HuffNode));

     temp->data=s[min1]->data+s[min2]->data;

     temp->LChild=s[min1];

     temp->RChild=s[min2];

     s[min1]=temp;

     s[min2]=NULL;

   }while(m);

   (*ht)=temp;

}

 

void PrintTree(HuffTree ht,int n){

   int i;

   if(ht==NULL) return;

   PrintTree(ht->RChild,n+1);

   for(i=0;i<n;i++)

     printf(" ");

   printf("%d\n",ht->data);

   PrintTree(ht->LChild,n+1);

}

 

main(){

   HuffTree ht;

   CreateHuffTree(&ht);

   PrintTree(ht,0);

}

运行结果:

二.哈夫曼编码(Visual Basic 6.0 实现)

算法核心:创建哈夫曼树、加密解密。

1.   创建哈夫曼树:本程序在创建哈夫曼树时采用了静态表的存储方式,与以往相比,哈夫曼树的结点元素增加了两个元素:tag标记与information信息,方便编码。其中information信息可以不要,因为我之前写的哈夫曼树中没有parent信息,本次沿用以前的哈夫曼树的创建方法,为了减少改动故没删掉information信息造成内存的浪费,敬请原谅!!

    关于编码程序及exe文件,已上传CSDN(及新浪爱问):http://download.csdn.net/source/3570180

    欢迎下载。。。

哈夫曼树头结点定义如下:

 Type HuffTree

  data1 As String  结点数据字符串

data2 As Integer ‘结点权值,整型

parent As Integer

LChild As Integer

RChild As Integer

tag As String * 1 ‘定义长度为一的定长字符串,其值为0或1,分别代表该结点是其双亲的左、右孩子

information As Boolean ‘布尔型,标记结点是否有双亲

End Type

其算法思想与数据结构课本上的类同,此处不再赘述。

 

2.   加密:

加密前的处理:

创建好树后,对给定的加密前的字符串S,我们将它进行分割,之所以进行分割,是为了保证加密后的字符串不至于太长,以免解密时发生堆栈溢出错误(系统决定的没办法)!我们将以每十个字符作为一个子串,逐个加密,加密后的串存于数组sJie()中。

加密过程:

首先利用mid函数截取字符串sS中的每个字符依次赋给Os: Os$=mid$(sS,i,1) ‘i为循环变量,i=1 to len(sS)

然后先根遍历哈夫曼树找到结点Os(返回其下标index)

用串Bstring连接该结点的tag值,之后连接其parent结点的tag值,依次找parent,一直到树根,连接其tag值。不过这样得到编码串Bstring与我们需要串是反序的,所以只用将Bstring逆序即可得到加密串。如此重复下去,直到 i=原串的长度(Len(sS))退出即可。

 

3.   解密

解密前的准备:

      解密的串的来源有两种,一种是上次编码后的串,另一种是用户输入的串。对于前一种串,在加密的时候已经进行分割sJie().而对于用户输入的串我们也要进行分割,我们以每30个字符作为一个子串;只不过这种分割不一定是一个整串,这一点有点棘手,只能定义一个全局变量p存储上一步调用解密函数访问到那个点的下标,下次接着访问。如果刚好访问到叶子结点,则下次从根节点(此时p=2*n-2,n为叶子结点的个数)开始访问。

解密操作(函数):

     因为我们之前已经创建了哈夫曼树,所以就不用字符串匹配了,这里我们将直接利用上已经建好的哈夫曼树。

我们利用mid()函数依次截取解密字符串sS中每个字符,依次存于Os中:Os$=mid$(sS,i,1) 此处的i的意义与加密时一样

下面对Os进行判断:(假设定义了树 :ht() as HuffTree)

     如果 Os=0 ,往左孩子转(p=ht(p).LChild);否则,往右孩子转(p=ht(p).RChild).

接着进行判断:判断p是否为叶子结点(ht(p).LChild=-1 And ht(p).RChild=-1),如果是叶子结点,则记下该结的数据(Rstring=Rstring+ht(p).data1)“+”表示连接

并且,又从树根(p=2*n-2)起,进行下一次解密。

====================================================

4.   哈夫曼编码之vb实现:

打开Visual Basic 6.0 ,一共添加3 个窗体(Form1.frm、Form2.frm、Form3.frm)、添加一个模块(Module1.bas)

各个窗体及其上的控件属性见下表:


图片

 

另外,点击菜单编辑器,给form1加两个菜单

菜单1

   标题:设置(&S);名称:Set;可视

菜单2

   标题:帮助(&H);名称:HelpMe;可视

模块Module1.代码如下:

Type HuffTree

data1 As String

data2 As Integer

parent As Integer

LChild As Integer

RChild As Integer

tag As String * 1

information As Boolean

End Type

 

Global xx As Integer

Global PW As String

Global iL As Integer

Global n As Integer

Global p As Integer

 

Function JiaMi(h() As HuffTree, ByVal ss As String)

Dim Os As String * 1

Dim pNode As Integer

Dim x As Integer

Dim BString As String

Dim length As Integer

Dim midstring As String

length = Len(ss)

For i = 1 To length

    Os = Mid(ss, i, 1)

    x = xx

    SearchNode h(), x, Os, pNode

    Do Until h(pNode).parent = -1

    midstring = midstring + h(pNode).tag

    pNode = h(pNode).parent

    Loop

    BString = BString + rev(midstring)

    Os$ = ""

    midstring = ""

Next i

JiaMi = BString

BString = ""

End Function

 

Function JieMi(h() As HuffTree, ss As String)

Dim RString As String

Dim Os As String * 1

Dim length As Integer

length = Len(ss)

i = 1

For i = 1 To length

 Os = Mid(ss, i, 1)

 If Os = "0" Then

   p = h(p).LChild

   Else

   p = h(p).RChild

 End If

 If h(p).LChild = -1 And h(p).RChild = -1 Then

  RString = RString + h(p).data1

  p = xx

 End If

Next i

JieMi = RString

RString = ""

End Function

 

Function SearchNode(h() As HuffTree, i As Integer, Os As String, pNode As Integer)

If i = -1 Then

Exit Function

End If

If h(i).data1 = Os Then

pNode = i

Exit Function

End If

SearchNode h(), h(i).LChild, Os, pNode

SearchNode h(), h(i).RChild, Os, pNode

End Function

Function rev(s As String)

Dim sstring As String

length = Len(s)

For i = 1 To length

sstring = sstring + Mid(s, length - i + 1, 1)

rev = sstring

Next i

End Function

 

Form1代码如下:

Dim ht() As HuffTree

Dim index1, index2 As Integer

Dim sJia, sJie() As String

Private Sub Command1_Click(Index As Integer)

Select Case Index

Case 0

Dim ss As String

Dim length As Integer

ss = Text1.Text

length = Len(ss)

Text1.Text = ""

If length Mod 10 = 0 Then

 iL = length / 10

Else

 iL = length \ 10 + 1

End If

ReDim sJia(iL) As String

ReDim sJie(iL) As String

For i = 0 To iL - 1

sJia(i) = Mid$(ss, i * 10 + 1, 10)

sJie(i) = JiaMi(ht(), sJia(i))

Text1.Text = Text1.Text + sJie(i)

Next i

r = InputBox("加密完成,是否写入文本?(Y/N)")

If UCase(r) = "Y" Then

 Open "JiaString.txt" For Output As #1

  Print #1, Text1.Text

 Close #1

 MsgBox "恭喜,系统已将加密文本写为本软件所在目录下的JiaString.txt;请注意查收!",VbOkOnly,操作成功

End If

'---------------------------------------------------

Case 1

If iL = 0 Then

Dim s As String

s = Text1.Text

l = Len(s)

 If l Mod 30 = 0 Then

    iL = l / 30

    Else

    iL = l \ 30 + 1

 End If

 ReDim sJie(iL) As String

 For i = 0 To iL - 1

    sJie(i) = Mid(s, i * 30 + 1, 30)

 Next i

End If

 Text1.Text = ""

 p = xx

For i = 0 To iL - 1

    Text1.Text = Text1.Text + JieMi(ht(), sJie(i))

Next i

iL = 0

r = InputBox("加密完成,是否写入文本?(Y/N)")

If UCase(r) = "Y" Then

 Open "JieString.txt" For Output As #1

  Print #1, Text1.Text

 Close #1

 MsgBox "恭喜,系统已将加密文本写为本软件所在目录下的JieString.tex;请注意查收!",VbOkOnly,操作成功

End If

'---------------------------------------------------

Case 2

Text1.Text = ""

Case 3

End

End Select

End Sub

Private Function Min2(h() As HuffTree, in1, in2)

Min = 10000

For i = 0 To xx

If h(i).information = False And Min > h(i).data2 Then

Min = h(i).data2

in1 = i

End If

Next i

h(in1).information = True

Min = 10000

For i = 0 To xx

If h(i).information = False And Min > h(i).data2 Then

Min = h(i).data2

in2 = i

End If

Next i

h(in2).information = True

End Function

Private Function CreateHuffTree()

Dim ss As String

Dim obj2 As FileSystemObject

Set obj2 = CreateObject("scripting.filesystemobject")

r = obj2.FileExists("sString.dll")

If r Then

 z = InputBox("是否沿用上次的编码树?(Y/N)")

 If UCase(z) = "Y" Then

    Open "sString.dll" For Input As #1

     Input #1, s1

    Close #1

    x = InStr(1, s1, "~")

    If x = 0 Then

     ss = s1

    Else

     ss = Mid(s1, 1, x - 1) + "," + Mid(s1, x + 1, Len(s1) - x)

    End If

 Else

    ss = Text1.Text

    x = InStr(1, ss, ",")

    If x Then

     s1 = Mid(ss, 1, x - 1) + "~" + Mid(ss, x + 1, Len(ss) - x)

     Else

     s1 = ss

    End If

    Open "sString.dll" For Output As #1

     Print #1, s1

    Close #1

 End If

Else

   ss = Text1.Text

       x = InStr(1, ss, ",")

    If x = 0 Then

     s1 = Mid(ss, 1, x - 1) + "~" + Mid(ss, x + 1, Len(ss) - x)

     Else

     s1 = ss

    End If

    Open "sString.dll" For Output As #1

     Print #1, s1

    Close #1

End If

'---------------------------------------------------

n = Len(ss)

xx = 2 * n - 2

ReDim ht(0 To xx) As HuffTree

For i = 0 To n - 1

ht(i).data1 = Mid$(ss, i + 1, 1)

ht(i).data2 = 1

ht(i).LChild = -1: ht(i).RChild = -1: ht(i).information = False: ht(i).parent = -1

Next i

For i = n To xx

ht(i).data2 = 10000

ht(i).data1 = ""

ht(i).parent = -1

Next i

For i = 0 To n - 2

Min2 ht(), index1, index2

ht(n + i).data2 = ht(index1).data2 + ht(index2).data2

ht(n + i).LChild = index1: ht(n + i).RChild = index2: ht(n + i).information = False

ht(index1).parent = n + i: ht(index2).parent = n + i

ht(index1).tag = "0": ht(index2).tag = "1"

Next i

End Function

 

Private Sub Command2_Click()

CreateHuffTree

Text1.Text = "请输入一个串进行加密或解密"

End Sub

 

Private Sub Form_Load()

Dim Obs As FileSystemObject

Set Obs = CreateObject("Scripting.FileSystemObject")

r = Obs.FileExists("PassWord.dll")

If r = False Then

   PW = ""

Else

   Open "PassWord.dll" For Input As #1

   Input #1, PW

   Close #1

End If

If PW <> "" Then

Form3.Show

Form1.Hide

End If

Text1.Text = "请输入一个串来创建编码树"

End Sub

 

Private Sub HelpMe_Click()

Shell "cmd /chelp\index.htm", vbHide

End Sub

 

Private Sub Set_Click()

Form1.Hide

Form2.Show

End Sub

 

Form2的代码如下:

Private Sub Text1_KeyPress(KeyAscii As Integer)

If KeyAscii = 13 Then

 Text2.SetFocus

End If

End Sub

 

Private Sub Text2_KeyPress(KeyAscii As Integer)

If KeyAscii = 13 Then

 Text3.SetFocus

End If

End Sub

 

Private Sub Text3_KeyPress(KeyAscii As Integer)

If KeyAscii = 13 Then

 Ps1 = Text1.Text

 Ps2 = Text2.Text

 Ps3 = Text3.Text

 If Ps1 <> PW Then

  MsgBox "原密码错误,请检查", vbOKOnly, "Error"

  Form2.Hide

  Form1.Show

 Else

  If Ps2 <> Ps3 Then

    MsgBox "两次输入不一致,请重新输入", vbOKOnly, "Error"

    Text1.Text = ""

    Text2.Text = ""

    Text3.Text = ""

    Text1.SetFocus

  Else

    PW = Ps2

    Open "PassWord.dll" For Output As #1

     Print #1, PW

    Close #1

    Form1.Show

    Form2.Hide

  End If

 End If

End If

End Sub

Form3的代码如下:

Dim s As String

 

Private Sub Text1_KeyPress(KeyAscii As Integer)

s = Text1.Text

If KeyAscii = 13 Then

 Form3.Hide

 Form2.Hide

 Form1.Show

 If s <> PW Then

     MsgBox "密码错误,请检查", vbDefaultButton1, "错误提示"

     End

 End If

End If

End Sub

注:由于本程序的帮助文件使用网页写的,而且镶嵌图片,故此处不列出代码,如想调试运行上述代码,请删除form1代码中的

Private Sub HelpMe_Click()

Shell "cmd /chelp\index.htm", vbHide

End Sub

段。

原创粉丝点击