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

引言

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

目录

  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博客,点赞并收藏这篇文章,您的支持是我持续创作的动力!


关键内容总结

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

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


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

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

相关推荐
网易独家音乐人Mike Zhou1 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
Swift社区4 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman5 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法
IT 青年5 小时前
数据结构 (1)基本概念和术语
数据结构·算法
Dong雨6 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展
SoraLuna6 小时前
「Mac玩转仓颉内测版24」基础篇4 - 浮点类型详解
开发语言·算法·macos·cangjie
liujjjiyun6 小时前
小R的随机播放顺序
数据结构·c++·算法
¥ 多多¥6 小时前
c++中mystring运算符重载
开发语言·c++·算法
trueEve7 小时前
SQL,力扣题目1369,获取最近第二次的活动
算法·leetcode·职场和发展
天若有情6737 小时前
c++框架设计展示---提高开发效率!
java·c++·算法