허프만 코딩이란? 허프만 코딩은 데이터 압축 알고리즘입니다. 일반적으로 사용되는 zip 압축의 핵심은 Huffman 인코딩이며, HTTP/에서는 Huffman 인코딩을 사용하여 HTTP 헤더를 압축합니다. 이 기사에서는 PHP에서 Huffman 인코딩 및 디코딩 구현 방법을 공유하겠습니다.
1. 허프만 인코딩
단어 개수
허프만 인코딩의 첫 번째 단계는 문서에서 각 문자의 발생 횟수를 계산하는 것입니다. PHP의 내장 함수 count_chars()는 다음과 같이 할 수 있습니다. a 허프만 트리
다음으로, 통계적 결과를 바탕으로 허프만 트리를 구성합니다. 구성 방법은 Wikipedia에 자세히 설명되어 있습니다. 다음은 PHP로 작성된 간단한 버전입니다.
$input = file_get_contents('input.txt'); $stat = count_chars($input, 1);
계산 후 $root는 허프만 트리의 루트 노드를 가리킵니다.
허프만 트리를 기반으로 코딩 사전 생성
허프만 트리를 사용하면 사전을 생성할 수 있습니다. 코딩의 경우 :
$huffmanTree = [];foreach ($stat as $char => $count) { $huffmanTree[] = [ 'k' => chr($char), 'v' => $count, 'left' => null, 'right' => null, ]; }// 构造树的层级关系,思想见wiki:https://zh.wikipedia.org/wiki/%E9%9C%8D%E5%A4%AB%E6%9B%BC%E7%BC%96%E7%A0%81$size = count($huffmanTree);for ($i = 0; $i !== $size - 1; $i++) { uasort($huffmanTree, function ($a, $b) { if ($a['v'] === $b['v']) { return 0; } return $a['v'] < $b['v'] ? -1 : 1; }); $a = array_shift($huffmanTree); $b = array_shift($huffmanTree); $huffmanTree[] = [ 'v' => $a['v'] + $b['v'], 'left' => $b, 'right' => $a, ]; } $root = current($huffmanTree);
파일 쓰기
사전을 사용하여 파일 내용을 인코딩하고 파일에 씁니다. 허프만 인코딩을 파일에 작성할 때 주의할 점이 몇 가지 있습니다.
인코딩 사전을 작성하고 내용을 파일에 함께 작성한 후에는 경계를 구분할 수 없으므로 그들이 차지하는 바이트를 기록해야 합니다. PHP에서 제공하는 fwrite() 함수는 한 번에 8비트(1바이트) 또는 8비트의 정수배를 쓸 수 있습니다. 그러나 허프만 인코딩에서는 문자가 1비트로만 표현될 수 있으며, PHP는 파일에 1비트만 쓰는 작업을 지원하지 않습니다. 따라서 우리는 인코딩을 직접 연결해야 하며 매 8비트를 얻은 후에만 파일을 작성해야 합니다.
8비트를 얻을 때마다 쓰기두 번째 항목과 마찬가지로 최종 파일 크기는 8비트의 정수배가 되어야 합니다. 따라서 전체 인코딩의 크기가 8001비트인 경우 끝에 7개의 0을 추가해야 합니다
function buildDict($elem, $code = '', &$dict) { if (isset($elem['k'])) { $dict[$elem['k']] = $code; } else { buildDict($elem['left'], $code.'0', $dict); buildDict($elem['right'], $code.'1', $dict); } } $dict = []; buildDict($root, '', $dict);
허프만 인코딩 디코딩은 비교적 간단합니다. 먼저 인코딩 사전을 읽은 다음 그에 따라 사전에 원본 문자를 디코딩합니다. 디코딩 과정에서 주의해야 할 문제가 있습니다. 인코딩 과정에서 파일 끝에 여러 개의 0비트를 추가했기 때문에 이 0비트가 특정 파일의 인코딩인 경우 문자가 사전에 있으면 디코딩 오류가 발생합니다.
그래서 디코딩 프로세스 중에 디코딩된 문자 수가 문서 길이에 도달하면 디코딩이 중지됩니다.
$dictString = serialize($dict);// 写入字典和编码各自占用的字节数 $header = pack('VV', strlen($dictString), strlen($input)); fwrite($outFile, $header);// 写入字典本身 fwrite($outFile, $dictString);// 写入编码的内容$buffer = ''; $i = 0;while (isset($input[$i])) { $buffer .= $dict[$input[$i]]; while (isset($buffer[7])) { $char = bindec(substr($buffer, 0, 8)); fwrite($outFile, chr($char)); $buffer = substr($buffer, 8); } $i++; }// 末尾的内容如果没有凑齐 8-bit,需要自行补齐 if (!empty($buffer)) { $char = bindec(str_pad($buffer, 8, '0')); fwrite($outFile, chr($char)); } fclose($outFile);
허프만 인코딩 위키 페이지의 HTML 코드를 로컬에 저장하고 허프만 인코딩 테스트를 진행했습니다. 테스트 결과: 인코딩 전: 418,504바이트
인코딩 후: 280,127바이트
space. 원본 텍스트에 반복되는 내용이 많은 경우 허프만 인코딩으로 절약한 공간은 50% 이상에 달할 수 있습니다.
텍스트 내용 외에도 다음과 같은 바이너리 파일을 허프만 인코딩해 보겠습니다. f.lux 설치 프로그램, 실험 결과는 다음과 같습니다.
인코딩 전: 770,384바이트
인코딩 후: 773,076바이트
인코딩 후에는 사전을 저장할 때 더 많은 공간을 차지합니다. 추가 처리를 하지 않기 때문에 공간을 많이 차지하지 않습니다. 반면 바이너리 파일에서는 각 문자가 나타날 확률이 상대적으로 균일하여 허프만 코딩의 장점을 활용할 수 없습니다.
관련 권장사항:
php는 URL 매개변수를 인코딩하고 디코딩합니다위 내용은 허프만 인코딩이란 무엇입니까? PHP에서 허프만 인코딩 및 디코딩을 구현하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!