顺序表
1. 顺序表概念
什么是顺序表 ?
顺序表是一种新的数据类型,它使用一段物理地址连续的存储单元依次存储数据元素(数组实现),并具有操作(增删查改)这个数组的方法
数组也是使用连续的地址空间存储数据,那么数组和顺序表有什么区别 ?
数组是一个连续地址依次存储数据的简单结构, 而顺序表只是使用数组这个结构存储数据 顺序表本身还具备操作这个数组的功能
2. 顺序表结构及实现
elem数组引用 指向存储数据的内存空间
size 记录当前顺序表中数据的个数 同时作为下一个元素的下标
顺序表的实现:
https://github.com/znxcmakhsd/DS/tree/main/12-12/ArrayList
3. 认识ArrayList
3.1 三种构造方法
ArrayList是Java提供的一个泛型类,它和我们自己实现的顺序表在基本逻辑上没有区别
使用ArrayList实例化顺序表对象:
public class Main { public static void main(String[] args) { ArrayList<Integer> arrayList1 = new ArrayList<>(); List<Integer> arrayList2 = new ArrayList<>(); } }
由于ArrayList实现了List接口,所以也可以使用List引用引用顺序表对象
ArrayList中的三种构造方法:
有参数的构造
无参构造
如图 使用无参构造构造对象时 不会给数组分配大小
那么 为什么可以插入数据 ?
这里就得看add方法的实现
第三个构造方法:
3.2 ArrayList的6种遍历
import jdk.internal.org.objectweb.asm.tree.LineNumberNode; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; public class Main { public static void main(String[] args) { ArrayList<Integer> arrayList1 = new ArrayList<>(); arrayList1.add(1); arrayList1.add(2); arrayList1.add(3); // 第一种遍历: System.out.println(arrayList1); // 第二种遍历: for for (int i = 0;i < arrayList1.size();i++) { System.out.print(arrayList1.get(i) + " "); } System.out.println(); // 第三种遍历: for-each for (Integer x:arrayList1) { System.out.print(x+" "); } System.out.println(); // 第4种遍历: 迭代器 Iterator Iterator<Integer> it = arrayList1.iterator(); while (it.hasNext()) { System.out.print(it.next()+" "); } System.out.println(); // 第5种遍历: 迭代器 ListIterator ListIterator<Integer> it2 = arrayList1.listIterator(); while (it2.hasNext()) { System.out.print(it2.next()+" "); } System.out.println(); // 第6种遍历: 迭代器 ListIterator 从后->前 ListIterator<Integer> it3 = arrayList1.listIterator(arrayList1.size()); while (it3.hasPrevious()) { System.out.print(it3.previous()+" "); } System.out.println(); } }
3.3 ArrayList的应用
1. 一道cvte面试题:
str1: "welcome to cvte"
str2: "come"
删除str1中 所有出现在str2中的字符 要求使用ArrayList——》结果: w, l, , t, , v, t
方法1:
思路: 将str1中的每个字符遍历 判断该字符有没有在str2中,如果没有放入arrayList
public static List<Character> func1(String str1,String str2) { ArrayList<Character> arrayList = new ArrayList<>(); for (int i = 0;i < str1.length();i++) { char ch = str1.charAt(i); if (!str2.contains(ch+"")) { arrayList.add(ch); } } return arrayList; }
这里需要注意: contains方法判断一个字符串是否有另一个字符串,字符ch需要加""转为字符串
方法2:
思路和方法1一样 只是没有使用contains方法
public static List<Character> func2(String str1,String str2) { ArrayList<Character> arrayList = new ArrayList<>(); for (int i = 0;i < str1.length();i++) { char ch = str1.charAt(i); int j = 0; for (;j < str2.length();j++) { if (str2.charAt(j) == ch) { break; } } if (j == str2.length()) { arrayList.add(ch); } } return arrayList; }
2. 杨辉三角
题目链接:
https://leetcode.cn/problems/pascals-triangle/description/
先说明下 返回值的含义
在这道题中 List引用的是ArrayList对象, 所以List<List<Interger>>表示顺序表中每个元素类型是存储整形的顺序表对象 类似于二维数组, 如下图
解题思路:
class Solution { public List<List<Integer>> generate(int numRows) { List<List<Integer>> retArray = new ArrayList<>(); // 提前插入第一行 List<Integer> firstRow = new ArrayList<>(); firstRow.add(1); retArray.add(firstRow); for (int i = 1;i < numRows;i++) { List<Integer> array = new ArrayList<>(); // 处理头 array.add(1); // 处理中间 for (int j = 1;j < i;j++) { List<Integer> lastRow = retArray.get(i-1);// 得到上一行 array.add(lastRow.get(j-1)+lastRow.get(j)); } // 处理尾 array.add(1); retArray.add(i,array); } return retArray; } }
4. 顺序表的优缺点
缺点:
1. 插入删除元素 需要移动元素,即执行一次插入删除操作 最坏需要移动n-1次 --->复杂度为O(N) 不够好
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的时间消耗
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
优点:
给定一个下标,可以以O(1)复杂度快速找到对应元素
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现