Код Шеннона
От: Ozone Россия  
Дата: 17.04.03 03:36
Оценка:
Писал лабу (СиАОД) по реализации алгоритма кодирования файлов кодом Шеннона на Pascal'e.
Может кому будет интересно.

program Shennon_code;
uses crt;
type
    TTable = record
       data : byte;
       P    : real;
       Q    : real;
       L    : byte;
       CODE : string[30];
    end;

    pVertex = ^Vertex;
    Vertex = record
      data: byte;
      left, right: pVertex;
    end;
var
  count     : integer;
  Table     : array [1..255] of TTable;
  DATA      : byte;
  T_count   : byte;
  F1, F2    : file of byte;
  L1, L2    : longint;
  L_sr      : real;
  H         : real;
  root      : pVertex;
{/*---------------------------------------------------------------------*/}
function Coding(InputFileName, OutputFileName: string): real;
     {/*............................................*/}
     procedure SortTable;
     var
        tmp_p: TTable;
        i,j: byte;
     begin
          for i:=1 to T_count do begin
             for j:=T_count downto i+1 do begin
               if Table[j].p > Table[j-1].p then begin
                  tmp_P:=Table[j];
                  Table[j]:=Table[j-1];
                  Table[j-1]:=tmp_P;
               end;
             end;
          end;
     end;
     {/*............................................*/}
     function GetCodeWord(Q: real; l: byte): string;
     var
        tmp: string[30];
        i: byte;
     begin
          tmp:='';
          for i:=1 to l do begin
            Q:=Q*2;
            case trunc(Q) of
              0: tmp:=tmp+'0';
              1: tmp:=tmp+'1';
            end;
            if Q >= 1 then Q:=Q-1;
          end;
          GetCodeWord:=tmp;
     end;
     {/*............................................*/}
     procedure ReadFile(FileName: string);
     var
        d,i : byte;
        c   : longint;
        flg : 0..1;
        tmp : real;
     begin
          Assign(F1,FileName);
          Reset(F1);
          c:=1;
          T_count:=1;
          while not EOF(F1) do begin
             read(F1,d); inc(c);
             flg:=0;
             for i:=1 to T_count do
                if Table[i].data = d then begin
                   flg:=1;
                   Table[i].p:=Table[i].p+1;
                   break;
                end;
             if flg = 0 then begin
                   Table[T_count].data:=d;
                   Table[T_count].p:=1;
                   Table[T_count].q:=0;
                   inc(T_count);
             end;
          end; dec(T_count); dec(c);
          Close(F1);

          SortTable;
          for i:=1 to T_count do begin
              Table[i].P := Table[i].P / c;
              if i = 1 then Table[i].Q := 0
              else Table[i].Q := Table[i-1].Q + Table[i-1].P;
              tmp := abs(ln(Table[i].P) / ln(2));
              if tmp - trunc(tmp) > 0.0 then
                 Table[i].L:=trunc(tmp)+1
              else
                 Table[i].L:=trunc(tmp);

              Table[i].Code := GetCodeWord(Table[i].Q, Table[i].L);
              L_sr := L_sr+Table[i].P*Table[i].L;
              H := H+Table[i].P*round(ln(Table[i].P)/ln(2));
          end;
     end;
     {/*............................................*/}
     procedure InsertBits(Q: real; l: byte);
     var
        i: byte;
        tmp: byte;
     begin
          tmp:=0;
          for i:=1 to l do begin
              Q:=Q*2;
              if count < 7  then begin
                 count:=count+1;
                 data := data shl 1;
                 inc(data,trunc(Q));
              end
              else begin
                 write(F2,data); inc(L2);
                 data := 0;
                 inc(data,trunc(Q));
                 count:=0;
              end;
              if Q > 1 then Q:=Q-1;
          end;
     end;
     {/*............................................*/}
var
   d, i: byte;
   L_sr: real;
begin
     count:=-1;
     ReadFile(InputFileName);
     SortTable;
     Assign(F1, InputFileName); Assign(F2, OutputFileName);
     Reset(F1); Rewrite(F2);
     L1:=0; L2:=0;
     while not EOF(F1) do begin
         read(F1,d); inc(L1);
         for i:=1 to T_count do
            if Table[i].data = d then begin
                InsertBits(Table[i].q,Table[i].l);
                break;
            end;
     end;
     if count >= 0 then
        for i:=1 to 7 - count do begin
            data := data shl 1;
            inc(data,0);
        end;
     write(F2,data);
     Close(F1); Close(F2);
end;
{/*---------------------------------------------------------------------*/}
procedure CreateTree;
     {/*................................................*/}
     procedure AddStringINTOVertex(s: string; data: byte);
     var
        p: ^pVertex;
        count: byte;
        i: byte;
     begin
          p:=@root;
          if p^ = nil then begin
             new(p^);
             p^^.data:=0;
             p^^.left:=nil;
             p^^.right:=nil;
          end;
          for i:=1 to length(s) do begin
              if s[i] = '0' then begin
                 p:=@(p^^.left);
                 if p^ = nil then begin
                    new(p^);
                    p^^.data:=0;
                    if (i = length(s)) and (p^^.data = 0) then
                       p^^.data := data;
                    p^^.left:=nil;
                    p^^.right:=nil;
                 end;
              end
              else if s[i] = '1' then begin
                 p:=@(p^^.right);
                 if p^ = nil then begin
                    new(p^);
                    p^^.data:=0;
                    if (i = length(s)) and (p^^.data = 0) then
                       p^^.data := data;
                    p^^.left:=nil;
                    p^^.right:=nil;
                 end;
              end;
          end;
     end;
     {/*................................................*/}
var
   i: byte;
begin
     root:=nil;
     for i:=1 to T_count do begin
        AddStringINTOVertex(Table[i].CODE, Table[i].data);
     end;
end;
{/*---------------------------------------------------------------------*/}
procedure DeCoding(InputFileName, OutputFileName: string);
var
   p: ^pVertex;
     {/*..................................................*/}
     function DecToBin(K: integer): string;
     var
        tmp, c, s: string;
        sum, len, i: integer;
     begin
          s:='';
          str((K mod 2),tmp);
          while K >= 2 do begin
            K := K div 2;
            sum := K mod 2;
            str(sum, c);
            tmp:=tmp+c;
          end;
          len:=length(tmp);
          s:='';
          for i:=0 to len-1 do s:=s+copy(tmp,len-i,1);
          if length(s) < 8 then
            for i:=length(s) to 7 do
              s:='0'+s;
          DecToBin:=s;
     end;
     {/*..................................................*/}
     function FindInVertex(s: string): byte;
     var
        w, i: byte;
     begin
          p:=@root;
          w:=0;
          for i:=1 to length(s) do begin
              if s[i] = '1' then p:=@(p^^.right)
              else if s[i] = '0' then p:=@(p^^.left);
              if p^^.data <> 0 then begin
                 w:=i;
                 break;
              end;
          end;
          FindInVertex:=w;
     end;
     {/*..................................................*/}
var
   str, tmp: string;
   position, len: byte;
   k: longint;
begin
     Assign(F1,InputFileName); Assign(F2,OutputFileName);
     Reset(F1); Rewrite(F2);
     str:=''; K:=0;
     while K <> L1 do begin
       tmp:='';
       if not Eof(F1) then begin
         read(F1,data);
         tmp:=DecToBin(data);
       end;
       str:=str+tmp;
       len:=length(str);
       if len > 200 then begin
          while len > 150 do begin
             position:=FindInVertex(str);
             if position <> 0 then begin
                write(F2, p^^.data);
                delete(str,1,position);
                len:=length(str);
                inc(K);
             end;
          end;
       end else begin
          position:=FindInVertex(str);
          if position <> 0 then begin
             write(F2, p^^.data);
             delete(str,1,position);
             inc(K);
          end;
       end;

     end;
     Close(F1); Close(F2);
end;
var
   i: byte;
BEGIN
     clrscr;
     GotoXY(60,24); writeln('Coding .....     ');
     Coding('1.txt','2.txt');
     GotoXY(1,1);
      writeln('K    = ',L2 / L1:1:5);
      writeln('L_sr = ',L_sr:1:5);
      writeln('H    = ',(-1)*H:1:5);
     GotoXY(60,24); writeln('Make tree ..... ');
     CreateTree;
     GotoXY(60,24); writeln('Decoding .....  ');
     DeCoding('2.txt','3.txt');
     GotoXY(60,24); writeln('The end         ');
     readln
END.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.