C# 帮助香农–;法诺编码

C# 帮助香农–;法诺编码,c#,algorithm,C#,Algorithm,你好,我希望有人能帮我做这个=): 我有一组数字,我需要将它们分成两组,两组的总和大致相等,第一组用“1”,第二组用“0”,然后以相同的方式将每组分成子组,直到子组成为集合中的一个数字 图片解释了这些疯狂的事情): 这是基本算法,如果你知道C,它很容易遵循。程序在浏览树时打印分区 请注意,可能存在一些bug,代码的质量与老师期望的作业质量相差几光年。(我猜这是一个家庭作业……如果是为了工作,更糟糕的是,我的代码几乎每天都有WTF质量) 但它应该让您了解基本的算法结构,知道: totalCoun

你好,我希望有人能帮我做这个=): 我有一组数字,我需要将它们分成两组,两组的总和大致相等,第一组用“1”,第二组用“0”,然后以相同的方式将每组分成子组,直到子组成为集合中的一个数字

图片解释了这些疯狂的事情):

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

请注意,可能存在一些bug,代码的质量与老师期望的作业质量相差几光年。(我猜这是一个家庭作业……如果是为了工作,更糟糕的是,我的代码几乎每天都有WTF质量)

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

  • totalCount计算作为参数传递的集合的Count元素之和(如果您不知道聚合)
  • 另一个聚合用法用于显示,忽略它即可
  • 我对排序进行了注释,因为多个元素具有相同的计数,而C#sort函数不保留顺序(我希望得到与相同的结果)
守则:

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();
var符号=新[]{
新符号{Text=“A”,计数=15,概率=double.NaN,代码=”},
新符号{Text=“B”,Count=7,Probability=double.NaN,Code=”“},
新符号{Text=“C”,计数=6,概率=double.NaN,代码=”“},
新符号{Text=“D”,计数=6,概率=double.NaN,代码=”},
新符号{Text=“E”,计数=5,概率=double.NaN,代码=”},
}.ToList();
Func totalCount=
符号=>符号聚合(0,(a,s)=>a+s.Count);
var total=总计数(符号);
foreach(符号中的变量符号)
{
symbol.概率=总数/symbol.计数;
}
//symbols.Sort((a,b)=>b.Count.CompareTo(a.Count));
//当你需要的时候,Y组合器在哪里?
动作递归=null;
递归=(符号、str、深度)=>{
如果(符号数==1)
{
symbols_uu.Single().Code=str;
返回;
}
var bestDiff=int.MaxValue;
int i;
对于(i=1;ia+s.Text+”),
符号跳过(i).聚合(“,(a,s)=>a+s.Text+”);
递归(符号取(i),str+“0”,深度+1);
递归(符号跳过(i)、str+“1”、深度+1);
};
递归(符号“”,0);
WriteLine(新字符串('-',78));
foreach(符号中的变量符号)
{
Console.WriteLine(“{0}\t{1}\t{2}\t{3}”),symbol.Code,symbol.Text,
符号。计数,符号。概率);
}
Console.ReadLine();

您卡在哪里了?这似乎很简单。你给出的例子没有显示分区步骤中的“和”。该算法在维基百科中有记录,基本上是哈夫曼算法的早期版本。OP图片中节点上的值是符号出现的次数。我一直在将数字(频率)划分为组和子组,并用二进制代码分配每个simbol=\非常感谢,我明天会查看您的代码,是的,这是一个家庭作业;)