🎈前言:在学习了前面的Java数组知识以及类和对象后,我们现在就尝试应用前面所学的知识,来实现一种简单的数据结构 ---- 顺序表 (MyArrayList);
快速导航🎀
一 . 线性表介绍
首先我们先来介绍一下线性表 :
线性表(linear list)是n个具有相同特性的数据元素的有限序列。
线性表是一种在实际中广泛使用的数据结构,常见 的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储 时,通常以数组和链式结构的形式存储。
二 . 顺序表
顺序表概念 :
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:
静态顺序表:使用定长数组存储。
动态顺序表:使用动态开辟的数组存储。
静态顺序表适用于确定知道需要存多少数据的场景.
静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用.
相比之下动态顺序表更灵活, 根据需要动态的分配空间大小.
MyArrayList讲解 :
大致思路:我们创建两个类,一个用来测试所写顺序表各个模块功能的类(Test),一个用来实现顺序表的类 (MyArrayList);详情如下 :
三. 顺序表(MyArrayList)各接口讲解
下面我们实现一个动态顺序表,这是需要实现的各个接口:
(相关讲解在代码中以注释形式给出,方便查看与理解)
public class SeqList {
// 打印顺序表
public void display() { }
// 在 pos 位置新增元素
public void add(int pos, int data) { }
// 判定是否包含某个元素
public boolean contains(int toFind) { return true; }
// 查找某个元素对应的位置
public int search(int toFind) { return -1; }
// 获取 pos 位置的元素
public int getPos(int pos) { return -1; }
// 给 pos 位置的元素设为 value
public void setPos(int pos, int value) { }
//删除第一次出现的关键字key
public void remove(int toRemove) { }
// 获取顺序表长度
public int size() { return 0; }
// 清空顺序表
public void clear() { }
}
3.1 打印顺序表
// 打印顺序表
public void display() {
for (int i = 0; i < this.usedSize; i++) { //打印到有有效数据截止,不考虑后面自动初始化的0
System.out.print(this.elem[i]+" ");
}
System.out.println();
}
3.2 获取顺序表的有效数据长度
// 获取顺序表的有效数据长度
public int size() {
return this.usedSize;
}
3.3 在pos位置新增元素
// 在 pos 位置新增元素
public void add(int pos, int data) {
if (pos<0 || pos>usedSize){ //判断pos位置不合法的情况
System.out.println("pos位置不合法!");
return;
}
if (isFull()){ //判断数据是否满了,如果满了进行扩容 ,扩容至原来的两倍
this.elem=Arrays.copyOf(this.elem,2*elem.length);
}
for (int i = usedSize-1; i >=pos ; i--) { //pos位置新增元素操作 往前赋值 腾出空间
this.elem[i+1]=this.elem[i];
}
this.elem[pos]=data;
this.usedSize++;
}
3.4 判断数组是否已满 与 为空
public boolean isFull() {
return usedSize==this.elem.length;
}
public boolean isEmpty(){
return this.usedSize==0;
}
3.5 判断是否包含某个元素
// 判定是否包含某个元素
public boolean contains(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i]==toFind){
return true;
}
}
return false;
}
3.6 查找某个元素对应的位置
// 查找某个元素对应的位置 找不到返回-1 找到返回下标
public int search(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i]==toFind){
return i;
}
}
return -1;
}
3.7 获取pos位置的元素
// 获取 pos 位置的元素
public int getPos(int pos) {
if (pos<0 || pos>=this.usedSize){ //判断pos位置是否合法
System.out.println("pos位置不合法!");
return -1;
}
if (isEmpty()){
System.out.println("顺序表为空!");
}
return this.elem[pos];
}
3.8 给 pos 位置的元素设为 value (更新为value)
// 给 pos 位置的元素设为 value (更新为value)
public void setPos(int pos, int value) {
if (pos<0 || pos >= this.usedSize){ //判断pos位置是否合法
System.out.println("pos位置不合法 !");
return;
}
if(isEmpty()){
System.out.println("顺序表为空!");
}
this.elem[pos]=value;
}
3.9 删除第一次出现的关键字key
//删除第一次出现的关键字key
public void remove(int toRemove) {
if (isEmpty()){
System.out.println("顺序表为空!");
}
int index=search(toRemove);
if (index==-1){
System.out.println("没有你要删除的元素 !");
}
for (int i = index; i < this.usedSize-1; i++) {
//删除操作为 将pos位置前面的那个元素赋值给pos,依次向前赋值,实现删除,
//最后余下的那个元素如果是数字不动不影响,因为下次操作会覆盖,如果是引用类型防止内存浪费制成null
this.elem[i]=this.elem[i+1];
}
this.usedSize--;
//如果是引用数据类型,还要操作usedSize位置
//this.elem[usedSize]=null;
}
3.10 清空顺序表
// 清空顺序表
public void clear() {
this.usedSize=0; //直接将有效数据个数制成0
/* for (int i = 0; i < usedSize; i++) {
this.elem[i]=null;
}
数据类型为引用时候这样操作
this.usedSize=0;*/
}
}
四.整体顺序表 MyArrayList 以及测试(部分) Test 代码展示
4.1 MyArrayList
import java.util.Arrays;
/**
* 顺序表
*/
public class MyArrayList {
public int[] elem; //定义一个数组
public int usedSize; //数组中的元素个数
public MyArrayList() {
this.elem = new int[10]; //构造函数,先初始化数组10个int空间的大小
}
// 打印顺序表
public void display() {
for (int i = 0; i < this.usedSize; i++) { //打印到有有效数据截止,不考虑后面自动初始化的0
System.out.print(this.elem[i]+" ");
}
System.out.println();
}
// 获取顺序表的有效数据长度
public int size() {
return this.usedSize;
}
// 在 pos 位置新增元素
public void add(int pos, int data) {
if (pos<0 || pos>usedSize){ //判断pos位置不合法的情况
System.out.println("pos位置不合法!");
return;
}
if (isFull()){ //判断数据是否满了,如果满了进行扩容 ,扩容至原来的两倍
this.elem=Arrays.copyOf(this.elem,2*elem.length);
}
for (int i = usedSize-1; i >=pos ; i--) { //pos位置新增元素操作
this.elem[i+1]=this.elem[i];
}
this.elem[pos]=data;
this.usedSize++;
}
public boolean isFull() {
return usedSize==this.elem.length;
}
// 判定是否包含某个元素
public boolean contains(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i]==toFind){
return true;
}
}
return false;
}
// 查找某个元素对应的位置 找不到返回-1
public int search(int toFind) {
for (int i = 0; i < this.usedSize; i++) {
if (this.elem[i]==toFind){
return i;
}
}
return -1;
}
// 获取 pos 位置的元素
public int getPos(int pos) {
if (pos<0 || pos>=this.usedSize){
System.out.println("pos位置不合法!");
return -1;
}
if (isEmpty()){
System.out.println("顺序表为空!");
}
return this.elem[pos];
}
public boolean isEmpty(){
return this.usedSize==0;
}
// 给 pos 位置的元素设为 value (更新为value)
public void setPos(int pos, int value) {
if (pos<0 || pos >= this.usedSize){
System.out.println("pos位置不合法 !");
return;
}
if(isEmpty()){
System.out.println("顺序表为空!");
}
this.elem[pos]=value;
}
//删除第一次出现的关键字key
public void remove(int toRemove) {
if (isEmpty()){
System.out.println("顺序表为空!");
}
int index=search(toRemove);
if (index==-1){
System.out.println("没有你要删除的元素 !");
}
for (int i = index; i < this.usedSize-1; i++) {
this.elem[i]=this.elem[i+1];
}
this.usedSize--;
//如果是引用数据类型,还有操作usedSize位置
//this.elem[usedSize]=null;
}
// 清空顺序表
public void clear() {
this.usedSize=0;
/* for (int i = 0; i < usedSize; i++) {
this.elem[i]=null;
}
数据类型为引用时候这样操作
this.usedSize=0;*/
}
}
4.2 Test
public class Test {
public static void main(String[] args) {
MyArrayList myArrayList=new MyArrayList();
myArrayList.add(0,1);
myArrayList.add(1,2);
myArrayList.add(2,3);
myArrayList.add(3,4);
myArrayList.display();
myArrayList.setPos(2,99);
myArrayList.display();
myArrayList.remove(99);
myArrayList.display();
System.out.println("------------------");
myArrayList.clear();
}
}
五. 顺序表思考 (引入链表)
就顺序表而言,(顺序表 : 物理上 和 逻辑上都是连续的)
1.我们在进行插入和删除元素的时候,必须得移动元素,时间复杂度就大大增大 即为 O(N)
2.扩容方面也存在不足
增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
如何解决这些不足呢 ? 答案就是应用 链表
链表可以实现插入和删除元素不去移动元素,不去考虑查找元素的问题,时间复杂度做到O(1)
且数据做到随用随取,放1个数据给1个数据空间,避免浪费;弥补了顺序表的缺点
为了能够弥补顺序表的缺点,就需要应用链表。
下篇博文博主就来讲解链表 。
✨ 如果觉得这篇文章对自己有所帮助,欢迎大家多多点赞收藏 ,重复学习 ~