欢迎光临
我们一直在努力

使用Java编写一个求集合所有子集的代码

1.1 文档目的

本文档对M源代码进行完整说明,包含程序功能、数据结构、核心逻辑、代码注释、缺陷分析、运行现象、源码全量带注释版本,供开发调试、课程实验查阅使用。

1.2 开发环境

  • 开发语言:Java 8+
  • 依赖集合类:ArrayList、HashMap、List、Map
  • 包路径:com

1.3 整体功能

本程序在求解一个集合的子集的过程中,需要首先对集合进行从小到大排序,然后通过递归迭代求出所有子集。

1.4 程序缺点

求子集的前期是需要先对数进行排序,然后才能算出每个子集中包含的数字。不能在不排序的情况下求出所有子集。感兴趣都可以自己研究下 。

2 数据结构设计

全局共享容器 Map<String, List<List<Integer>>> map,三个固定 Key 承担不同存储职责:

表格

Key 名称存储结构作用说明
list List<List<Integer>> 原始数据源,仅存放 1 个一维数组,即输入数字集合[1,4,6,7,8]
lists List<List<Integer>> 全局结果集,存放所有生成完成的递增子序列
prev List<List<Integer>> 缓存上一轮递归产出的子序列,用于本轮拼接生成更长子序列

辅助局部变量说明:

  • list:从map.get("list")取出原始一维数字数组
  • listPrev:接收prev缓存集合,区分首次递归 / 迭代扩展递归
  • u:临时集合,存储本轮新生成的加长子序列,递归结束后赋值给prev
  • 3 核心方法说明

    3.1 递归方法 getR

    方法签名

    java

    运行

    public static Map<String, List<List<Integer>>> getR(Map<String, List<List<Integer>>> map)

    入参

    map:全局数据容器,包含原始数据、结果集、上一轮子序列缓存

    返回值

    传入的原Map对象(引用传递,内部数据已被递归修改)

    分支逻辑拆分
    分支 1:prev 为空(首次递归入口)
  • 遍历原始数组每个数字,生成长度为 1 的单元素子序列;
  • 所有单元素序列存入全局结果lists;
  • 将单元素序列存入临时集合u,赋值给prev;
  • 递归调用自身,进入长序列生成逻辑。
  • 分支 2:prev 存在数据(扩展更长子序列)
  • 遍历上一轮全部短子序列;
  • 复制当前短序列,遍历原始数组所有数字;
  • 判断:序列末尾数字 < 当前遍历数字,满足则拼接新序列;
  • 新序列存入全局结果集,同时存入临时集合u;
  • 更新prev为本轮拼接出的长序列;
  • 递归调用自身,继续生成更长子序列。
  • 4 Main 主方法执行流程

  • 初始化空集合、存储 Map 容器;
  • 填充原始数字数组 [1,4,6,7,8],封装为二维集合存入list键;
  • 初始化空结果集lists、空缓存prev放入 Map;
  • 调用递归方法getR(map)开始生成子序列;
  • 取出递归后的结果集,手动新增一个空一维集合插入结果列表;
  • 打印修改后的结果集合;
  • 5 完整代码如下

    java

    运行

    package com;

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    /**
    * 递归生成严格递增子序列程序
    * 功能:基于有序数字数组,递归构造全部严格递增子序列
    * 缺陷:无递归终止条件,无限递归触发栈溢出StackOverflowError
    */
    public class MyProject {
    /**
    * 递归核心函数,循环扩展生成递增子序列
    * @param map 全局数据存储容器
    * key=list:原始一维数字数组(二维包装)
    * key=lists:所有递增子序列总结果集
    * key=prev:上一轮生成的子序列缓存,用于拼接更长序列
    * @return 修改完成数据后的map引用对象
    */
    public static Map<String,List<List<Integer>>> getR( Map<String,List<List<Integer>>> map){
    // 获取原始数字一维数组 [1,4,6,7,8]
    List<Integer> list=map.get("list").get(0);
    // 获取全局结果集合,存放所有子序列
    List<List<Integer>> lists=map.get("lists");
    // 定义变量接收上一轮子序列缓存
    List<List<Integer>> listPrev=new ArrayList<>();
    // 若prev缓存存在数据,则赋值给临时变量
    if(map.get("prev").size()>0){
    listPrev=map.get("prev");
    }

    // 判断:存在上一轮生成的子序列,需要拼接更长序列
    if(listPrev!=null&&listPrev.size()>0){
    // 空分支,无任何处理逻辑,冗余代码
    if(listPrev.size()==1){

    }else{
    // u存储本轮新生成的加长子序列,作为下一轮prev缓存
    List<List<Integer>> u=new ArrayList<>();
    // 遍历上一轮所有短子序列
    for(int i=0;i<listPrev.size();i++){
    // 复制当前子序列,防止修改原缓存集合
    List<Integer> l=new ArrayList<>();
    l.addAll(listPrev.get(i));
    // 遍历原始数组所有数字,尝试尾部追加
    for(int j=0;j<list.size();j++){
    // 严格递增判定:序列最后一位小于待追加数字
    if(l.get(l.size()-1)<list.get(j)){
    // 构建新子序列
    List<Integer> list1=new ArrayList<>();
    list1.addAll(l);
    // 追加更大数值,生成长度+1的递增子序列
    list1.add(list.get(j));
    // 存入全局结果集
    lists.add(list1);
    // 存入本轮临时集合,用于下一轮递归
    u.add(list1);
    }
    }
    // 同步更新map内的结果集
    map.put("lists", lists);
    }
    // 将本轮生成序列设置为下一轮的prev缓存
    map.put("prev", u);
    // 递归调用,继续生成更长子序列
    getR(map);
    }

    }else{
    // 首次递归:prev缓存为空,生成长度为1的单元素子序列
    List<List<Integer>> u=new ArrayList<>();
    // 遍历原始数组每一个数字
    for(int i=0;i<list.size();i++){
    List<Integer> l=new ArrayList<>();
    l.add(list.get(i));
    // 存入全局结果
    lists.add(l);
    // 存入临时集合,作为下一轮prev数据
    u.add(l);
    }
    // 更新map缓存与结果集
    map.put("prev", u);
    map.put("lists",lists);
    // 递归进入长序列扩展逻辑
    getR(map);
    }
    // 返回数据容器
    return map;
    }

    public static void main(String[] args) {
    // 原始数字一维数组
    List<Integer> l=new ArrayList<>();
    // 全局数据存储Map
    Map<String,List<List<Integer>>> map=new HashMap<>();
    // 二维包装容器,用于存放原始一维数组
    List<List<Integer>> m=new ArrayList<>();
    // 初始化全局子序列结果集合
    List<List<Integer>> n=new ArrayList<>();
    // 初始化prev空缓存集合
    List<List<Integer>> u=new ArrayList<>();

    // 将空结果集、空前置缓存存入map
    map.put("lists",n);
    map.put("prev", u);

    // 填充待处理有序数字
    l.add(1);
    l.add(4);
    l.add(6);
    l.add(7);
    l.add(8);
    // 一维数组包装进二维集合
    m.add(l);
    // 原始数据源存入map
    map.put("list", m);

    // 调用递归生成所有递增子序列(会无限递归栈溢出)
    map=getR(map);

    // 取出递归后的结果集合(代码无法执行到此处)
    List<List<Integer>> lists1=map.get("lists");
    // 创建空一维列表
    List<Integer> l1=new ArrayList<Integer>();
    // 将空列表插入结果集合首位
    lists1.add(l1);
    // 覆盖map内的结果集
    map.put("lists", lists1);

    // 控制台打印输出(代码无法执行到此处)
    System.out.println(lists1);
    }
    }

    赞(0)
    未经允许不得转载:171主机测评 » 使用Java编写一个求集合所有子集的代码
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址