3.线性表-数组

0.线性表的定义

线性表又称线性存储结构,是最简单的一种存储结构,专门用来存储逻辑关系为“一对一”的数据。

在一个数据集中,如果每个数据的左侧都有且仅有一个数据和它有关系,数据的右侧也有且仅有一个数据和它有关系,那么这些数据之间就是“一对一“的逻辑关系。

举个简单的例子:

在这里插入图片描述

如上图所示,在 {1,2,3,4,5} 数据集中,每个数据的左侧都有且仅有一个数据和它紧挨着(除 1 外),右侧也有且仅有一个数据和它紧挨着(除 5 外),这些数据之间就是“一对一“的关系。

使用线性表存储具有“一对一“逻辑关系的数据,不仅可以将所有数据存储到内存中,还可以将“一对一”的逻辑关系也存储到内存中。

线性表存储数据的方案可以这样来理解,先用一根线将所有数据按照先后次序“”起来,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w2uXOqCL-1665767931028)(/uploads/allimg/220721/0U1525G7-1.gif)]图 2 数据和“一对一”的逻辑关系

图 2 中,左侧是“串”起来的数据,右侧是空闲的物理空间。将这“一串儿”数据存放到物理空间中,有以下两种方法:

在这里插入图片描述

两种存储方式都可以将数据之间的关系存储起来,从线的一头开始捋,可以依次找到每个数据,且数据的前后位置没有发生改变。

像图 3 这样,用一根线将具有“一对一”逻辑关系的数据存储起来,这样的存储方式就称为线性表或者线性存储结构。

0.1线性表的顺序存储和链式存储

从图 3 不难看出,线性表存储数据的实现方案有两种,分别是:

  1. 像图 3a) 那样,不破坏数据的前后次序,将它们连续存储在内存空间中,这样的存储方案称为顺序存储结构(简称顺序表);
  2. 像图 3b) 那样,将所有数据分散存储在内存中,数据之间的逻辑关系全靠“一根线”维系,这样的存储方案称为链式存储结构(简称链表)。

也就是说,使用线性表存储数据,有两种真正可以落地的存储方案,分别是顺序表和链表。

0.2前驱和后继

在具有“一对一“逻辑关系的数据集中,每个个体习惯称为数据元素(简称元素)。例如,图 1 显示的这组数据集中,一共有 5 个元素,分别是 1、2、3、4 和 5。

此外,很多教程中喜欢用前驱和后继来描述元素之间的前后次序:

  • 某一元素的左侧相邻元素称为该元素的“直接前驱”,此元素左侧的所有元素统称为该元素的“前驱元素”;
  • 某一元素的右侧相邻元素称为该元素的“直接后继”,此元素右侧的所有元素统称为该元素的“后继元素”;

以图 1 数据中的元素 3 来说,它的直接前驱是 2 ,此元素的前驱元素有 2 个,分别是 1 和 2;同理,此元素的直接后继是 4 ,后继元素也有 2 个,分别是 4 和 5。
在这里插入图片描述

1.使用数组实现顺序表

算法:描述解决问题的步骤,在计算机上描述解决问题的步骤,需要使用流程控制
数组:一段连续的存储空间
线性表:线性表是数据结构的一种,数据结构是数据元素之间的关系,线性表中数据
元素的关系就是线性表的定义,数据元素的上层是数据对象,数据对象是数据元素相
同的数据元素的集合,线性表的抽象数据类型就是在线性表上加上一些操作例如:增删
改查等其它操作。理解线性表的概念,其实数组就是一个线性表

2.顺序表的API设计

在这里插入图片描述

  • 线性表实现Iterable接口,重写iterator方法
  • 创建内部类SIterator实现Iterator接口,重写hasNext()方法和next()方法
  • 线性表长度等于数组长度扩容扩2倍
  • 线性表长度小于数组长度的四分之一缩容二分之一
import java.util.Iterator;

public class SequenceList<T extends Comparable<T>> implements Iterable{
    T[] ele;
    int len;

    SequenceList(){
        ele = (T[]) new Comparable[16];
        this.len = 0;
    }

    SequenceList(int capacity){
        ele = (T[]) new Comparable[capacity];
        this.len = 0;
    }

    //清空线性表
    public void clear(){
        ele = null;
        this.len = 0;
    }

    //线性表是否为空
    public boolean isEmpty(){
        return this.len == 0;
    }

    //线性表的长度
    public int size(){
        return this.len;
    }

    //获取指定索引处的元素
    public T get(int i){
       return ele[i];
    }

    //在数组末尾插入元素
    public void insert(T t){
        if(len == ele.length){
            resize(ele.length*2);
        }
        ele[len++] = t;
    }
    
    //在数组指定索引处,插入元素
    public void insert(int index,T t){
        if(len == ele.length){
            resize(ele.length*2);
        }
        for(int i = len-1; i >= index; i--){
            ele[i+1] = ele[i];
        }
        ele[index] = t;
        this.len++;
    }

    //删除指定索引出的元素,并返回索引处的元素
    public T remove(int index){
        if(len<ele.length/4){
            resize(ele.length/2);
        }
        T result = ele[index];
        for(int i =index+1; i < len; i++){
            ele[i-1] = ele[i];
        }
        this.len--;
        return result;
    }
    
    //查找元素所在的索引
    public int indexOf(T t){
        for (int i = 0; i < len; i++){
            if(t == ele[i]){
                return i;
            }
        }
        return -1;
    }
    
    //扩容、缩容
    public void resize(int capacity){
        Comparable[] temp = ele;
        ele = (T[]) new Comparable[capacity];
        for (int i = 0; i < temp.length; i++) {
            ele[i] = (T) temp[i];
        }
    }

    //迭代(遍历)
    @Override
    public Iterator iterator() {
        return new SIterator();
    }

    private class SIterator implements Iterator{
        int n;

        SIterator(){
            n = 0;
        }

        @Override
        public boolean hasNext() {
            return n<len;
        }

        @Override
        public Object next() {
            return ele[n++];
        }
    }
}

测试:

public class SequenceListTest {
    public static void main(String[] args) {
        SequenceList<String> list = new SequenceList<>();
        list.insert("k");
        list.insert("l");
        list.insert("z");
        list.insert("h");
        System.out.println(list.size());
        System.out.println("----------------------");
        for (Object o : list) {
            System.out.println(o);
        }
        System.out.println("-----------------------");
        list.insert(3,"w");
        for (Object o : list) {
            System.out.println(o);
        }
        System.out.println("------------------------");
        System.out.println(list.get(2));
        System.out.println(list.remove(2));
        System.out.println("-------------------------");
        for (Object o : list) {
            System.out.println(o);
        }
    }
}




4
----------------------
k
l
z
h
-----------------------
k
l
z
w
h
------------------------
z
z
-------------------------
k
l
w
h

时间复杂度:
不同的操作有不同的时间复杂度

get方法的时间复杂度为1
insert(int i, T t):时间复杂度为n
insert(T t):时间复杂度为1
remove(int i): 时间复杂度为n
indexOf(T t):时间复杂度为n
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

森林老虎

混口饭吃嘿嘿

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值