java-数据结构与算法-02-数据结构-05-栈

文章目录

    • 1. 栈
      • 1. 概述
      • 2. 链表实现
      • 3. 数组实现
      • 4. 应用
    • 2. 习题
      • E01. 有效的括号-Leetcode 20
      • E02. 后缀表达式求值-Leetcode 120
      • E03. 中缀表达式转后缀
      • E04. 双栈模拟队列-Leetcode 232
      • E05. 单队列模拟栈-Leetcode 225

1. 栈

1. 概述

计算机科学中,stack 是一种线性的数据结构,只能在其一端添加数据和移除数据。习惯来说,这一端称之为栈顶,另一端不能操作数据的称之为栈底,就如同生活中的一摞书

栈是一种特殊的线性表,只能在一端进行操作

  • 往栈中添加元素的操作,一般叫做 push,入栈
  • 从栈中移除元素的操作,一般叫做 pop,出栈(只能移除栈顶元素,也叫做:弹出栈顶元素)
  • 后进先出的原则,Last In First Out,LIFO
    在这里插入图片描述

先提供一个栈接口

public interface Stack<E> {/*** 向栈顶压入元素* @param value 待压入值* @return 压入成功返回 true, 否则返回 false*/boolean push(E value);/*** 从栈顶弹出元素* @return 栈非空返回栈顶元素, 栈为空返回 null*/E pop();/*** 返回栈顶元素, 不弹出* @return 栈非空返回栈顶元素, 栈为空返回 null*/E peek();/*** 判断栈是否为空* @return 空返回 true, 否则返回 false*/boolean isEmpty();/*** 判断栈是否已满* @return 满返回 true, 否则返回 false*/boolean isFull();
}

栈的应用
浏览器的前进和后退

在这里插入图片描述

2. 链表实现

package com.itheima.datastructure.stack;import java.util.Iterator;
import java.util.StringJoiner;/*** 链表实现的栈。* 该类实现了Stack接口和Iterable接口,允许对栈中的元素进行迭代。** @param <E> 栈中元素的类型。*/
public class LinkedListStack<E> implements Stack<E>, Iterable<E> {/*** 栈的容量,默认为Integer.MAX_VALUE,表示不限制容量。*/private int capacity = Integer.MAX_VALUE;/*** 栈中元素的数量。*/private int size;/*** 链表的头节点,用于简化插入和删除操作。*/private final Node<E> head = new Node<>(null, null);/*** 默认构造函数。*/public LinkedListStack() {}/*** 带容量限制的构造函数。** @param capacity 栈的容量限制。*/public LinkedListStack(int capacity) {this.capacity = capacity;}/*** 将元素压入栈顶。** @param value 要压入栈的元素。* @return 如果栈未满,则返回true;否则返回false。*//*head -> 2 -> 1 -> null*/@Overridepublic boolean push(E value) {if (isFull()) {return false;}head.next = new Node<>(value, head.next);size++;return true;}/*** 从栈顶弹出一个元素。** @return 如果栈不为空,则返回栈顶元素;否则返回null。*//*head -> 2 -> 1 -> null*/@Overridepublic E pop() {if (isEmpty()) {return null;}Node<E> first = head.next;head.next = first.next;size--;return first.value;}/*** 查看栈顶元素。** @return 如果栈不为空,则返回栈顶元素;否则返回null。*/@Overridepublic E peek() {if (isEmpty()) {return null;}return head.next.value;}/*** 检查栈是否为空。** @return 如果栈为空,则返回true;否则返回false。*/@Overridepublic boolean isEmpty() {return size == 0;}/*** 检查栈是否已满。** @return 如果栈已满,则返回true;否则返回false。*/@Overridepublic boolean isFull() {return size == capacity;}/*** 创建一个迭代器,用于遍历栈中的元素。** @return栈的元素迭代器。*/@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {Node<E> p = head.next;@Overridepublic boolean hasNext() {return p != null;}@Overridepublic E next() {E value = p.value;p = p.next;return value;}};}/*** 链表节点类,用于存储栈中的元素。** @param <E> 节点中存储的元素类型。*/static class Node<E> {E value;Node<E> next;public Node(E value, Node<E> next) {this.value = value;this.next = next;}}/*** 将栈中的元素转换为字符串表示。** @return 栈的字符串表示,元素之间用逗号分隔。*/@Overridepublic String toString() {StringJoiner sj = new StringJoiner(",");for (E e : this) {sj.add(e.toString());}return sj.toString();}
}

3. 数组实现

/*** 数组实现的栈类,支持泛型元素。* @param <E> 栈中元素的类型。*/
package com.itheima.datastructure.stack;import java.util.Iterator;public class ArrayStack<E> implements Stack<E>, Iterable<E> {/*** 存储栈元素的数组。*/private final E[] array;/*** 栈顶指针,指示当前栈的顶部元素的位置。*/private int top; // 栈顶指针/*** 构造一个指定容量的栈。* @param capacity 栈的初始容量。*/@SuppressWarnings("all")public ArrayStack(int capacity) {this.array = (E[]) new Object[capacity];}/*** 将元素压入栈顶。* @param value 要压入栈的元素。* @return 如果栈未满,则返回true;否则返回false。*/@Overridepublic boolean push(E value) {if (isFull()) {return false;}array[top++] = value;return true;}/*** 弹出栈顶元素。* @return 栈顶元素,如果栈为空,则返回null。*/@Overridepublic E pop() {if (isEmpty()) {return null;}E e = array[--top];array[top] = null; // help GCreturn e;}/*** 查看栈顶元素。* @return 栈顶元素,如果栈为空,则返回null。*/@Overridepublic E peek() {if (isEmpty()) {return null;}return array[top - 1];}/*** 检查栈是否为空。* @return 如果栈为空,则返回true;否则返回false。*/@Overridepublic boolean isEmpty() {return top == 0;}/*** 检查栈是否已满。* @return 如果栈已满,则返回true;否则返回false。*/@Overridepublic boolean isFull() {return top == array.length;}/*** 返回栈元素的迭代器,用于遍历栈。* @return栈元素的迭代器。*//*底          顶0   1   2   3a   b   c   dp*/@Overridepublic Iterator<E> iterator() {return new Iterator<E>() {int p = top;@Overridepublic boolean hasNext() {return p > 0;}@Overridepublic E next() {return array[--p];}};}
}

4. 应用

模拟如下方法调用

public static void main(String[] args) {System.out.println("main1");System.out.println("main2");method1();method2();System.out.println("main3");
}public static void method1() {System.out.println("method1");method3();
}public static void method2() {System.out.println("method2");
}public static void method3() {System.out.println("method3");
}

模拟代码

package com.itheima.datastructure.stack;/*** CPU模拟类,使用栈来模拟方法的调用与返回。*/
public class CPU {/*** 方法帧类,用于存储方法的退出点。*/static class Frame {int exit;/*** 构造方法,初始化方法帧的退出点。* * @param exit 方法的退出点值。*/public Frame(int exit) {this.exit = exit;}}/*** 程序计数器,用于指示当前执行的指令位置。*/static int pc = 1;/*** 方法调用栈,用于模拟方法的调用与返回过程。*/static ArrayStack<Frame> stack = new ArrayStack<>(100);/*** 程序入口点。* * @param args 命令行参数。*/public static void main(String[] args) {// 初始化方法调用栈,压入一个表示main方法开始的帧stack.push(new Frame(-1));// 当栈不为空时,循环执行指令while (!stack.isEmpty()) {// 根据程序计数器的值执行相应的操作switch (pc) {case 1:// 执行main方法的第一段代码System.out.println("main1");pc++;break;case 2:// 执行main方法的第二段代码System.out.println("main2");pc++;break;case 3:// 调用method1方法stack.push(new Frame(pc + 1));pc = 100;break;case 4:// 调用method2方法stack.push(new Frame(pc + 1));pc = 200;break;case 5:// 方法返回,从栈中弹出方法帧,并跳转到退出点System.out.println("main3");pc = stack.pop().exit;break;case 100:// method1方法的代码段System.out.println("method1");stack.push(new Frame(pc + 1));pc = 300;break;case 101:// method1方法返回pc = stack.pop().exit;break;case 200:// method2方法的代码段System.out.println("method2");pc = stack.pop().exit;break;case 300:// method3方法的代码段System.out.println("method3");pc = stack.pop().exit;break;}}}
}

2. 习题

E01. 有效的括号-Leetcode 20

一个字符串中可能出现 [] () 和 {} 三种括号,判断该括号是否有效
有效的例子

()[]{}([{}])()

无效的例子

[)([)]([]

思路

  • 遇到左括号, 把要配对的右括号放入栈顶
  • 遇到右括号, 若此时栈为空, 返回 false,否则把它与栈顶元素对比
    • 若相等, 栈顶元素弹出, 继续对比下一组
    • 若不等, 无效括号直接返回 false
  • 循环结束
    • 若栈为空, 表示所有括号都配上对, 返回 true
    • 若栈不为空, 表示右没配对的括号, 应返回 false

答案(用到了课堂案例中的 ArrayStack 类)

public boolean isValid(String s) {ArrayStack<Character> stack = new ArrayStack<>(s.length() / 2 + 1);for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (c == '(') {stack.push(')');} else if (c == '[') {stack.push(']');} else if (c == '{') {stack.push('}');} else {if (!stack.isEmpty() && stack.peek() == c) {stack.pop();} else {return false;}}}return stack.isEmpty();
}

E02. 后缀表达式求值-Leetcode 120

后缀表达式也称为逆波兰表达式,即运算符写在后面

  • 从左向右进行计算
  • 不必考虑运算符优先级,即不用包含括号

示例

输入:tokens = ["2","1","+","3","*"]
输出:9
即:(2 + 1) * 3输入:tokens = ["4","13","5","/","+"]
输出:6
即:4 + (13 / 5)

题目假设

  • 数字都视为整数
  • 数字和运算符个数给定正确,不会有除零发生

代码

public int evalRPN(String[] tokens) {LinkedList<Integer> numbers = new LinkedList<>();for (String t : tokens) {switch (t) {case "+" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a + b);}case "-" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a - b);}case "*" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a * b);}case "/" -> {Integer b = numbers.pop();Integer a = numbers.pop();numbers.push(a / b);}default -> numbers.push(Integer.parseInt(t));}}return numbers.pop();
}

E03. 中缀表达式转后缀

public class E03InfixToSuffix {/*思路1. 遇到数字, 拼串2. 遇到 + - * /- 优先级高于栈顶运算符 入栈- 否则将栈中高级或平级运算符出栈拼串, 本运算符入栈3. 遍历完成, 栈中剩余运算符出栈拼串- 先出栈,意味着优先运算4. 带 ()- 左括号直接入栈- 右括号要将栈中直至左括号为止的运算符出栈拼串|   ||   ||   |_____a+ba+b-ca+b*ca*b+c(a+b)*c*/public static void main(String[] args) {System.out.println(infixToSuffix("a+b"));System.out.println(infixToSuffix("a+b-c"));System.out.println(infixToSuffix("a+b*c"));System.out.println(infixToSuffix("a*b-c"));System.out.println(infixToSuffix("(a+b)*c"));System.out.println(infixToSuffix("a+b*c+(d*e+f)*g"));}/*** 将中缀表达式转换为后缀表达式。* 后缀表达式也称为逆波兰表达式,它使用栈的操作来实现运算符的优先级处理,有效地简化了计算过程。* * @param exp 中缀表达式字符串,包含数字、运算符和括号。* @return 后缀表达式字符串。*/static String infixToSuffix(String exp) {// 使用链表作为栈来存储运算符LinkedList<Character> stack = new LinkedList<>();// 使用StringBuilder来构建后缀表达式StringBuilder sb = new StringBuilder(exp.length());// 遍历中缀表达式的每个字符for (int i = 0; i < exp.length(); i++) {char c = exp.charAt(i);// 根据字符的不同类型进行处理switch (c) {case '*', '/', '+', '-' -> {// 处理运算符if (stack.isEmpty()) {stack.push(c);} else {if (priority(c) > priority(stack.peek())) {stack.push(c);} else {// 当当前运算符的优先级不高于栈顶运算符时,将栈顶运算符弹出到后缀表达式中while (!stack.isEmpty() && priority(stack.peek()) >= priority(c)) {sb.append(stack.pop());}stack.push(c);}}}case '(' -> {// 遇到左括号直接入栈stack.push(c);}case ')' -> {// 遇到右括号,将栈中的运算符依次弹出到后缀表达式中,直到遇到左括号while (!stack.isEmpty() && stack.peek() != '(') {sb.append(stack.pop());}// 弹出左括号,不加入到后缀表达式中stack.pop();}default -> {// 遇到数字直接加入到后缀表达式中sb.append(c);}}}// 将栈中剩余的运算符依次弹出到后缀表达式中while (!stack.isEmpty()) {sb.append(stack.pop());}// 返回构建好的后缀表达式return sb.toString();}/*** 计算运算符的优先级。* * @param c 运算符* @return 运算符的优先级* @throws IllegalArgumentException 如果运算符不合法,则抛出此异常*/
static int priority(char c) {// 使用switch表达式来根据运算符的类型返回对应的优先级return switch (c) {case '*' -> 2; // 乘法和除法具有相同的优先级case '/' -> 2;case '+' -> 1; // 加法和减法具有相同的优先级case '-' -> 1;case '(' -> 0; // 左括号具有最低优先级default -> throw new IllegalArgumentException("不合法的运算符:" + c);};
}}

返回结果

ab+c*
abc*+d-e*
abc+*

E04. 双栈模拟队列-Leetcode 232

给力扣题目用的自实现栈,可以定义为静态内部类

class ArrayStack<E> {private E[] array;private int top; // 栈顶指针@SuppressWarnings("all")public ArrayStack(int capacity) {this.array = (E[]) new Object[capacity];}public boolean push(E value) {if (isFull()) {return false;}array[top++] = value;return true;}public E pop() {if (isEmpty()) {return null;}return array[--top];}public E peek() {if (isEmpty()) {return null;}return array[top - 1];}public boolean isEmpty() {return top == 0;}public boolean isFull() {return top == array.length;}
}

参考解答,注意:题目已说明

  • 调用 push、pop 等方法的次数最多 100
package com.itheima.datastructure.stack;/*** 双栈模拟队列** <ul>*     <li>调用 push、pop 等方法的次数最多 100</li>* </ul>*/
public class E04Leetcode232 {/*队列头        队列尾b顶   底     底   顶s1              s2队列尾添加s2.push(a)s2.push(b)队列头移除先把 s2 的所有元素移动到 s1s1.pop()*/ArrayStack<Integer> s1 = new ArrayStack<>(100);ArrayStack<Integer> s2 = new ArrayStack<>(100);public void push(int x) { //向队列尾添加s2.push(x);}public int pop() { // 从对列头移除if (s1.isEmpty()) {while (!s2.isEmpty()) {s1.push(s2.pop());}}return s1.pop();}public int peek() { // 从对列头获取if (s1.isEmpty()) {while (!s2.isEmpty()) {s1.push(s2.pop());}}return s1.peek();}public boolean empty() {return s1.isEmpty() && s2.isEmpty();}}

E05. 单队列模拟栈-Leetcode 225

给力扣题目用的自实现队列,可以定义为静态内部类

public class ArrayQueue3<E> {private final E[] array;int head = 0;int tail = 0;@SuppressWarnings("all")public ArrayQueue3(int c) {c -= 1;c |= c >> 1;c |= c >> 2;c |= c >> 4;c |= c >> 8;c |= c >> 16;c += 1;array = (E[]) new Object[c];}public boolean offer(E value) {if (isFull()) {return false;}        array[tail & (array.length - 1)] = value;tail++;return true;}public E poll() {if (isEmpty()) {return null;}E value = array[head & (array.length - 1)];head++;return value;}public E peek() {if (isEmpty()) {return null;}return array[head & (array.length - 1)];}public boolean isEmpty() {return head == tail;}public boolean isFull() {return tail - head == array.length;}
}

参考解答,注意:题目已说明

  • 调用 push、pop 等方法的次数最多 100
  • 每次调用 pop 和 top 都能保证栈不为空
public class E05Leetcode225 {/*队列头     队列尾cba顶           底queue.offer(a)queue.offer(b)queue.offer(c)*/ArrayQueue3<Integer> queue = new ArrayQueue3<>(100);int size = 0;public void push(int x) {queue.offer(x);for (int i = 0; i < size; i++) {queue.offer(queue.poll());}size++;}public int pop() {size--;return queue.poll();}public int top() {return queue.peek();}public boolean empty() {return queue.isEmpty();}
}

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

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

相关文章

netty入门-3 EventLoop和EventLoopGroup,简单的服务器实现

文章目录 EventLoop和EventLoopGroup服务器与客户端基本使用增加非NIO工人NioEventLoop 处理普通任务与定时任务 结语 EventLoop和EventLoopGroup 二者大概是什么这里不再赘述&#xff0c;前一篇已简述过。 不理解也没关系。 下面会简单使用&#xff0c;看了就能明白是什么 这…

第124天:内网安全-代理 Sockets协议路由不出网后渗透通讯CS-MSF 控制上线

目录 思维导图 环境配置 案例一&#xff1a;网络通讯&控制上线--CS-路由添加&节点建立&协议生成&正反连接 案例二&#xff1a;网络通讯&控制上线--MSF-路由添加&节点建立&协议生成&正反连接 思维导图 环境配置 这里由于系统内存问题我只设…

Python的人脸识别程序

1.录入人脸&#xff0c;输入ID号 haarcascade_frontalface_default.xml # 导入模块 import os import numpy as np import cv2 as cv import cv2face_detector cv2.CascadeClassifier(rD:\Automation_All_Files\OCR\haarcascade_frontalface_default.xml) # 待更改# 为即将…

Windows10+vs 2017中创建WEB API教程

我们如果需要用到web api怎么办&#xff1f;一般来说可以自己开发和去使用别人开发好的api&#xff0c;今天我们来讲一下Windows10vs 2017中创建web Api的教程。目前本教程当中的方法在Win10 VS2017&#xff08;MVC5&#xff09;win server2016vs2017&#xff0c;vs2013 vs201…

网安人必须人手一份的《Linux私房教程》,GitHub星标286K!

Linux是一套免费使用和自由传播的操作系统内核&#xff0c;是一个基于POSIX和Unix的多用户、多任务支持多线程和多CPU的操作系统内核。它能运行主要的Unix工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想&#xff0c;是一个性能稳…

【iOS】GCD

参考文章&#xff1a;GCD函数和队列原理探索 之前写项目的时候&#xff0c;进行耗时的网络请求使用GCD处理过异步请求&#xff0c;但对一些概念都很模糊&#xff0c;这次就来系统学习一下GCD相关 相关概念 什么是GCD&#xff1f; Grand Center Dispatch简称GCD&#xff0c;是…

ChatTTS真人文本转语音模型,富有韵律与情感,且免费开源

上期图文教程&#xff0c;我们分享了微软TTS真人转语音大模型&#xff0c;但是微软的TTS模型只有针对新用户免费一年&#xff0c;其他用户都是收费的&#xff0c;虽然微软开源了部分TTS的功能&#xff0c;但是针对真人类似的富有情感的TTS模型并没有进行开源&#xff0c;本期介…

软件测试基础1--功能测试

1、什么是软件测试&#xff1f; 软件是控制计算机硬件运行的工具。 软件测试&#xff1a;使用技术手段验证软件是否满足使用需求&#xff0c;为了发现软件功能和需求不相符合的地方&#xff0c;或者寻找实际输出和预期输出之间的差异。 软件测试的目的&#xff1a;减少软件缺陷…

学习笔记之JAVA篇(0724)

p 方法 方法声明格式&#xff1a; [修饰符1 修饰符2 ...] 返回值类型 方法名&#xff08;形式参数列表&#xff09;{ java语句;......; } 方法调用方式 普通方法对象.方法名&#xff08;实参列表&#xff09;静态方法类名.方法名&#xff08;实参列表&#xff09; 方法的详…

【YashanDB知识库】YashanDB的JDBC/OCI驱动如何设置字符编码

问题现象 Oracle、Mysql数据库链接串&#xff0c;JDBC驱动连接串可以指定客户端的编码格式&#xff1a; jdbc:mysql://hostname:port/database_name?useUnicodetrue&characterEncodingutf8mb4 jdbc:oracle:thin://hostname:port/service_name?NLS_LANGUAGEAMERICAN&am…

【SQL语句大全(MySQL)】

SQL语法 添加删除修改查询基本查询条件查询分组函数/聚合函数分组查询排序分页查询&#xff08;限制查询&#xff09;多表查询连接查询根据年代分类连接查询根据连接方式分类1、内连接2、左外连接3、右外连接 多张表连接的语法格式 嵌套查询 SQL语句书写顺序 添加 INSERT INTO…

构建生成工具cmake的使用(1)

ps:本文是对cmake的基础讲解&#xff0c;掌握后解决70-80%情况是足以应对的&#xff0c;后续会对cmake有进阶内容。 一 前言 CMake 是一个工具&#xff0c;帮助开发者管理和自动化软件项目的构建过程。它使用一个叫做CMakeLists.txt 的文本文件来描述项目的组织结构、编译选项…

oracle数据库下的定时任务,如何创建Jobs

oarcle中写存储过程&#xff0c;上面的文章中已经介绍过了&#xff0c;这次是写好存储过程后&#xff0c;在Jobs文件夹中新建job,达到定时执行任务的目的。 1、在plsql数据库中&#xff0c;找到左边的Jobs,右键点击新建&#xff0c;如下图&#xff1a; 2、按照下图将相应的项添…

【Gitlab】SSH配置和克隆仓库

生成SSH Key ssh-keygen -t rsa -b 4096 私钥文件: id_rsa 公钥文件:id_rsa.pub 复制生成的ssh公钥到此处 克隆仓库 git clone repo-address 需要进行推送和同步来更新本地和服务器的文件 推送更新内容 git push <remote><branch> 拉取更新内容 git pull &…

LINUX高性能服务器框架

1.服务器模型&#xff1a; 1). C/S模型 &#xff1a; 此模型就是一个服务器能给多个客户端提供服务&#xff0c;但所以资源都被服务端所占有&#xff0c;客户端想要获取只能通过请求连接服务端去获取。由于客户端的请求访问是异步的&#xff0c;所以需要一个手段进行此类事件的…

基于微信小程序的课堂考勤系统的设计与实现(论文+源码)_kaic

基于微信小程序的课堂考勤系统的设计与实现 摘 要 在高校教育普及的今天&#xff0c;学生人数日益增多&#xff0c;为保证课堂质量&#xff0c;教师多要在课前进行考勤。因此本设计提出基于微信小程序的课堂考勤系统&#xff0c;增加了定位功能&#xff0c;避免了“假打卡”…

前端开发知识(一)-html

1.前端开发需掌握的内容&#xff1a; 2.前端开发的三剑客&#xff1a;html、css、javascript Vue可以简化JavaScpript流程。 Element&#xff08;饿了么开发的&#xff09; &#xff1a;前端组件库。 Ngix&#xff1a;前端服务器。 3.前端开发工具&#xff1a;vscode 1)按…

基于Java+SpringBoot+Vue的学生心理咨询评估系统

前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 哈喽兄弟们&#xff0c;好久不见哦&#xff5…

乐尚代驾六订单执行一

加载当前订单 需求 无论是司机端&#xff0c;还是乘客端&#xff0c;遇到页面切换&#xff0c;重新登录小程序等&#xff0c;只要回到首页面&#xff0c;查看当前是否有正在执行订单&#xff0c;如果有跳转到当前订单执行页面 之前这个接口已经开发&#xff0c;为了测试&…

Linux嵌入式学习——数据结构——线性表的链式结构

线性表的链式存储 解决顺序存储的缺点&#xff0c;插入和删除&#xff0c;动态存储问题。 特点&#xff1a; 线性表链式存储结构的特点是一组任意的存储单位存储线性表的数据元素&#xff0c;存储单元可以是连续的&#xff0c;也可以不连续。可以被存储在任意内存未被占…