- •Метод арифметичного кодування
- •Постановка задачи Тема работы: Сжатие текстовой информации методом арифметического кодирования. Задание:
- •Реализация метода
- •Разработанный проект
- •Проект, разработанный на wpf
- •Решение задачи ргр
- •Исходный код программы
- •Класс, представляющий алфавит
- •Класс, реализующий алгоритм арифметического кодирования
- •Класс главного окна
- •Итак, если Вам важно качественно сжать данные, то используйте арифметическое кодирование. Если же Вам нужно быстро реализовать процесс компрессии, то лучше выбрать алгоритм Хаффмана.
Разработанный проект
Проект, разработанный на wpf
Рисунок 1 представляет работу алгоритма на маленьком примере. На рисунке 2 продемонстрирована работа со всем русским алфавитом. Числа выходят большими, поэтому использование BigInteger вполне оправдано.
Решение задачи ргр
Исходный код программы
Класс, представляющий алфавит
public class Letter : INotifyPropertyChanged
{
/// <summary>
/// Represents a general name of a sign
/// </summary>
public string Name { get; set; }
/// <summary>
/// Represents the very sign
/// </summary>
public char Char { get; set; }
private double _p;
public double Probability
{
get { return _p; }
set
{
_p = value;
NotifyPropertyChanged("Probability");
}
}
// For automatic updating in the window
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Класс, реализующий алгоритм арифметического кодирования
/// <summary>
/// Algorithm class
/// </summary>
public class Arithmetic : INotifyPropertyChanged
{
// list of letters and their probabilities
private List<Letter> letters;
// temporary list of sums
private List<long> sums;
// edges
private BigInteger left, right;
// input text
private string text;
private int curLetter, power;
// output text
private string encodedText = "";
/// <summary>
/// 2^Power in denominator
/// </summary>
public int Power
{
get { return power; }
}
/// <summary>
/// Current left edge
/// </summary>
public BigInteger Left
{
get { return left; }
}
/// <summary>
/// Current right edge
/// </summary>
public BigInteger Right
{
get { return right; }
}
public string EncodedText
{
get { return encodedText; }
private set { encodedText = value; NotifyPropertyChanged("EncodedText"); }
}
public Arithmetic(List<Letter> letters, int symbolsAmount, string text)
{
this.text = text.Clone() as string;
this.sums = new List<long>();
this.curLetter = -1;
this.letters = letters;
var min = letters[0];
sums.Add(0);
foreach (var cur in letters)
{
if (min.Probability > cur.Probability) min = cur;
sums.Add(sums[sums.Count - 1] + Convert.ToInt64(cur.Probability*1000));
}
var maxVal = 1/min.Probability;
right = new BigInteger(maxVal);
right = BigInteger.Pow(right, symbolsAmount);
power = Convert.ToInt32(Math.Ceiling(BigInteger.Log(right, 2)));
right = BigInteger.Pow(new BigInteger(2), power);
left = 0;
}
public bool MakeAStep()
{
if (curLetter == text.Length - 1) return true;
curLetter++;
var encodeChar = Char.ToLower(text[curLetter]);
var index = letters.FindIndex(0, n => n.Char == encodeChar);
if (index == -1) return false;
index++;
var tmp = new BigInteger(sums[index - 1]);
tmp = BigInteger.Multiply((right - left), tmp);
tmp = BigInteger.Divide(tmp, new BigInteger(1000));
left = left + tmp;
tmp = new BigInteger(sums[sums.Count - 1] - sums[index]);
tmp = BigInteger.Multiply((right - left), tmp);
tmp = BigInteger.Divide(tmp, new BigInteger(1000));
right = right - tmp;
encodedText += encodeChar;
return false;
}
// for auto updating
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
