n*n矩阵,输出矩阵中任意两点之间所有路径
题目1:给你一个正整数n, 构造一个n*n的四项链表矩阵。
要求: 1.使用四项链表
2.矩阵从左到右,从上到下值依次为1,2,3,4,......n*n
题目2:基于题目1, 在n*n链表矩阵中,输出矩阵中任意两点之间所有路径。
要求: 1.不能使用全局变量
2.方法只接收两个参数,分别为起始节点
3.不能重复遍历
构造一个n*n的四项链表矩阵
思路: 要构建一个n*n的矩阵,有这个一个简单思路:
- 初始化i=0
- 先构建第i行,第i列链表
- 再构建(n-1)*(n-1)矩阵
- 将第二步链表与第三步矩阵连接起来
- i=i+1
- 重复第二步
/**
* @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) + 回溯
- 如果起始节点相等,直接输出,结束
- 起两个栈, 一个主栈,一个副栈
- 主栈:存放线路上的节点,用于符合条件时直接输出
- 副栈:存放主栈节点的邻接节点集合,需考虑边界与重复遍历问题
- 起始节点入主栈,起始节点的邻接节点入副站
- 副栈弹出节点集合
- 弹出集合中第一个节点node(集合长度-1)
- 集合重新入副栈
- 如果node=null, 主栈、副栈执行pop()操作,表示需要回溯到上一步(可以理解为,当前无路可走,需要从上一个节点试图走其他方向), 跳转并重复第4步
- 如果node!=null, 将node节点压入主栈
- 此时如果node==终止节点,则输出主站所有节点,弹出主栈节点(此时==终止节点),跳转并重复第4步
- 将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;
}
}