帮助Shannon-Fano编码

时间:2010-09-14 18:30:24

标签: c# algorithm

你好,我希望有人会帮我这个=): 我有一些数字,我需要将它们分成两组,大约相等的总和,并将第一组分配为“1”,第二组分配“0”,然后将每组分成相同的方式进入子组,直到子组为止来自集合的数字之一!

图片解释这个疯狂的事情): pict

1 个答案:

答案 0 :(得分:2)

这是基本算法,如果你知道C#,那么它很容易理解。程序在浏览树时打印分区。

请注意,存在一些可能的错误,而且代码距离教师对作业的期望质量还有几年的距离。 (因为我猜这是一个家庭作业......如果它是为了工作,那就更糟了,我的代码几乎是Daily-WTF质量)

但它应该让你了解基本的算法结构,知道:

    如果您不知道Aggregate,
  • totalCount会将作为参数传递的集合的Count元素的总和。
  • 其他聚合用法可供显示,只需忽略它。
  • 我评论了排序,因为多个元素具有相同的计数,而C#排序函数不保留顺序(我希望获得与the wikipedia article相同的结果)

代码:

var symbols = new[] {
    new Symbol { Text = "A", Count=15, Probability=double.NaN, Code=""},
    new Symbol { Text = "B", Count=7,  Probability=double.NaN, Code="" },
    new Symbol { Text = "C", Count=6,  Probability=double.NaN, Code="" },
    new Symbol { Text = "D", Count=6,  Probability=double.NaN, Code="" },
    new Symbol { Text = "E", Count=5,  Probability=double.NaN, Code="" },
}.ToList();

Func<IEnumerable<Symbol>, int> totalCount = 
    symbols_ => symbols_.Aggregate(0, (a, s) => a + s.Count);

var total = totalCount(symbols);
foreach(var symbol in symbols)
{
    symbol.Probability = total / symbol.Count;
}

//symbols.Sort((a, b) => b.Count.CompareTo(a.Count));

// Where is the Y-Combinator when you need it ?
Action<IEnumerable<Symbol>, string, int> recurse = null;
recurse = (symbols_, str, depth) => {
    if (symbols_.Count() == 1)
    {
        symbols_.Single().Code = str;
        return;
    }

    var bestDiff = int.MaxValue;
    int i;
    for(i = 1; i < symbols_.Count(); i++)
    {
        var firstPartCount = totalCount(symbols_.Take(i));
        var secondPartCount = totalCount(symbols_.Skip(i));
        var diff = Math.Abs(firstPartCount - secondPartCount);

        if (diff < bestDiff) bestDiff = diff;
        else break;
    }
    i = i - 1;

    Console.WriteLine("{0}{1}|{2}", new String('\t', depth),
        symbols_.Take(i).Aggregate("", (a, s) => a + s.Text + " "),
        symbols_.Skip(i).Aggregate("", (a, s) => a + s.Text + " "));

    recurse(symbols_.Take(i), str + "0", depth+1);
    recurse(symbols_.Skip(i), str + "1", depth+1);
};

recurse(symbols, "", 0);

Console.WriteLine(new string('-', 78));
foreach (var symbol in symbols)
{
    Console.WriteLine("{0}\t{1}\t{2}\t{3}", symbol.Code, symbol.Text,
        symbol.Count, symbol.Probability);
}
Console.ReadLine();