n*n矩阵,输出矩阵中任意两点之间所有路径

news2024/11/14 18:43:10

题目1:给你一个正整数n, 构造一个n*n的四项链表矩阵。

要求: 1.使用四项链表

            2.矩阵从左到右,从上到下值依次为1,2,3,4,......n*n

题目2:基于题目1, 在n*n链表矩阵中,输出矩阵中任意两点之间所有路径。

要求: 1.不能使用全局变量

            2.方法只接收两个参数,分别为起始节点

            3.不能重复遍历

构造一个n*n的四项链表矩阵

思路: 要构建一个n*n的矩阵,有这个一个简单思路:

  1. 初始化i=0
  2. 先构建第i行,第i列链表
  3. 再构建(n-1)*(n-1)矩阵
  4. 将第二步链表与第三步矩阵连接起来
  5. i=i+1
  6. 重复第二步

/**
 * @param k 当前要构造K*K矩阵
 * @param n
 * @return
 */
public Node<E> build(int k, int n) {
    if (k <= 0) {
        return null;
    }
    Node<E> head = new Node();
    // 右侧
    Node<E> r = head;
    int i = k - 1;
    while (i > 0) {
        Node<E> right = new Node();
        r.right = right;
        right.left = r;
        r = right;
        i--;
    }
    // 下面
    i = k - 1;
    Node<E> d = head;
    while (i > 0) {
        Node<E> down = new Node();
        d.down = down;
        down.up = d;
        d = down;
        i--;
    }

    // n-1矩阵  subHead n-1矩阵头节点
    Node<E> subHead = build(k - 1, n);

    // 先连接顶部
    Node<E> h = head.right;
    Node<E> subH = subHead;
    while (null != h) {
        h.down = subH;
        subH.up = h;

        h = h.right;
        subH = subH.right;
    }
    // 再连接左侧
    Node<E> down = head.down;
    Node<E> subDown = subHead;
    while (null != down) {
        down.right = subDown;
        subDown.left = down;

        down = down.down;
        subDown = subDown.down;
    }
    return head;
}

 输出矩阵中任意两点之间所有路径

思路: 深度优先搜索(DFS) + 回溯

  1. 如果起始节点相等,直接输出,结束
  2. 起两个栈, 一个主栈,一个副栈
    1. 主栈:存放线路上的节点,用于符合条件时直接输出
    2. 副栈:存放主栈节点的邻接节点集合,需考虑边界与重复遍历问题
  3. 起始节点入主栈,起始节点的邻接节点入副站
  4. 副栈弹出节点集合
    1. 弹出集合中第一个节点node(集合长度-1)
    2. 集合重新入副栈
  5. 如果node=null, 主栈、副栈执行pop()操作,表示需要回溯到上一步(可以理解为,当前无路可走,需要从上一个节点试图走其他方向), 跳转并重复第4步
  6. 如果node!=null, 将node节点压入主栈
  7. 此时如果node==终止节点,则输出主站所有节点,弹出主栈节点(此时==终止节点),跳转并重复第4步
  8. 将node邻接节点压入副栈

如下图5 * 5矩阵, 起始节点7 ,终止节点19

第一次                                                                       

第二次 

第三次

第四次                                     

第五次                                   

第六次

 第**次

  • 此时主栈栈顶元素为19,等于终止节点,则输出主占所有节点值
  • 弹出主栈栈顶节点19,从新取副栈栈顶节点
  • 当前主栈栈顶为18,试图从18开始再向其他方向寻找
  • 18邻接节点取出13,压住主栈

这样,不断压入弹出最终可遍历出所有路线

核心代码

public void search(Node<E> startNode, Node<E> endNode) {

    if (startNode == endNode) {
        System.out.println(startNode.v + " ");
        return;
    }

    // 主栈
    Stack<Node<E>> stack = new Stack<>();
    // 副栈
    Stack<Queue<Node<E>>> adjoinStack = new Stack<>();

    // 将开始节点入主栈
    stack.push(startNode);
    // 将起始节点邻接节点集合如副栈
    this.pushAdjoinStack(stack, startNode, adjoinStack);

    while (!stack.empty()) {
        Queue<Node<E>> queue = adjoinStack.pop();
        Node<E> node = queue.poll();

        adjoinStack.push(queue);
        // 如果到无路可走
        if (null == node) {
            adjoinStack.pop();
            stack.pop();
            continue;
        }

        stack.push(node);

        // 找到一个路径
        if (node == endNode) {
            this.printResult(stack);
            // 弹出主栈栈顶元素
            stack.pop();
            continue;
        }

        pushAdjoinStack(stack, node, adjoinStack);

    }
}

/**
 * 将node节点的邻接几点入副站
 * 1. 边界问题
 * 2. 避免重复入副站
 *
 * @param stack
 * @param node
 * @param adjoinStack
 */
public void pushAdjoinStack(Stack<Node<E>> stack, Node<E> node, Stack<Queue<Node<E>>> adjoinStack) {
    Queue<Node<E>> nodeList = new LinkedList<>();
    if (node.up != null && !stack.contains(node.up)) {
        nodeList.offer(node.up);
    }
    if (node.down != null && !stack.contains(node.down)) {
        nodeList.offer(node.down);
    }
    if (node.left != null && !stack.contains(node.left)) {
        nodeList.offer(node.left);
    }
    if (node.right != null && !stack.contains(node.right)) {
        nodeList.offer(node.right);
    }
    adjoinStack.push(nodeList);
}

完整代码:

/**
 * 节点类
 *
 * @author ywl
 * @version 1.0
 * @date 2024/8/21 20:01
 */

public class Node<E> {
    E v;
    Node<E> up;
    Node<E> down;
    Node<E> left;
    Node<E> right;
    
    // 省略 getter setter
}

import java.util.*;

/**
 * 题目1:给你一个正整数n, 构造一个n*n的四项链表矩阵。
 * 题目2:基于题目1, 在n*n链表矩阵中,输出矩阵中任意两点之间所有路径。
 *
 * @author ywl
 * @version 1.0
 * @date 2024/8/21 20:01
 */
public class StLink<E> {

    public Node<E> build(int k, int n) {
        if (k <= 0) {
            return null;
        }
        Node<E> head = new Node();
        // 右侧
        Node<E> r = head;
        int i = k - 1;
        while (i > 0) {
            Node<E> right = new Node();
            r.right = right;
            right.left = r;
            r = right;
            i--;
        }
        // 下面
        i = k - 1;
        Node<E> d = head;
        while (i > 0) {
            Node<E> down = new Node();
            d.down = down;
            down.up = d;
            d = down;
            i--;
        }

        // n-1矩阵  subHead n-1矩阵头节点
        Node<E> subHead = build(k - 1, n);

        // 先连接顶部
        Node<E> h = head.right;
        Node<E> subH = subHead;
        while (null != h) {
            h.down = subH;
            subH.up = h;

            h = h.right;
            subH = subH.right;
        }
        // 再连接左侧
        Node<E> down = head.down;
        Node<E> subDown = subHead;
        while (null != down) {
            down.right = subDown;
            subDown.left = down;

            down = down.down;
            subDown = subDown.down;
        }
        return head;
    }

    public static void main(String[] args) {
        int n = 4;
        StLink<Integer> sl = new StLink<>();
        Node<Integer> head = sl.build(n, n);

        // 循环赋值
        Node<Integer> down = head;
        int c = 1;
        while (null != down) {
            Node<Integer> right = down;
            while (null != right) {
                right.setV(c++);
                right = right.right;
            }
            down = down.down;
        }

        /**
         * 1  2  3  4
         * 5  6  7  8
         * 9  10 11 12
         * 13 14 15 16
         */
        sl.search(head.right, head.right.right.down.down);
    }

    public void search(Node<E> startNode, Node<E> endNode) {

        if (startNode == endNode) {
            System.out.println(startNode.v + " ");
            return;
        }

        // 主栈
        Stack<Node<E>> stack = new Stack<>();
        // 副栈
        Stack<Queue<Node<E>>> adjoinStack = new Stack<>();

        // 将开始节点入主栈
        stack.push(startNode);
        // 将起始节点邻接节点集合如副栈
        this.pushAdjoinStack(stack, startNode, adjoinStack);

        int maxLen = Integer.MAX_VALUE;
        List<List<E>> result = new ArrayList<>();
        while (!stack.empty()) {
            Queue<Node<E>> queue = adjoinStack.pop();
            Node<E> node = queue.poll();
            adjoinStack.push(queue);

            // 如果无路可走
            if (null == node) {
                adjoinStack.pop();
                stack.pop();
                continue;
            }

            stack.push(node);

            // 找到一个路径
            if (node == endNode) {
                List<E> es = this.printResult(stack);
                if(es.size() == maxLen) {
                    result.add(es);
                } else if(es.size() < maxLen) {
                    maxLen = es.size();
                    result = new ArrayList<>();
                    result.add(es);
                }
                // 弹出主栈栈顶元素
                stack.pop();
                continue;
            }

            pushAdjoinStack(stack, node, adjoinStack);

        }

        System.out.println("最小路径:");
        for(List<E> r : result) {
            for(int i = 0; i < r.size(); i++) {
                System.out.print(r.get(i)+" ");
            }
            System.out.println();
        }
    }

    /**
     * 将node节点的邻接几点入副站
     * 1. 边界问题
     * 2. 避免重复入副站
     *
     * @param stack
     * @param node
     * @param adjoinStack
     */
    public void pushAdjoinStack(Stack<Node<E>> stack, Node<E> node, Stack<Queue<Node<E>>> adjoinStack) {
        Queue<Node<E>> nodeList = new LinkedList<>();
        if (node.up != null && !stack.contains(node.up)) {
            nodeList.offer(node.up);
        }
        if (node.down != null && !stack.contains(node.down)) {
            nodeList.offer(node.down);
        }
        if (node.left != null && !stack.contains(node.left)) {
            nodeList.offer(node.left);
        }
        if (node.right != null && !stack.contains(node.right)) {
            nodeList.offer(node.right);
        }
        adjoinStack.push(nodeList);
    }

    private List<E> printResult(Stack<Node<E>> stack) {
        List<E> r = new ArrayList<>();
        Iterator<Node<E>> iterator = stack.iterator();
        while (iterator.hasNext()) {
            Node<E> next = iterator.next();
            r.add(next.v);
            System.out.print(next.v + " ");
        }
        System.out.println();
        return r;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2101563.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5款文案自动生成器,高质量创意文案一键为你生成

在当今竞争激烈的内容创作领域&#xff0c;每一个字、每一句话都承载着巨大的价值。对于创作者而言&#xff0c;文案自动生成器的出现&#xff0c;犹如在茫茫大海中点亮了一座指引方向的灯塔。它们不仅为创作者节省了宝贵的时间和精力&#xff0c;更像是一把神奇的钥匙&#xf…

5.4树,森林

5.4.1树的存储结构 可采用顺序存储结构or链式存储结构 要求能唯一的反映树中各节点之间的逻辑 1.双亲表示法 采用一端连续的空间来存储,同时在每个节点中增设一个伪指针,指示双亲节点在数组中的下标 优点:找双亲节点方便,找孩子不方便 attention:由于根节点无双亲节点,所以…

C++:关于反向迭代器的学习分享

前言&#xff1a; 小编仅是一位初学者&#xff0c;所以对于C的理解有限&#xff0c;文章大概率会出现表达不清楚可能也只是因为小编不知道如何更好表达&#xff0c;本文章仅作为一个学习的总结分享。 反向迭代器的概念 反向迭代器故名思意解释反向的迭代器&#xff0c;与正向迭…

地铁X光危险品检测数据集

地铁X光危险品检测数据集介绍 数据集概览 本数据集旨在为地铁X光安检系统提供高质量的危险品检测训练素材。数据集包含18类常见危险品&#xff0c;总共6265张图像&#xff0c;每张图像均经过精心标注&#xff0c;确保了数据的质量和一致性。数据集适用于多种格式&#xff08;Y…

Spring优缺点和SpringBoot基础和搭建

前言 Spring框架是一个流行的Java企业级开发框架&#xff0c;旨在简化应用程序开发。它的核心特性包括依赖注入和面向切面编程&#xff0c;提供了灵活性和强大的社区支持。然而&#xff0c;Spring也存在学习曲线陡峭和配置复杂等缺点。 Spring Boot是基于Spring的项目&#x…

2024年高教社杯数学建模竞赛须知——三大注意事项

为了让大家在最后一天更好的备注国赛&#xff0c;我们今日将结合2024年国赛的新规给大家讲解国赛中三大主要的事项&#xff1a; 论文模版问题——国赛乃至大部分数模竞赛从来没有给出任何的论文模版&#xff0c;大部分的模版均为一次又一次学生、老师内部传播形成。资料使用问…

文件包含PHP伪协议利用方法

首先我们需要把配置文件php.ini 在 php.ini ⾥有两个重要的参数 allow_url_fopen 、allow_url_include&#xff1b; allow_url_fopen:默认值是 ON。允许 url ⾥的封装协议访问⽂件&#xff1b; allow_url_include:默认值是 OFF。不允许包含 url ⾥的封装协议包含⽂件&#x…

深度学习-VGG16原理和代码详解

VGG16 原理和代码详解 VGG16 是由牛津大学的 Visual Geometry Group (VGG) 提出的深度卷积神经网络&#xff0c;发表于 2014 年的论文 “Very Deep Convolutional Networks for Large-Scale Image Recognition”。VGG16 是其中的一种结构&#xff0c;由 16 层网络组成&#xf…

win系统安装mysql,使用mysqldump,pycharm使用mysqldump,避坑

文章目录 下载mysql的win客户端设置系统环境变量验证是否可用pycharm使用mysqldump异常问题排查 下载mysql的win客户端 官网下载地址如果下载旧版本&#xff0c;需自行到Archives里面找 本人使用的是mysql5.7&#xff0c;找到相应版本后&#xff0c;点击Download下载 设置系统…

Docker入门笔记

Docker 文章目录 Docker1. 下载 &#xff08;centos&#xff09;2. 部署 MySQL3. 常用命令4. 数据卷5. 自定义镜像6. Java 项目部署 1. 下载 &#xff08;centos&#xff09; 卸载旧版 yum remove docker \docker-client \docker-client-latest \docker-common \docker-lates…

个人旅游网(3)——功能详解——旅游路线功能

文章目录 一、旅游路线分类功能1.1、接口详解1.1.1、findAll 二、路线分类下的旅游路线功能2.2、接口详解2.2.1、findRouteListByCid 三、点击单条旅游路线查看其详情功能3.1、接口详解3.1.1、findRouteListByRid 四、分页功能4.1、导入依赖4.2、配置项的配置4.3、实现分页 一、…

Zotero tags(action and tags for zotero)怎么使用

先在下面的网址安装action and tags for zotero&#xff1a; https://github.com/windingwind/zotero-actions-tags 视频讲解&#xff1a; Zotero Tag -> Actions and Tags for Zotero - 远不止标签管理&#xff01;_哔哩哔哩_bilibili 使用方法&#xff1a; 找到一些表情…

Linux驱动(四):Linux2.6字符设备驱动及GPIO子系统

目录 前言一、Linux2.6字符设备驱动的编写1.设备号2.注册设备号3.释放设备号4.核心结构体5.设备相关的 API 函数6.自动创建设备节点 二、GPIO 子系统1.申请所需gpio口资源2.释放gpio口资源3. 配置 gpio 口的工作模式4.获取gpio口的电平状态5.设置 gpio 的电平状态 三、目标实现…

路由引入(ospf+rip)

1.搭建拓扑图 2.配置接口ip地址

IO进程(线程篇)

知识点链接 https://www.yuque.com/aihenaobaijin/camuoq/lscmvf6z1arklau4?singleDoc# 《IO进程》 建议先学习知识点&#xff0c;再进行下面的练习 线程 概念 线程是一个轻量级的进程&#xff0c;为了提高系统的性能引入线程 线程和进程是参与统一的调度 在同一个进程中可…

【RSA】简单说说什么是RSA非对称加密

希望文章能给到你启发和灵感&#xff5e; 如果觉得文章对你有帮助的话&#xff0c;点赞 关注 收藏 支持一下博主吧&#xff5e; 阅读指南 开篇说明一、基础环境说明1.1 硬件环境1.2 软件环境 二、什么是非对称加密2.1 常见的非对称加密有哪些&#xff1f;2.2 哪些场景适合使用…

渗透测试靶机---- DC系列 DC-4

渗透测试靶机---- DC系列 DC-4 开启靶机&#xff0c;登录页面&#xff0c;平平无奇 扫描ip 端口&#xff0c;服务等信息 访问80 登录窗&#xff01;&#xff01;&#xff01; 这里说明了admin信息&#xff0c;那么就直接爆破这个admin的密码 密码&#xff1a;happy 登录成功 在…

64位Office API声明语句第001讲

跟我学VBA&#xff0c;我这里专注VBA, 授人以渔。我98年开始&#xff0c;从源码接触VBA已经20余年了&#xff0c;随着年龄的增长&#xff0c;越来越觉得有必要把这项技能传递给需要这项技术的职场人员。希望职场和数据打交道的朋友&#xff0c;都来学习VBA,利用VBA,起码可以提高…

华为云征文|使用sysbench对Mysql应用加速测评

文章目录 ❀前言❀测试环境准备❀测试工具选择❀测试工具安装❀mysql配置❀未开启Mysql加速测试❀开启Mysql加速测试❀总结 ❀前言 大家好&#xff0c;我是早九晚十二。 昨天有梳理一篇关于华为云最新推出的云服务器产品Flexus云服务器X。当时有说过&#xff0c;这次的华为云F…

0.3 学习Stm32经历过的磨难

文章目录 用库函数传参 能否按位或STM32库函数XXX_GetFlagStatus和XXX_GetITStatus的区别 用库函数传参 能否按位或 答案是看清况&#xff0c;而不是一股脑的写&#xff01;&#xff08;血泪的经验啊&#xff09; 可行的情况&#xff1a; //如gpio初始化结构体中的gpiopin参…