演示網址:http://huffman.sinaapp.com/php
源文件下載地址:http://xiaocao.u.qiniudn.com/work/huffman-2013-12-19.zipcss
哈夫曼樹─即最優二叉樹,帶權路徑長度最小的二叉樹,常常應用於數據壓縮。 在計算機信息處理中,「哈夫曼編碼」是一種一致性編碼法(又稱「熵編碼法」),用於數據的無損耗壓縮。 簡單的,就是靠權值排序,而後,轉碼,最優保存。html
保存譯碼:在服務器端保存源字符串,命名爲:」Encording.txt」node
保存編碼:在服務器端保存壓縮後壓縮碼,命名爲:」Decording.txt」算法
保存哈夫曼樹:在服務器端保存哈夫曼樹數組,命名爲:」Huffman.txt」數組
瀏覽器本地保存:在本地緩存輸入歷史。而且實現自行選擇本地版本。瀏覽器
前臺表單提交頁面,後臺表單處理頁面,以及哈夫曼壓縮,解壓縮系統。包含兩個主文件:huffman.php和index.php(另外還包含style.css控制樣式,huffman.js保存緩存和控制交互。)
|--index.php(處理基本表單,數據保存) |--huffman.php(壓縮,解壓縮) |--style.css(控制樣式) |--huffman.js(保存緩存和控制交互)緩存
huffman.php
服務器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?php
/* 先介紹幾個php內置函數:
asort()函數對數組進行排序並保持索引關係。主要用於對那些單元順序很重要的結合數組進行排序。
array_shift() 函數刪除數組中的第一個元素,並返回被刪除元素的值。
str_pad(string, long, 補充元素, 類型) 函數把字符串填充爲指定的長度
base_convert() 函數在任意進制之間轉換數
substr(string, start, end) 方法可在字符串中抽取從 start 下標開始的指定數目的字符。
*/
/*=========================================================*/
/*=========================================================*/
/*=========================================================*/
/*
基於靜態huffman編碼的壓縮,要保存的文件有huffmantree(數組), binary(字符串)
本文以PHP做爲描述語言較詳細講解huffman樹原理及應用
*/
?>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
<?php
class
huffman
{
/*
* 壓縮入口
* $str:待壓縮的字符串
*/
public
function
encode(
$str
)
{
$len
=
strlen
(
$str
);
//計算每一個字符權重值(出現的頻度)
//ord(),是php內置ASCII轉化函數,將字符轉化成ASCII碼
for
(
$i
=0;
$i
<
$len
;
$i
++)
$array
[ord(
$str
{
$i
})]=0;
//初始化數組
for
(
$i
=0;
$i
<
$len
;
$i
++)
$array
[ord(
$str
{
$i
})]++;
$HuffmanArray
=
array
();
//asort()函數對數組進行排序並保持索引關係。主要用於對那些單元順序很重要的結合數組進行排序。
asort(
$array
);
/**
* 構造huffman樹,時間複雜度O(nlogn)
* 選擇兩個使用頻率較小<字符在字符串中出現的次數>的結點合併生成出一個樹
*/
//循環建立哈夫曼樹數組
while
(
$item1
= each(
$array
))
{
$item2
= each(
$array
);
$this
->creat_tree(
$item1
,
$item2
,
$array
,
$HuffmanArray
);
asort(
$array
);
}
//array_shift() 函數刪除數組中的第一個元素,並返回被刪除元素的值。
$HuffmanArray
=
array_shift
(
$HuffmanArray
);
$tab
=null;
$code_tab
=
$this
->creat_tab(
$HuffmanArray
,
$tab
);
//壓縮&轉換整個字符串爲二進制表達式
$binary
=null;
for
(
$i
=0;
$i
<
$len
;
$i
++)
$binary
.=
$tab
[ord(
$str
{
$i
})];
//轉化爲壓縮後的字符串
$code
=
$this
->encode_bin(
$binary
);
//靜態huffman編碼算法壓縮後需保留huffman樹
return
array
(
'tree'
=>
$HuffmanArray
,
'len'
=>
strlen
(
$binary
),
'code'
=>
$code
);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* 解壓縮入口
* $huffman:解壓所使用的huffman樹
* $str:被壓縮的字符
* $blen:壓縮前的位長度
*/
public
function
decode(
$huffman
,
$str
,
$blen
)
{
$len
=
strlen
(
$str
);
$binary
=null;
//將編碼解爲二進制表達式
for
(
$i
=0;
$i
<
$len
;
$i
++)
$binary
.=
str_pad
(
base_convert
(ord(
$str
{
$i
}),10,2),8,
'0'
,STR_PAD_LEFT);
$binary
=
substr
(
$binary
,0,
$blen
);
return
$this
->decode_tree(
$binary
,
$huffman
,
$huffman
);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/**
* 將壓縮後的二進制表達式再轉爲字符串
* $binary:二進制表達式字串
*/
private
function
encode_bin(
$binary
)
{
$len
=
strlen
(
$binary
);
//二進制轉字符須要整8位,不足8位補0
$blen
=
$len
+8-
$len
%8;
$binary
=
str_pad
(
$binary
,
$blen
,
'0'
);
$encode
=null;
//每8位轉爲一個字符
for
(
$i
=7;
$i
<
$blen
;
$i
+=8)
{
$frag
=
substr
(
$binary
,
$i
-7,8);
//base_convert() 函數在任意進制之間轉換數字
$encode
.=
chr
(
base_convert
(
$frag
,2,10));
}
return
$encode
;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
/**
* 構造huffman樹,使用貪婪算法選擇最小的兩個元素做爲樹的子節點
* $item1:權重最小的元素1
* $item2:權重次小的元素2
* $array:全部字符出現次數表<權重表>
*$HuffmanArray:保存生成的huffman樹結構
*/
private
function
creat_tree(
$item1
,
$item2
,&
$array
,&
$HuffmanArray
)
{
list(
$key
,
$weight
)=
$item1
;
list(
$key2
,
$weight2
)=
$item2
;
//假設當前樹的左右節點爲空節點
$c1
=
$key
;
$c2
=
$key2
;
//判斷兩個元素若爲樹則直接做爲節點併入主樹
if
(isset(
$HuffmanArray
[
$key2
]))
{
$c2
=
$HuffmanArray
[
$key2
];
unset(
$HuffmanArray
[
$key2
]);
}
if
(isset(
$HuffmanArray
[
$key
]))
{
$c1
=
$HuffmanArray
[
$key
];
unset(
$HuffmanArray
[
$key
]);
}
//設置樹結點權值
$array
[
$key2
]=
$weight
+
$weight2
;
//合併節點後刪除元素
unset(
$array
[
$key
]);
//合併到huffman樹中
$HuffmanArray
[
$key2
]=
array
(0=>
$c1
,1=>
$c2
);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
* 廣度優先遍歷樹,獲得全部原字符對應的二進制表達式<01010...>
* $tree:已經構建好的huffman樹
* $tab:編碼表,保存全部字符對應的編碼
* $a0:左遍歷樹的路徑<11010...>
* $a1:右遍歷樹的路徑
*/
private
function
creat_tab(
$tree
,&
$tab
,
$a0
=null,
$a1
=null)
{
if
(
$tree
==null)
return
;
//遍歷左右子樹
foreach
(
$tree
as
$node
=>
$ctree
)
{
if
(
is_array
(
$ctree
))
{
//判斷未到達葉子節點時再向下遍歷
$this
->creat_tab(
$ctree
,
$tab
,
$a0
.
$node
,
$a1
.
$node
);
}
else
{
//遍歷到葉子節點<原字符ascii碼>時的全部路徑,既二進制表達式,下同
$tab
[
$ctree
]=${
'a'
.
$node
}.
$node
;
}
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
/**
* 使用進製表達式深度優先遍歷樹,0爲左子樹,1爲右子樹,而到根節點,即爲二進制表達式所指向的原字符
* $binary:二進制表達式字串
* $huffman:huffman樹
* $tree:當前所遍歷的子樹
* $i:指向二進制表達式字串的<指針>
* $code:解碼後的字符串
*/
private
function
decode_tree(
$binary
,
$huffman
,
$tree
,
$i
=0,
$code
=null)
{
$lr
=
$binary
{
$i
};
//遍歷完成
if
(
$lr
==null)
return
$code
;
//判斷是否到根節點,根節點既爲二進制表達式對應的原字符ascii碼
if
(
is_array
(
$tree
[
$lr
]))
{
//繼續向下遍歷子樹
return
$this
->decode_tree(
$binary
,
$huffman
,
$tree
[
$lr
],
$i
+1,
$code
);
}
else
{
//將二進制表達式解碼爲原字符
$code
.=
chr
(
$tree
[
$lr
]);
return
$this
->decode_tree(
$binary
,
$huffman
,
$huffman
,
$i
+1,
$code
);
}
}
}
?>
|
下面是js緩存源碼app
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
$( document ).ready(
function
(){
/*函數寫的比較亂,慢慢改進*/
//flag是用來判斷,是否須要添加緩存計數
var
flag=
true
;
function
get_Storage(key){
return
window.localStorage.getItem(key);
}
function
set_Storage(key, value){
return
window.localStorage.setItem(key, value);
}
/*初始化函數*/
function
init(){
var
node =
new
huffman();
$(
"#submited"
).click(
function
(event){
var
value = $(
"#node"
).val();
if
(value!=
''
){
node.set($(
"#node"
).val());
}
});
//顯示選取的文件,添加到div中
$(
'#local'
).click(
function
(event){
var
len= get_Storage(
"length"
);
var
text=
""
;
for
(
var
i = 1; i <= len; i++){
text +=
'<button type="button" class="item btn btn-primary" data='
+i+
'>'
+get_Storage(i)+
'</button><br><br>'
;
}
//若是有內容就顯示,不然,提示用戶添加
if
(len){
$(
'#modal-body'
).html(text);
}
//選擇本地緩存設置
$(
'.item'
).click(
function
(event){
var
id = $(
this
).attr(
"data"
);
$(
"#node"
).val(get_Storage(id));
//設置flag標誌
flag=
false
;
$(
"#close"
).click();
$(
"#submited"
).click();
});
});
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
/*構建原型*/
function
huffman(){}
huffman.prototype={
set:
function
(value){
if
(flag){
if
(get_Storage(
"length"
)){
var
num = parseInt( get_Storage(
"length"
))+1;
set_Storage(
"length"
, num);
}
else
{
set_Storage(
"length"
,1);
}
set_Storage(get_Storage(
"length"
),value);
}
},
get:
function
(){
var
i = get_Storage(
"length"
);
var
array =
new
Array();
for
(p=0; p<i; p++){
var
item=get_Storage(p);
array.push(item);
}
this
.show(array);
},
show:
function
(array){
//這裏要顯示對話框
}
}
window.onload=init();
});
|