c# 对排序输入进行高效霍夫曼编码 | 贪婪算法(Efficient Huffman Coding for Sorted Input | Greedy Algo)

 排序输入的高效霍夫曼编码 示例图

建议先阅读下面的文章:

 c语言:c语言 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)_霍夫曼的贪婪c语言-CSDN博客

c++:c++ 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)_霍夫曼的贪婪算法设计核心代码-CSDN博客

c#:C# 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客

c++ STL:c++ STL 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客

java:java 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客

python:python 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客

javascript:JavaScript 霍夫曼编码 | 贪婪算法(Huffman Coding | Greedy Algo)-CSDN博客

        上面讨论的算法的时间复杂度是 O(nLogn)。如果我们知道给定的数组是排好序的(按频率非递减顺序),我们可以在 O(n) 时间内生成霍夫曼码。以下是针对已排序输入的 O(n) 算法。

1.创建两个空队列。

2.为每个唯一字符创建一个叶节点,并按频率非递减顺序将其入队到第一个队列。最初第二个队列是空的。

3.通过检查两个队列的前面,使两个频率最小的节点出队。重复以下步骤两次 
        1. 如果第二个队列为空,则从第一个队列出队。

2. 如果第一个队列为空,则从第二个队列出队。 
        3. 否则,比较两个队列的前面,并使最小的节点出队。 
        4.创建一个新的内部节点,其频率等于两个节点频率之和。将第一个出队节点设为其左子节点,将第二个出队节点设为右子节点。将此节点入队到第二个队列。
5.重复步骤 3 和 4,直到队列中有多个节点。剩下的节点就是根节点,树就完成了。 

示例代码: 

// Clean c# stl code to generate huffman codes if the array
// is sorted in non-decreasing order
 
using System;
using System.Collections.Generic;
 
// Node structure for creating a binary tree
public class Node {
    public char Ch
    {
        get;
        set;
    }
    public int Freq
    {
        get;
        set;
    }
    public Node Left
    {
        get;
        set;
    }
    public Node Right
    {
        get;
        set;
    }
 
    public Node(char c, int f, Node l = null, Node r = null)
    {
        Ch = c;
        Freq = f;
        Left = l;
        Right = r;
    }
}
 
class Program {
    // Find the min freq node between q1 and q2
    static Node MinNode(Queue<Node> q1, Queue<Node> q2)
    {
        Node temp;
 
        if (q1.Count == 0) {
            temp = q2.Dequeue();
            return temp;
        }
 
        if (q2.Count == 0) {
            temp = q1.Dequeue();
            return temp;
        }
 
        if (q1.Peek().Freq < q2.Peek().Freq) {
            temp = q1.Dequeue();
            return temp;
        }
        else {
            temp = q2.Dequeue();
            return temp;
        }
    }
 
    // Function to print the generated huffman codes
    static void PrintHuffmanCodes(Node root,
                                  string str = "")
    {
        if (root == null)
            return;
        if (root.Ch != '$') {
            Console.WriteLine(root.Ch + ": " + str);
            return;
        }
 
        PrintHuffmanCodes(root.Left, str + "0");
        PrintHuffmanCodes(root.Right, str + "1");
    }
 
    // Function to generate huffman codes
    static void
    GenerateHuffmanCode(List<Tuple<char, int> > v)
    {
        if (v.Count == 0)
            return;
 
        Queue<Node> q1 = new Queue<Node>();
        Queue<Node> q2 = new Queue<Node>();
 
        foreach(var tuple in v)
        {
            q1.Enqueue(new Node(tuple.Item1, tuple.Item2));
        }
 
        while (q1.Count > 0 || q2.Count > 1) {
            Node l = MinNode(q1, q2);
            Node r = MinNode(q1, q2);
            Node node
                = new Node('$', l.Freq + r.Freq, l, r);
            q2.Enqueue(node);
        }
 
        PrintHuffmanCodes(q2.Peek());
    }
 
    static void Main(string[] args)
    {
        List<Tuple<char, int> > v
            = new List<Tuple<char, int> >{
                  Tuple.Create('a', 5),
                  Tuple.Create('b', 9),
                  Tuple.Create('c', 12),
                  Tuple.Create('d', 13),
                  Tuple.Create('e', 16),
                  Tuple.Create('f', 45)
              };
 
        GenerateHuffmanCode(v);
    }

输出: 

f: 0 
c: 100 
d: 101 
a: 1100 
b: 1101 
e: 111

时间复杂度: O(n)
        如果输入未排序,则需要先对其进行排序,然后才能通过上述算法进行处理。排序可以使用堆排序或合并排序来完成,两者都在 Theta(nlogn) 中运行。因此,对于未排序的输入,总体时间复杂度变为 O(nlogn)。 
辅助空间: O(n)

  • 39
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值