贪心算法应用:装箱问题(FFD问题)详解

article/2025/7/1 13:25:34

在这里插入图片描述

贪心算法应用:装箱问题(FFD问题)详解

1. 装箱问题概述

装箱问题(Bin Packing Problem)是计算机科学和运筹学中的一个经典组合优化问题。问题的描述如下:

给定一组物品,每个物品有一定的体积,以及若干容量相同的箱子,目标是用最少数量的箱子装下所有物品。

问题形式化描述

  • 输入:
    • n个物品,每个物品有一个大小wᵢ,其中0 < wᵢ ≤ C(C为箱子容量)
    • 无限数量的箱子,每个箱子容量为C
  • 输出:
    • 将n个物品分配到尽可能少的箱子中,且每个箱子中物品大小之和不超过C

2. 贪心算法简介

贪心算法(Greedy Algorithm)是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。

对于装箱问题,常见的贪心算法策略有:

  1. 首次适应算法(First Fit, FF):将每个物品放入第一个能容纳它的箱子
  2. 最佳适应算法(Best Fit, BF):将每个物品放入能容纳它的最满的箱子
  3. 首次适应递减算法(First Fit Decreasing, FFD):先将物品按大小降序排序,然后使用首次适应算法
  4. 最佳适应递减算法(Best Fit Decreasing, BFD):先将物品按大小降序排序,然后使用最佳适应算法

本文将重点介绍**首次适应递减算法(FFD)**及其Java实现。

3. 首次适应递减算法(FFD)详解

3.1 算法思想

FFD算法是解决装箱问题最常用的启发式算法之一,其基本思想是:

  1. 先将所有物品按体积从大到小排序
  2. 然后依次处理每个物品,将其放入第一个能容纳它的箱子
  3. 如果没有合适的箱子,则开启一个新箱子

3.2 算法步骤

  1. 输入物品列表和箱子容量C
  2. 将物品按体积从大到小排序
  3. 初始化空的箱子列表
  4. 对于每个物品:
    a. 遍历已有箱子,找到第一个能容纳该物品的箱子
    b. 如果找到,将物品放入该箱子
    c. 如果没有找到,创建一个新箱子并将物品放入
  5. 返回使用的箱子列表

3.3 算法复杂度分析

  • 排序阶段:O(n log n),取决于排序算法
  • 装箱阶段:最坏情况下为O(n²),因为对于每个物品可能需要遍历所有箱子

3.4 算法性能

FFD算法有以下性能保证:

  1. 对于任何输入,FFD使用的箱子数不超过(11/9)*OPT + 1,其中OPT是最优解
  2. 对于大多数实际案例,FFD的表现非常接近最优解

4. Java实现FFD算法

4.1 基本实现

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class BinPackingFFD {public static void main(String[] args) {// 示例物品大小List<Integer> items = List.of(4, 8, 5, 1, 2, 3, 6, 7, 9, 4);int binCapacity = 10;List<List<Integer>> bins = firstFitDecreasing(items, binCapacity);System.out.println("使用的箱子数量: " + bins.size());for (int i = 0; i < bins.size(); i++) {System.out.println("箱子 " + (i+1) + ": " + bins.get(i) + " (总大小: " + bins.get(i).stream().mapToInt(Integer::intValue).sum() + ")");}}public static List<List<Integer>> firstFitDecreasing(List<Integer> items, int binCapacity) {// 复制物品列表以避免修改原始数据List<Integer> sortedItems = new ArrayList<>(items);// 按降序排序sortedItems.sort(Collections.reverseOrder());List<List<Integer>> bins = new ArrayList<>();for (int item : sortedItems) {boolean placed = false;// 尝试将物品放入已有箱子for (List<Integer> bin : bins) {int currentBinWeight = bin.stream().mapToInt(Integer::intValue).sum();if (currentBinWeight + item <= binCapacity) {bin.add(item);placed = true;break;}}// 如果没有合适的箱子,创建新箱子if (!placed) {List<Integer> newBin = new ArrayList<>();newBin.add(item);bins.add(newBin);}}return bins;}
}

4.2 优化实现

为了提高效率,我们可以预先计算并存储每个箱子的剩余容量:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class BinPackingFFDOptimized {public static void main(String[] args) {List<Integer> items = List.of(4, 8, 5, 1, 2, 3, 6, 7, 9, 4);int binCapacity = 10;List<Bin> bins = firstFitDecreasingOptimized(items, binCapacity);System.out.println("使用的箱子数量: " + bins.size());for (int i = 0; i < bins.size(); i++) {System.out.println("箱子 " + (i+1) + ": " + bins.get(i).items + " (总大小: " + bins.get(i).currentWeight + ")");}}static class Bin {List<Integer> items = new ArrayList<>();int currentWeight = 0;int capacity;Bin(int capacity) {this.capacity = capacity;}boolean canAdd(int item) {return currentWeight + item <= capacity;}void addItem(int item) {items.add(item);currentWeight += item;}}public static List<Bin> firstFitDecreasingOptimized(List<Integer> items, int binCapacity) {List<Integer> sortedItems = new ArrayList<>(items);sortedItems.sort(Collections.reverseOrder());List<Bin> bins = new ArrayList<>();for (int item : sortedItems) {boolean placed = false;for (Bin bin : bins) {if (bin.canAdd(item)) {bin.addItem(item);placed = true;break;}}if (!placed) {Bin newBin = new Bin(binCapacity);newBin.addItem(item);bins.add(newBin);}}return bins;}
}

4.3 进一步优化:使用优先队列

我们可以使用优先队列来更高效地找到合适的箱子:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;public class BinPackingFFDWithPQ {public static void main(String[] args) {List<Integer> items = List.of(4, 8, 5, 1, 2, 3, 6, 7, 9, 4);int binCapacity = 10;List<Bin> bins = firstFitDecreasingWithPQ(items, binCapacity);System.out.println("使用的箱子数量: " + bins.size());for (int i = 0; i < bins.size(); i++) {System.out.println("箱子 " + (i+1) + ": " + bins.get(i).items + " (总大小: " + bins.get(i).currentWeight + ")");}}static class Bin implements Comparable<Bin> {List<Integer> items = new ArrayList<>();int currentWeight = 0;int capacity;Bin(int capacity) {this.capacity = capacity;}boolean canAdd(int item) {return currentWeight + item <= capacity;}void addItem(int item) {items.add(item);currentWeight += item;}// 按照剩余容量升序排列,这样我们可以优先尝试剩余容量多的箱子@Overridepublic int compareTo(Bin other) {return Integer.compare(other.capacity - other.currentWeight, this.capacity - this.currentWeight);}}public static List<Bin> firstFitDecreasingWithPQ(List<Integer> items, int binCapacity) {List<Integer> sortedItems = new ArrayList<>(items);sortedItems.sort(Collections.reverseOrder());List<Bin> bins = new ArrayList<>();PriorityQueue<Bin> pq = new PriorityQueue<>();for (int item : sortedItems) {Bin bin = pq.peek();if (bin != null && bin.canAdd(item)) {bin = pq.poll();bin.addItem(item);pq.offer(bin);} else {Bin newBin = new Bin(binCapacity);newBin.addItem(item);bins.add(newBin);pq.offer(newBin);}}return bins;}
}

5. 算法测试与验证

5.1 测试用例设计

为了验证我们的实现是否正确,我们可以设计以下测试用例:

  1. 简单测试:少量物品,容易验证

    • 输入:[2, 3, 4, 5], 容量=7
    • 预期:2个箱子 [5,2]和[4,3]
  2. 边界测试

    • 所有物品大小相同
    • 单个物品正好装满一个箱子
    • 单个物品超过箱子容量(应抛出异常)
  3. 随机测试

    • 生成随机物品列表进行测试
  4. 已知最优解测试

    • 使用已知最优解的小规模问题

5.2 测试代码实现

import org.junit.Test;
import static org.junit.Assert.*;
import java.util.List;public class BinPackingFFDTest {@Testpublic void testSimpleCase() {List<Integer> items = List.of(2, 3, 4, 5);int binCapacity = 7;List<List<Integer>> bins = BinPackingFFD.firstFitDecreasing(items, binCapacity);assertEquals(2, bins.size());assertTrue(bins.get(0).containsAll(List.of(5, 2)) || bins.get(1).containsAll(List.of(5, 2)));assertTrue(bins.get(0).containsAll(List.of(4, 3)) || bins.get(1).containsAll(List.of(4, 3)));}@Testpublic void testPerfectFit() {List<Integer> items = List.of(5, 5, 5, 5);int binCapacity = 10;List<List<Integer>> bins = BinPackingFFD.firstFitDecreasing(items, binCapacity);assertEquals(2, bins.size());for (List<Integer> bin : bins) {assertEquals(10, bin.stream().mapToInt(Integer::intValue).sum());}}@Testpublic void testSingleItem() {List<Integer> items = List.of(7);int binCapacity = 10;List<List<Integer>> bins = BinPackingFFD.firstFitDecreasing(items, binCapacity);assertEquals(1, bins.size());assertEquals(7, bins.get(0).stream().mapToInt(Integer::intValue).sum());}@Test(expected = IllegalArgumentException.class)public void testItemTooLarge() {List<Integer> items = List.of(11);int binCapacity = 10;BinPackingFFD.firstFitDecreasing(items, binCapacity);}@Testpublic void testEmptyInput() {List<Integer> items = List.of();int binCapacity = 10;List<List<Integer>> bins = BinPackingFFD.firstFitDecreasing(items, binCapacity);assertTrue(bins.isEmpty());}
}

6. 性能分析与优化

6.1 时间复杂度分析

  1. 排序阶段:O(n log n)
  2. 装箱阶段
    • 基本实现:O(n²) - 对于每个物品,最坏情况下需要检查所有箱子
    • 优先队列优化:O(n log n) - 每次插入和提取操作都是O(log n)

6.2 空间复杂度分析

  • O(n) - 需要存储所有物品和箱子信息

6.3 实际性能测试

我们可以编写性能测试代码来比较不同实现的性能:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;public class BinPackingPerformanceTest {public static void main(String[] args) {int numItems = 10000;int binCapacity = 100;List<Integer> items = generateRandomItems(numItems, binCapacity);// 预热firstFitDecreasing(new ArrayList<>(items), binCapacity);firstFitDecreasingOptimized(new ArrayList<>(items), binCapacity);firstFitDecreasingWithPQ(new ArrayList<>(items), binCapacity);// 测试基本实现long start = System.currentTimeMillis();List<List<Integer>> bins1 = firstFitDecreasing(new ArrayList<>(items), binCapacity);long end = System.currentTimeMillis();System.out.println("基本实现: " + (end - start) + "ms, 箱子数: " + bins1.size());// 测试优化实现start = System.currentTimeMillis();List<BinPackingFFDOptimized.Bin> bins2 = firstFitDecreasingOptimized(new ArrayList<>(items), binCapacity);end = System.currentTimeMillis();System.out.println("优化实现: " + (end - start) + "ms, 箱子数: " + bins2.size());// 测试优先队列实现start = System.currentTimeMillis();List<BinPackingFFDWithPQ.Bin> bins3 = firstFitDecreasingWithPQ(new ArrayList<>(items), binCapacity);end = System.currentTimeMillis();System.out.println("优先队列实现: " + (end - start) + "ms, 箱子数: " + bins3.size());}private static List<Integer> generateRandomItems(int numItems, int maxSize) {List<Integer> items = new ArrayList<>();Random random = new Random();for (int i = 0; i < numItems; i++) {items.add(random.nextInt(maxSize) + 1); // 1到maxSize}return items;}// 这里需要包含前面三个实现的方法...
}

7. 应用场景与扩展

7.1 实际应用场景

装箱问题在现实世界中有许多应用:

  1. 物流与运输:将货物装入集装箱或卡车
  2. 资源分配:云计算中的虚拟机分配
  3. 存储管理:文件存储到磁盘或内存中
  4. 生产计划:任务分配到机器上
  5. 广告投放:将广告分配到固定时长的广告位

7.2 变种与扩展

  1. 多维装箱问题:物品有多个维度(长、宽、高)
  2. 可变大小箱子:箱子大小可以不同
  3. 成本最小化:不同箱子有不同的成本
  4. 在线装箱问题:物品按顺序到达,必须立即分配
  5. 带冲突的装箱问题:某些物品不能放在同一个箱子中

7.3 其他算法比较

虽然FFD是一个很好的启发式算法,但还有其他算法可以解决装箱问题:

  1. 精确算法

    • 分支限界法
    • 动态规划(适用于小规模问题)
  2. 近似算法

    • Next Fit (NF)
    • Worst Fit (WF)
    • Almost Worst Fit (AWF)
  3. 元启发式算法(适用于大规模问题):

    • 遗传算法
    • 模拟退火
    • 禁忌搜索

8. 完整Java实现示例

以下是结合了所有优化和功能的完整实现:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;public class AdvancedBinPackingFFD {public static void main(String[] args) {// 示例使用List<Integer> items = generateRandomItems(20, 10);int binCapacity = 10;System.out.println("物品列表: " + items);BinPackingResult result = packItems(items, binCapacity);System.out.println("使用的箱子数量: " + result.getBinCount());System.out.println("平均填充率: " + String.format("%.2f", result.getAverageFillRate() * 100) + "%");System.out.println("详细装箱情况:");result.printBins();}/*** 装箱结果类*/public static class BinPackingResult {private final List<Bin> bins;private final int binCapacity;public BinPackingResult(List<Bin> bins, int binCapacity) {this.bins = bins;this.binCapacity = binCapacity;}public int getBinCount() {return bins.size();}public double getAverageFillRate() {return bins.stream().mapToDouble(bin -> (double)bin.getCurrentWeight() / binCapacity).average().orElse(0);}public void printBins() {for (int i = 0; i < bins.size(); i++) {Bin bin = bins.get(i);System.out.printf("箱子 %2d: %s (总大小: %2d, 填充率: %5.2f%%)%n",i + 1, bin.getItems(), bin.getCurrentWeight(),(double)bin.getCurrentWeight() / binCapacity * 100);}}public List<Bin> getBins() {return Collections.unmodifiableList(bins);}}/*** 箱子类*/public static class Bin implements Comparable<Bin> {private final List<Integer> items = new ArrayList<>();private int currentWeight = 0;private final int capacity;public Bin(int capacity) {this.capacity = capacity;}public boolean canAdd(int item) {if (item > capacity) {throw new IllegalArgumentException("物品大小超过箱子容量");}return currentWeight + item <= capacity;}public void addItem(int item) {if (!canAdd(item)) {throw new IllegalStateException("无法将物品添加到箱子中");}items.add(item);currentWeight += item;}public List<Integer> getItems() {return Collections.unmodifiableList(items);}public int getCurrentWeight() {return currentWeight;}public int getRemainingCapacity() {return capacity - currentWeight;}@Overridepublic int compareTo(Bin other) {// 按剩余容量降序排列return Integer.compare(other.getRemainingCapacity(), this.getRemainingCapacity());}}/*** 装箱方法*/public static BinPackingResult packItems(List<Integer> items, int binCapacity) {// 验证输入if (binCapacity <= 0) {throw new IllegalArgumentException("箱子容量必须为正数");}for (int item : items) {if (item <= 0) {throw new IllegalArgumentException("物品大小必须为正数");}if (item > binCapacity) {throw new IllegalArgumentException("存在物品大小超过箱子容量");}}// 复制物品列表以避免修改原始数据List<Integer> sortedItems = new ArrayList<>(items);// 按降序排序sortedItems.sort(Collections.reverseOrder());List<Bin> bins = new ArrayList<>();PriorityQueue<Bin> binQueue = new PriorityQueue<>();for (int item : sortedItems) {Bin bin = binQueue.peek();if (bin != null && bin.canAdd(item)) {bin = binQueue.poll();bin.addItem(item);binQueue.offer(bin);} else {Bin newBin = new Bin(binCapacity);newBin.addItem(item);bins.add(newBin);binQueue.offer(newBin);}}return new BinPackingResult(bins, binCapacity);}/*** 生成随机物品列表*/public static List<Integer> generateRandomItems(int count, int maxSize) {List<Integer> items = new ArrayList<>();java.util.Random random = new java.util.Random();for (int i = 0; i < count; i++) {items.add(random.nextInt(maxSize) + 1); // 1到maxSize}return items;}
}

9. 总结

首次适应递减算法(FFD)是解决装箱问题的一种高效启发式算法,通过先将物品按大小降序排序,然后使用首次适应策略,能够在大多数情况下得到接近最优的解。本文详细介绍了:

  1. 装箱问题的定义和贪心算法的基本概念
  2. FFD算法的详细思想和实现步骤
  3. 多种Java实现方式,包括基本实现、优化实现和使用优先队列的实现
  4. 测试用例设计和性能分析方法
  5. 实际应用场景和算法扩展

FFD算法的时间复杂度主要取决于排序阶段(O(n log n))和装箱阶段(O(n²)或优化后的O(n log n)),在实际应用中表现良好。对于需要更高精度的场景,可以考虑结合其他优化算法或精确算法。

更多资源:

https://www.kdocs.cn/l/cvk0eoGYucWA

本文发表于【纪元A梦】!


http://www.hkcw.cn/article/PBDbnQKaYj.shtml

相关文章

如何在 Windows 11 中永久更改默认浏览器:阻止 Edge 占据主导地位

在 Windows 11 中更改默认浏览器对于新手或技术不太熟练的用户来说可能会令人沮丧。 为什么要在 Windows 11 中更改默认浏览器? 这是一个重要的问题:你为什么要从 Microsoft Edge 切换过来? 生态系统集成:如果你已经在广泛使用 Google 服务,Chrome 可以提供无缝集成。同…

【MySQL】视图与用户管理

目录 一、视图 &#xff08;一&#xff09;基本使用 1、创建视图 2、修改视图 3、删除视图 &#xff08;二&#xff09;视图规则和限制 二、用户管理 &#xff08;一&#xff09;用户操作 1、用户信息 2、创建用户 3、删除用户 4、修改用户密码 &#xff08;二&…

PNG文件格式

文章目录 一、概述二、文件结构三、文件署名域四、数据块1、IDHR文件头数据块2、调色板数据块3、IDAT数据块4、IEND数据块 五、其他辅助数据块&#xff08;了解即可&#xff09;六、动态png——APNG 一、概述 PNG是20世纪90年代中期开始开发的图像文件存储格式&#xff0c;其目…

Python_day43

DAY 43 复习日 作业&#xff1a; kaggle找到一个图像数据集&#xff0c;用cnn网络进行训练并且用grad-cam做可视化 进阶&#xff1a;并拆分成多个文件 关于 Dataset 从谷歌图片中抓取了 1000 多张猫和狗的图片。问题陈述是构建一个模型&#xff0c;该模型可以尽可能准确地在图像…

【Quest开发】bug记录——Link界面无音频选项

此方法适用于这个不见了的情况 打开设备管理器&#xff0c;点击卸载 再到Oculus\Support\oculus-drivers找到oculus-driver点击重装驱动&#xff0c;重启电脑即可修复

汇编语言学习(二)——寄存器

目录 一、通用寄存器 二、数据存储 三、汇编指令 四、物理地址 五 、段寄存器 一、通用寄存器 在8086 CPU中&#xff0c;通用寄存器共有四个&#xff0c;分别是 AX、BX、CX 和 DX&#xff0c;它们通常用于存放一般性的数据&#xff0c;均为 16 位寄存器&#xff0c;可以存…

Error creating bean with name *.PageHelperAutoConfiguration 异常解析

一、问题报错 微服务安装成功&#xff0c;启动失败&#xff0c;报错如下&#xff1a; 二、 Spring Boot应用启动错误分析 错误概述 这是一个Spring Boot应用启动过程中出现的Bean创建错误。根据错误堆栈&#xff0c;主要问题在于无法创建PageHelper分页插件的自动配置类。 …

【Zephyr 系列 3】多线程与调度机制:让你的 MCU 同时干多件事

好的,下面是Zephyr 系列第 3 篇:聚焦 多线程与调度机制的实践应用,继续面向你这样的 Ubuntu + 真板实战开发者,代码清晰、讲解通俗、结构规范,符合 CSDN 高质量博客标准。 🧠关键词:Zephyr、线程调度、k_thread、k_sleep、RTOS、BluePill 📌适合人群:想从裸机开发进…

AI万能写作v1.0.12

AI万能写作是一款高度自动化、智能化、个性化的AI智能软件&#xff0c;旨在通过人工智能技术进行内容整合创作&#xff0c;为用户提供便捷高效的写作辅助。这款APP能够一键生成各类素材内容&#xff0c;帮助用户快速获取思路和灵感&#xff0c;成为写作、学习、工作以及日常生活…

【Linux网络篇】:HTTP协议深度解析---基础概念与简单的HTTP服务器实现

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;Linux篇–CSDN博客 文章目录 一.三个预备知识认识域名认识URL认识URL编码和解码 二.http请求…

【JAVA后端入门基础001】Tomcat 是什么?通俗易懂讲清楚!

&#x1f4da;博客主页&#xff1a;代码探秘者 ✨专栏&#xff1a;《JavaSe》 其他更新ing… ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;作者水平有限&#xff0c;欢迎各位大佬指点&…

系统思考:成长与投资不足

最近认识了一位95后年轻创业者&#xff0c;短短2年时间&#xff0c;他的公司从十几个人发展到几百人&#xff0c;规模迅速扩大。随着团队壮大&#xff0c;用户池也在持续扩大&#xff0c;但令人困惑的是&#xff0c;业绩增长却没有明显提升&#xff0c;甚至人效持续下滑。尽管公…

PHP7+MySQL5.6 查立得轻量级公交查询系统

# PHP7MySQL5.6 查立得轻量级公交查询系统 ## 系统简介 本系统是一个基于PHP7和MySQL5.6的轻量级公交查询系统(40KB级)&#xff0c;支持线路查询、站点查询和换乘查询功能。系统采用原生PHPMySQL开发&#xff0c;无需第三方框架&#xff0c;适合手机端访问。 首发版本&#x…

【笔记】Windows系统部署suna基于 MSYS2的Poetry 虚拟环境backedn后端包编译失败处理

基于 MSYS2&#xff08;MINGW64&#xff09;中 Python 的 Poetry 虚拟环境包编译失败处理笔记 一、背景 在基于 MSYS2&#xff08;MINGW64&#xff09;中 Python 创建的 Poetry 虚拟环境里&#xff0c;安装 Suna 开源项目相关包时编译失败&#xff0c;阻碍项目正常部署。 后端…

docker可视化工具

一、portainer&#xff08;不常用&#xff09; 1、安装portainer [rootlocalhost /]# docker run -d -p 8088:9000 --name portainer --restartalways -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data --privilegedtrue portainer/portainer-c…

#16 学习日志软件测试

#16 #13布置的任务都没有wanc 反思一下 一个是贪玩 一个是懒 还有一个原因是学习方式 单看视频容易困 然后是一个进度宝贝 java ai 编程 完 挑着看的 廖雪峰教程 完 速看 很多过时 javaweb ai笔记 见到13.aop 小林coding 看到4.并发 java guide 还没开始 若依框架 笔…

【数据集】NCAR CESM Global Bias-Corrected CMIP5 Output to Support WRF/MPAS Research

目录 数据概述🔍 数据集简介:🧪 数据处理方法:📅 时间范围(Temporal Coverage):📈 模拟情景(Scenarios):🌡️ 关键变量(Variables):📏 垂直层级(Vertical Levels):💾 数据格式与获取方式:数据下载及处理参考🌍 数据集名称: NCAR CESM Global B…

如何用AI写作?

过去半年&#xff0c;我如何用AI高效写作&#xff0c;节省数倍时间 过去六个月&#xff0c;我几乎所有文章都用AI辅助完成。我的朋友——大多是文字工作者&#xff0c;对语言极为敏感——都说看不出我的文章是AI写的还是亲手创作的。 我的AI写作灵感部分来自丘吉尔。这位英国…

dvwa4——File Inclusion

LOW: 先随便点开一个文件&#xff0c;可以观察到url栏变成这样&#xff0c;说明?page是dvwa当前关卡用来加载文件的参数 http://10.24.8.35/DVWA/vulnerabilities/fi/?pagefile1.php 我们查看源码 &#xff0c;没有什么过滤&#xff0c;直接尝试访问其他文件 在url栏的pag…

mysql数据库实现分库分表,读写分离中间件sharding-sphere

一 概述 1.1 sharding-sphere 作用&#xff1a; 定位关系型数据库的中间件&#xff0c;合理在分布式环境下使用关系型数据库操作&#xff0c;目前有三个产品 1.sharding-jdbc&#xff0c;sharding-proxy 1.2 sharding-proxy实现读写分离的api版本 4.x版本 5.x版本 1.3 说明…