文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java数据结构顺序表从零基础到精通进阶

2024-04-02 19:55

关注

一、什么是线性表

线性表是最基本、最简单、也是最常用的一种数据结构。线性表*(linear list)*是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。常见的线性表有顺序表,链表,栈,队列,字符串等

注意:这里说的线性表都指的是逻辑结构,也就是他们的逻辑结构是线性的,但物理结构却不一定是线性的。

在数据结构逻辑层次上细分,线性表可分为一般线性表和受限线性表。一般线性表也就是我们通常所说的“线性表”,可以自由的删除或添加结点。受限线性表主要包括栈和队列,受限表示对结点的操作受限制

二、顺序表

顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中

顺序表可以分为以下两类:

静态顺序表比较死板,如果数组长度太小,担心后面数据存不下,太大,又会有空间浪费.

所以我们一般都用动态增长的顺序表,按需所取.

三、手撕顺序表

在学习数据结构的过程中,我们不仅要学会如何用数据结构,懂得它的理论部分,更要亲自动手去实践,将数据结构实现一遍,这样的话理解会更深刻

顺序表中我们如果只是单纯拿一个数组去用的话就会出现:顺序表中到底有多少有效数据,满了还是没满等问题,所以我们在实现顺序表的时候都还会再加一个size(有效数据个数)属性(顺序表的容量可以通过data.length获得)

属性定义


public class MyArrayList {
    public int[] data;    // 存储数据
    public int size;    // 有效数据个数
}

构造方法


public MyArrayList() {
    this.data = new int[10];   // 后面不够再增容
    this.size = 0;    // 初始无有效数据,size 为0
}

接口实现

对于顺序表我们一般都会有以下接口需要去实现:


// 打印顺序表
public void display();
// 在 pos 位置增加元素
public void add(int pos, int num);
// 判断顺序表中是否包含某个元素
public boolean contains(int num);
// 查找某个元素所在位置
public int search(int key);
// 获取 pos 位置的元素
public int getPos(int pos);
// 将 pos 位置的元素值设为 value
public void setPos(int pos, int value);
//删除第一次出现的关键字key
public void remove(int key);
// 获取顺序表长度
public int size();
// 清空顺序表
public void clear();

在实现这些接口的过程中,凡是涉及到数组下标的,我们都要进行下标合法性的检验,并且要注意用size,还是data.length

确保顺序表空间

在对顺序表增加元素的时候,我们一定要确保顺序表有足够的空间去增加元素,否则就会导致数组下标越界等情况发生


private void ensureCapacity() {
    if (this.size == this.data.length) {
        // 说明满了,该扩容了
        this.data = Arrays.copyOf(this.data, 2 * this.data.length);
    }
}

增加元素

往顺序表中增加元素的时候要注意可以在size位置去加元素(相当于尾插),同时也要确保顺序表有空间足够插入,在移动元素的时候要注意边界情况(下标越界,移动元素过多等),也别忘了size++


public void add(int pos, int num) {
    if (pos < 0 || pos > this.size) {    // 检验下表合法性
        throw new RuntimeException("ArrayIndexOutOfBoundsException : " + pos);
    }
    ensureCapacity();
    for (int i = this.size; i > pos; i--) {
        this.data[i] = this.data[i - 1];
    }
    this.data[pos] = num;
    this.size++;
}

打印顺序表

注意这里只打印有效数据


public String printMyArrayList() {
    String str = "[";
    for (int i = 0; i < this.size - 1; i++) {   // for循环中的右边界应该用size而不用data.length
        str += this.data[i] + ", ";
    }
    str += this.data[this.size - 1];
    str += "]";
    return str;
}

测试

对前面写的三个接口做测试


public class UseArrayList {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(0, 0);
        myArrayList.add(1, 1);
        myArrayList.add(2, 2);
        myArrayList.add(3, 3);
        myArrayList.add(4, 2);
        myArrayList.add(0, 100);   // 头插
        myArrayList.add(2, 666);   // 中间插
        System.out.println(myArrayList.printMyArrayList());
    }
}

运行结果:

判断顺序表中是否包含某个元素


public boolean contains(int num) {
    for (int i = 0; i < this.size; i++) {
        if (this.data[i] == num) {
            return true;
        }
    }
    return false;
}

测试:


public class UseArrayList {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(0, 0);
        myArrayList.add(1, 1);
        myArrayList.add(2, 2);
        myArrayList.add(3, 3);
        System.out.println(myArrayList.contains(3));
        System.out.println(myArrayList.contains(2));
        System.out.println(myArrayList.contains(0));
        System.out.println(myArrayList.contains(666));
    }
}

运行结果:

查找元素

查找顺序表中某个元素的位置(返回下标)


public int search(int key) {
    for (int i = 0; i < this.size; i++) {
        if (this.data[i] == key) {
            return i;
        }
    }
    return -1;    // 不存在这个元素,返回-1
}

测试:


public class UseArrayList {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(0, 0);
        myArrayList.add(1, 1);
        myArrayList.add(2, 2);
        myArrayList.add(3, 3);
        System.out.println(myArrayList.search(0));
        System.out.println(myArrayList.search(3));
        System.out.println(myArrayList.search(666));
    }
}

获取 pos 位置的元素

注意:size位置为无效元素


public int getPos(int pos) {
    if (pos < 0 || pos >= this.size) {
        throw new RuntimeException("ArrayIndexOfBoundsException : " + pos);
    }
    return this.data[pos];
}

测试:


public class UseArrayList {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(0, 0);
        myArrayList.add(1, 1);
        myArrayList.add(2, 2);
        myArrayList.add(3, 3);
        System.out.println(myArrayList.getPos(0));
        System.out.println(myArrayList.getPos(3));
        System.out.println(myArrayList.getPos(1));
        System.out.println(myArrayList.getPos(6));
    }
}

将 pos 位置的元素值设为 value

这里不涉及元素的移动


public void setPos(int pos, int value) {
    if (pos < 0 || pos >= this.size) {     // size位置为无效元素
        throw new RuntimeException("ArrayIndexOfBoundsException : " + pos);
    }
    this.data[pos] = value;
}

测试:


public class UseArrayList {
    public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(0, 0);
        myArrayList.add(1, 1);
        myArrayList.add(2, 2);
        myArrayList.add(3, 3);
        myArrayList.setPos(0, 666);
        myArrayList.setPos(3, 777);
        System.out.println(myArrayList.printMyArrayList());
    }
}

删除第一次出现的关键字key

注意在删除的时候的数组边界以及改变size


public void remove(int key) {
    int pos = search(key);
    if (pos == -1) {
        return;        // 若是这个数字不存在,则返回
    }
    for (int i = pos; i < this.size - 1; i++) {
        this.data[i] = this.data[i + 1];      // 从后往前挪,直接将要删除的数字覆盖掉
    }
    this.size--;
}

获取顺序表长度


public int size() {
    return this.size;
}

清空顺序表


public void clear() {
    this.size = 0;
}

删除所有的key

如果我们想要删除顺序表中所有的key,如何做?

法一:我们可以将第一次出现的key删除完之后再继续搜索若有,则删除,没有则删除完毕


public void removeAll(int key) {
    for (int i = 0; i < this.size; i++) {
        if (this.search(key) != -1) {
            remove(key);
        } else {
            return;
        }
    }
}

法二:我们可以转变以下思路,不直接删除key,而是重新创建一个数组,将源数组中不是key的值复制到新数组,再让原数组的引用指向新数组,间接完成删除操作


public void removeAllPlus(int key) {
    int[] newData = new int[this.data.length];    // 新数组长度应该和源数组长度相同
    int j = 0;
    for (int i = 0; i < this.size; i++) {
        if (this.data[i] != key) {
            newData[j] = this.data[i];
            j++;
        }
    }
    this.data = newData;
    this.size = j;
}

注意:在元素复制完之后要改变源数组的引用,并改变顺序表的size

法三:我们既然可以通过复制的方式实现间接删除操作,那么我们可以想着将原数组就当成目标数组,即两个指针,一个数组


public void removeAllPlusPlus(int key) {
    int dest = 0;
    for (int src = 0; src < this.size; src++) {
        if (this.data[src] != key) {
            this.data[dest] = this.data[src];
            dest++;
        }
    }
    this.size = dest;
}

到此这篇关于Java数据结构顺序表从零基础到精通进阶的文章就介绍到这了,更多相关Java 顺序表内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯