贪心算法:活动选择问题与霍夫曼编码

引言

贪心算法是一种在每一步选择中都采取当前最优解的方法。贪心算法通常用于解决一些优化问题,它的主要优势在于其简单性和高效性。本文将详细介绍两个经典的贪心算法问题:活动选择问题和霍夫曼编码。

目录

  1. 活动选择问题
  2. 霍夫曼编码

活动选择问题

定义

活动选择问题是一个经典的贪心算法问题,目的是在给定的一组活动中选择尽可能多的活动,使得这些活动互不重叠。

问题描述

假设有一组活动 (A = {a_1, a_2, \ldots, a_n}),每个活动 (a_i) 都有一个开始时间 (s_i) 和一个结束时间 (f_i)。活动选择问题要求选择尽可能多的活动,使得这些活动互不重叠,即对于任意两个选择的活动 (a_i) 和 (a_j),有 (f_i \leq s_j) 或 (f_j \leq s_i)。

贪心选择策略

贪心选择策略是每次选择结束时间最早且不与已选择活动重叠的活动。

示例

假设有以下活动:

复制代码
活动     开始时间  结束时间
a1       1        4
a2       3        5
a3       0        6
a4       5        7
a5       3        9
a6       5        9
a7       6        10
a8       8        11
a9       8        12
a10      2        14
a11      12       16

贪心算法实现

下面是用Java实现活动选择问题的代码示例:

java 复制代码
import java.util.*;

public class ActivitySelection {
    // 活动类,包含开始时间和结束时间
    static class Activity {
        int start;
        int finish;

        Activity(int start, int finish) {
            this.start = start;
            this.finish = finish;
        }
    }

    // 活动选择算法
    public static void selectActivities(List<Activity> activities) {
        // 按结束时间升序排序
        activities.sort(Comparator.comparingInt(a -> a.finish));

        System.out.println("选中的活动:");

        // 第一个活动总是被选中
        Activity lastSelected = activities.get(0);
        System.out.println("活动 (" + lastSelected.start + ", " + lastSelected.finish + ")");

        // 选择其他活动
        for (int i = 1; i < activities.size(); i++) {
            Activity currentActivity = activities.get(i);
            if (currentActivity.start >= lastSelected.finish) {
                System.out.println("活动 (" + currentActivity.start + ", " + currentActivity.finish + ")");
                lastSelected = currentActivity;
            }
        }
    }

    public static void main(String[] args) {
        List<Activity> activities = Arrays.asList(
                new Activity(1, 4),
                new Activity(3, 5),
                new Activity(0, 6),
                new Activity(5, 7),
                new Activity(3, 9),
                new Activity(5, 9),
                new Activity(6, 10),
                new Activity(8, 11),
                new Activity(8, 12),
                new Activity(2, 14),
                new Activity(12, 16)
        );

        selectActivities(activities);
    }
}

活动选择问题的详细图解

以下是活动选择问题的执行过程图解:
选择活动过程 活动 排序后的活动 活动a1 1, 4 活动a4 5, 7 活动a8 8, 11 活动a11 12, 16 活动a1 1, 4 活动a2 3, 5 活动a3 0, 6 活动a4 5, 7 活动a5 3, 9 活动a6 5, 9 活动a7 6, 10 活动a8 8, 11 活动a9 8, 12 活动a10 2, 14 活动a11 12, 16 活动选择问题 按结束时间升序排序活动 选择第一个活动 选择其他活动 选择结束

霍夫曼编码

定义

霍夫曼编码(Huffman Coding)是一种用于数据压缩的贪心算法。通过构建最优前缀码,使得出现频率较高的字符使用较短的编码,而出现频率较低的字符使用较长的编码,从而达到压缩数据的目的。

问题描述

给定一个字符集及其对应的权重(出现频率),通过霍夫曼编码生成最优前缀码,使得编码后的总长度最短。

贪心选择策略

贪心选择策略是每次选择权重最小的两个节点,合并它们,并将新节点的权重设为两个节点权重之和。

示例

假设有以下字符及其对应的权重:

复制代码
字符    权重
A       5
B       9
C       12
D       13
E       16
F       45

霍夫曼编码算法实现

下面是用Java实现霍夫曼编码的代码示例:

java 复制代码
import java.util.PriorityQueue;

public class HuffmanCoding {
    // 节点类,包含字符、权重、左子节点和右子节点
    static class Node implements Comparable<Node> {
        char character;
        int frequency;
        Node left;
        Node right;

        Node(char character, int frequency) {
            this.character = character;
            this.frequency = frequency;
        }

        Node(int frequency, Node left, Node right) {
            this.frequency = frequency;
            this.left = left;
            this.right = right;
        }

        @Override
        public int compareTo(Node o) {
            return this.frequency - o.frequency;
        }
    }

    // 构建霍夫曼树
    public static Node buildHuffmanTree(char[] characters, int[] frequencies) {
        PriorityQueue<Node> priorityQueue = new PriorityQueue<>();
        for (int i = 0; i < characters.length; i++) {
            priorityQueue.add(new Node(characters[i], frequencies[i]));
        }

        while (priorityQueue.size() > 1) {
            Node left = priorityQueue.poll();
            Node right = priorityQueue.poll();
            Node newNode = new Node(left.frequency + right.frequency, left, right);
            priorityQueue.add(newNode);
        }

        return priorityQueue.poll();
    }

    // 打印霍夫曼编码
    public static void printHuffmanCodes(Node root, String code) {
        if (root == null) {
            return;
        }

        if (root.character != '\0') {
            System.out.println(root.character + ": " + code);
        }

        printHuffmanCodes(root.left, code + "0");
        printHuffmanCodes(root.right, code + "1");
    }

    public static void main(String[] args) {
        char[] characters = {'A', 'B', 'C', 'D', 'E', 'F'};
        int[] frequencies = {5, 9, 12, 13, 16, 45};

        Node root = buildHuffmanTree(characters, frequencies);
        printHuffmanCodes(root, "");
    }
}

霍夫曼编码的详细图解

以下是霍夫曼编码问题的执行过程图解:
霍夫曼编码生成 合并过程 字符及权重 根节点: ABCDEF 100 左子节点: ABCDE 55 右子节点: F 45 左子节点: AB 14 右子节点: CD 25 左子节点: A 5 右子节点: B 9 左子节点: C 12 右子节点: D 13 生成编码 打印霍夫曼编码 初始队列 A 5, B 9, C 12, D 13, E 16, F 45 合并 A 5 和 B 9 生成新节点 AB 14 更新队列 队列: AB 14, C 12, D 13, E 16, F 45 合并 C 12 和 D 13 生成新节点 CD 25 更新队列 队列: AB 14, CD 25, E 16, F 45 合并 AB 14 和 E 16 生成新节点 ABE 30 更新队列 队列: ABE 30, CD 25, F 45 合并 ABE 30 和 CD 25 生成新节点 ABCDE 55 更新队列 队列: ABCDE 55, F 45 合并 ABCDE 55 和 F 45 生成根节点 ABCDEF 100 A 5 B 9 C 12 D 13 E 16 F 45 霍夫曼编码 初始化优先队列 将每个字符和权重加入优先队列 选择两个权重最小的节点 合并两个节点并加入新节点到优先队列 重复选择和合并直到优先队列只剩一个节点 生成霍夫曼树 生成霍夫曼编码 结束

结论

通过上述讲解和实例代码,我们详细展示了贪心算法在活动选择问题和霍夫曼编码中的应用。贪心算法是一种简单且高效的算法,适用于许多优化问题。希望这篇博客对您有所帮助!


如果您觉得这篇文章对您有帮助,请关注我的CSDN博客,点赞并收藏这篇文章,您的支持是我持续创作的动力!


关键内容总结:

  • 活动选择问题的定义和实现
  • 霍夫曼编码的定义和实现
  • 两种贪心算法的应用示例及详细图解

推荐阅读:深入探索设计模式专栏 ,详细讲解各种设计模式的应用和优化。点击查看:深入探索设计模式。


特别推荐:设计模式实战专栏 ,深入解析设计模式的实际应用,提升您的编程技巧。点击查看:设计模式实战。

如有任何疑问或建议,欢迎在评论区留言讨论。谢谢阅读!

相关推荐
吠品11 分钟前
Flutter 工程配本地 Maven 引 AAR,仓库声明为啥不生效
c语言·人工智能·算法
罗湖老棍子15 分钟前
【例题1】黑暗城堡(信息学奥赛一本通- P1486)
算法·图论·最短路·dijkstra·最小生成树·最短路径生成树
hetao173383730 分钟前
2026-10-20 hetao1733837 的刷题记录
c++·算法
碧海银沙音频科技研究院2 小时前
基于ATS308X的无线语音交互对话功能实现
人工智能·嵌入式硬件·深度学习·算法
尹玉玺3 小时前
从原子残片到天道公理:以德谟克利特思想全貌,重新定界西方唯物认知的历史层级与边界
人工智能·算法·架构
青少儿编程课堂3 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:差分数组与区间修改实战解析
c++·python·算法·bfs·信息学竞赛
重生之小比特3 小时前
【算法拾光】二分查找|二分查找 + 再排序数组中查找元素的第一个和最后一个位置
算法·leetcode·职场和发展
零基础1233 小时前
基于模型的强化学习与不基于模型的强化学习:核心区别与实战选择
python·算法
罗西的思考14 小时前
【Agentic RL】Dressage Staleness 控制深度分析
人工智能·算法·机器学习