首页 > 其他分享 >知识改变命运 数据结构【顺序表】

知识改变命运 数据结构【顺序表】

时间:2024-08-14 22:58:27浏览次数:11  
标签:顺序 int ArrayList list System 改变命运 数据结构 public out

1.线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结
构,常见的线性表:顺序表、链表、栈、队列…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物
理上存储时,通常以数组和链式结构的形式存储。
在这里插入图片描述

2.顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成
数据的增删查改。

2.1 接口的实现

public class SeqList {
    private int[] array;
    private int size;
    // 默认构造方法
    SeqList(){ }
    // 将顺序表的底层容量设置为initcapacity
    SeqList(int initcapacity){ }
    // 新增元素,默认在数组最后新增
    public void add(int data) { }
    // 在 pos 位置新增元素
    public void add(int pos, int data) { }
    // 判定是否包含某个元素
    public boolean contains(int toFind) { return true; }
    // 查找某个元素对应的位置
    public int indexOf(int toFind) { return -1; }
    // 获取 pos 位置的元素
    public int get(int pos) { return -1; }
    // 给 pos 位置的元素设为 value
    public void set(int pos, int value) { }
    //删除第一次出现的关键字key
    public void remove(int toRemove) { }
    // 获取顺序表长度
    public int size() { return 0; }
    // 清空顺序表
    public void clear() { }
    // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display() { }
}

代码实现:

public class MyListArray implements List{
    public  int []elme;
    public int ussize=0;
    public MyListArray (){
       this.elme  =new int[2];
    }

    /**
     * 把data放在数组中 有效数据的最后一个
     * @param data
     */
    @Override

    public void add(int data) {
        if(isFull()){
            resize();
        }
        elme[ussize]=data;
        ussize++;
    }

    public void resize(){
       elme=Arrays.copyOf(elme,2*(elme.length));
    }

    /**
     * 将data放在数组pos的位置;
     * @param pos
     * @param data
     */
    @Override
    public void add(int pos, int data) {
        if (isFull()){
            this.resize();
        }
        if(pos<0||pos>ussize){
            throw new RuntimeException("pos位置不合法");
        }
        for (int i = ussize-1; i>=pos ; i--) {
            this.elme[i+1] =this.elme[i];
        }
        elme[pos]=data;
        ussize++;
    }

    /**
     * 找到tofind数据返回ture或flase
     * @param toFind
     * @return
     */
    @Override
    public boolean contains(int toFind) {
        for (int i = 0; i <ussize-1 ; i++) {
            if(toFind==elme[i]){
                return true;
            }
        }
        return false;
    }
    /**
     * 找到tofind数据返回下标
     * @param toFind
     * @return
     */
    @Override
    public int indexOf(int toFind) {
        for (int i = 0; i <ussize-1 ; i++) {
            if(toFind==elme[i]){
                return i;
            }
        }
        return -1;
    }

    /**
     * 获取下表的值
     * @param pos
     * @return
     */
    @Override
    public int get(int pos) {
        if(pos<0||pos>=ussize){
            throw new RuntimeException("pos位置不合法");
        }
        return elme[pos];
    }

    /**
     * 更新pos下标的值为value
     * @param pos
     * @param value
     */
    @Override
    public void set(int pos, int value) {
        if(pos<0||pos>=ussize){
            throw new RuntimeException("pos位置不合法");
        }
        this.elme[pos]=value;
    }

    @Override
    public void remove(int toRemove) {
        int index=indexOf(toRemove);
        if(index==-1){
            return;
        }
        for (int i =index; i <ussize-1 ; i++) {
            elme[i]=elme[i+1];
        }
        ussize--;
    }
    public void removeALl(int toRemove) {
        for (int i = 0; i <ussize ; i++) {
            if(elme[i]==toRemove){
                for (int j =i; j <ussize ; j++) {
                    elme[j]=elme[j+1];
                }
                ussize--;
                i--;
            }
        }

    }

    @Override
    public int size() {
        return this.ussize;
    }

    /**
     * 删除所有数据
     */
    @Override
    public void clear() {
//        for (int i = 0; i < ussize; i++) {
//            elme[i]=null;
//        }如果是引用类型
        ussize=0;
    }

    @Override
    public void display() {
        for (int i = 0; i <ussize; i++) {
            System.out.print(elme[i]+" ");
        }
        System.out.println();
    }

    @Override
    public boolean isFull() {
        return ussize==elme.length;
    }
}

3. ArrayList简介

在集合框架中,ArrayList是一个普通的类,实现了List接口,具体框架图如下:
在这里插入图片描述

【说明】

  1. ArrayList是以泛型方式实现的,使用时必须要先实例化
  2. ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
  3. ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
  4. ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
  5. 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
  6. ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表

4. ArrayList使用

4.1 ArrayList的构造

在这里插入图片描述

public static void main(String[] args) {
	// ArrayList创建,推荐写法
	// 构造一个空的列表
	List<Integer> list1 = new ArrayList<>();
	// 构造一个具有10个容量的列表
	List<Integer> list2 = new ArrayList<>(10);
	list2.add(1);
	list2.add(2);
	list2.add(3);
	// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整形元素
	// list3构造好之后,与list中的元素一致
	ArrayList<Integer> list3 = new ArrayList<>(list2);
	// 避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难
	List list4 = new ArrayList();
	list4.add("111");
	list4.add(100);
}

4.2 ArrayList常见操作

ArrayList虽然提供的方法比较多,但是常用方法如下所示,需要用到其他方法时,同学们自行查看ArrayList的帮助
文档

boolean add(E e) 尾插 e

void add(int index, E element) 将 e 插入到 index 位置

boolean addAll(Collection<? extends E> c) 尾插 c 中的元素

E remove(int index) 删除 index 位置元素

boolean remove(Object o) 删除遇到的第一个 o

E get(int index) 获取下标 index 位置元素

E set(int index, E element) 将下标 index 位置元素设置为 element

void clear() 清空

boolean contains(Object o) 判断 o 是否在线性表中

int indexOf(Object o) 返回第一个 o 所在下标

int lastIndexOf(Object o) 返回最后一个 o 的下标

List<E> subList(int fromIndex, int toIndex) 截取部分 list
public static void main(String[] args) {
	List<String> list = new ArrayList<>();
	list.add("JavaSE");
	list.add("JavaWeb");
	list.add("JavaEE");
	list.add("JVM");
	list.add("测试课程");
	System.out.println(list);
	// 获取list中有效元素个数
	System.out.println(list.size());
	// 获取和设置index位置上的元素,注意index必须介于[0, size)间
	System.out.println(list.get(1));
	list.set(1, "JavaWEB");
	System.out.println(list.get(1));
	// 在list的index位置插入指定元素,index及后续的元素统一往后搬移一个位置
	list.add(1, "Java数据结构");
	System.out.println(list);
	// 删除指定元素,找到了就删除,该元素之后的元素统一往前搬移一个位置
	list.remove("JVM");
	System.out.println(list);
	// 删除list中index位置上的元素,注意index不要超过list中有效元素个数,否则会抛出下标越界异常
	list.remove(list.size()-1);
	System.out.println(list);
	// 检测list中是否包含指定元素,包含返回true,否则返回false
	if(list.contains("测试课程")){
	list.add("测试课程");
	}
	// 查找指定元素第一次出现的位置:indexOf从前往后找,lastIndexOf从后往前找
	list.add("JavaSE");
	System.out.println(list.indexOf("JavaSE"));
	System.out.println(list.lastIndexOf("JavaSE"));
	// 使用list中[0, 4)之间的元素构成一个新的SubList返回,但是和ArrayList共用一个elementData数组
	List<String> ret = list.subList(0, 4);
	System.out.println(ret);
	list.clear();
	System.out.println(list.size());
}

我们要强调下上面方法中的:
E remove(int index)
boolean remove(Object o)
当我们要删掉1时候,会发现是删掉的是下标1的数值所以我们要这样去写
在这里插入图片描述

4.3 ArrayList的遍历

ArrayList 可以使用三方方式遍历:for循环+下标、foreach、使用迭代器

ArrayList<Integer> list=new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println(list);
        System.out.println("=======for循环========");
        for (int i = 0; i <list.size() ; i++) {
            System.out.print(list.get(i));
        }
        System.out.println();
        System.out.println("=======for each 循环========");
        for (Integer x: list) {
            System.out.print(x);
        }
        System.out.println("=======迭代器遍历1========");
        Iterator<Integer> it= list.iterator();
        while(it.hasNext()){
            System.out.print(it.next()+" ");
        }
        System.out.println();
        System.out.println("=======迭代器遍历2========");
        ListIterator it1=list.listIterator();
        while (it1.hasNext()){
            System.out.print(it1.next());
        }
        System.out.println();
        System.out.println("=======迭代器遍历3========");
        ListIterator it2=list.listIterator(list.size());
        while (it2.hasPrevious()){
            System.out.print(it2.previous());
        }
        System.out.println();

4.4 ArrayList的扩容机制

下面代码有缺陷吗?为什么?

  public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add(i);
        }
    }

ArrayList是一个动态类型的顺序表,即:在插入元素的过程中会自动扩容。以下是ArrayList源码中扩容方式:

Object[] elementData; // 存放元素的空间
     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 默认空间
     private static final int DEFAULT_CAPACITY = 10; // 默认容量大小
     public boolean add(E e) {
         ensureCapacityInternal(size + 1); // Increments modCount!!
         elementData[size++] = e;
         return true;
     }
     private void ensureCapacityInternal(int minCapacity) {
         ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
     }
     private static int calculateCapacity(Object[] elementData, int minCapacity) {
         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
             return Math.max(DEFAULT_CAPACITY, minCapacity);
         }
         return minCapacity;
     }
     private void ensureExplicitCapacity(int minCapacity) {
         modCount++;
// overflow-conscious code
         if (minCapacity - elementData.length > 0)
             grow(minCapacity);
     }
     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
     private void grow(int minCapacity) {
// 获取旧空间大小
         int oldCapacity = elementData.length;
// 预计按照1.5倍方式扩容
         int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果用户需要扩容大小 超过 原空间1.5倍,按照用户所需大小扩容
         if (newCapacity - minCapacity < 0)
             newCapacity = minCapacity;
// 如果需要扩容大小超过MAX_ARRAY_SIZE,重新计算容量大小
         if (newCapacity - MAX_ARRAY_SIZE > 0)
             newCapacity = hugeCapacity(minCapacity);
// 调用copyOf扩容
         elementData = Arrays.copyOf(elementData, newCapacity);
     }
     private static int hugeCapacity(int minCapacity) {
// 如果minCapacity小于0,抛出OutOfMemoryError异常
         if (minCapacity < 0)
             throw new OutOfMemoryError();
         return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
     }

上面jdk8的扩容机制
【总结】

  1. 检测是否真正需要扩容,如果是调用grow准备扩容
  2. 预估需要库容的大小
    初步预估按照1.5倍大小扩容
    如果用户所需大小超过预估1.5倍大小,则按照用户所需大小扩容
    真正扩容之前检测是否能扩容成功,防止太大导致扩容失败
  3. 使用copyOf进行扩容
    缺陷:对空间有一定的浪费。

标签:顺序,int,ArrayList,list,System,改变命运,数据结构,public,out
From: https://blog.csdn.net/2402_84062064/article/details/141023909

相关文章

  • 高阶数据结构(Java):AVL树插入机制的探索
    目录1、概念1.1什么是AVL树2.1平衡因子3、AVL树节点的定义4、AVL树的插入机制4.1初步插入节点4.2更新平衡因子4.3 提升右树高度4.3.1右单旋4.3.2左右双旋4.4 提升左树高度4.4.1左单旋 4.4.2右左双旋5、AVL树的验证6、AVL树的删除1、概念1.1什......
  • 【数据结构】详细介绍线性表中的顺序表,带你复盘实现细节,附上顺序表编程练习题
    目录一.线性表二.顺序表 1.静态顺序表与动态顺序表2.动态顺序表的接口实现 2.1顺序表初始化 2.2判断是否需要扩容  2.3 顺序表指定位置插入2.4 顺序表头插2.5 顺序表尾插2.6 顺序表指定位置删除2.7 顺序表头删2.8 顺序表尾删2.9 顺序表查找2.1......
  • 顺序结构
    定义与特点定义顺序结构就是程序运行时自上而下的依次执行我们所写的代码,直到执行完所有语句。在C语言、Java等编程语言中,顺序结构都是程序设计的基础。特点线性执行:程序中的语句按照它们在代码中的顺序,从上到下依次执行。无跳转:在顺序结构中,不存在跳转到其他语句或模块执......
  • 线程执行顺序 join()
    importlombok.SneakyThrows;importjava.util.concurrent.TimeUnit;publicclassT{@SneakyThrowspublicstaticvoidmain(String[]args){Objecto=newObject();Threadthread1=newThread(()->{try{......
  • 数据结构之链表超详解(1)
     一人我饮酒醉醉把佳人成双对两眼是独相随只求他日能双归娇女我轻扶琴燕嬉我紫竹林痴情红颜心甘情愿千里把你寻说红颜我痴情笑曲动我琴声妙轻狂高傲懵懂无知只怪太年少弃江山我忘天下斩断情丝无牵挂千古留名传佳话我两年征战已白发一生征战何人陪谁是谁非谁相随戎马一......
  • 一次函数最优化数据结构
    哎呀没写完,明天再补吧李超线段树一个节点维护递归到这个点,包含整个区间,并且在mid处取值最大的线段。若有两条线段,其中x比y在mid处值更大,如果x在l和r处值都比y大,显然y没有用。否则y只可能在左区间或右区间比x优。李超线段树利用单侧递归保证时间复杂度。但是李超线段树不便于......
  • 嵌入式软件--数据结构与算法 DAY 12
    数据结构和算法是程序的核心,虽然在嵌入式应用中很少会用到,但了解认知这种思维过程是非常有必要的。一个好的程序员应该把数据结构和算法看的比代码更重要。1.数据结构是什么?定义1(宏观):数据结构是为了高效访问数据而设计出的一种数据的组织和存储方式。定义2(微观):数据结构......
  • 嵌入式软件--数据结构与算法 DAY 13
    在嵌入式中,对算法的要求不高,但顺序查找和冒泡排序是经典算法,必须掌握。1.算法定义算法是一个用于解决特定问题的有限指令序列(计算机可以执行的操作)。通俗的理解就是可以解决特定问题的方法。2.时间复杂度时间复杂度不是执行完一段程序的总时间,而是描述为一个算法中基本操作......
  • C语言-有n个整数,使前面各数顺序向后移m个位置,最后m个数变成最前面m个数,见 图8.43。写
    1.题目要求:有n个整数,使前面各数顺序向后移m个位置,最后m个数变成最前面m个数,见图8.43。写一函数实现以上功能,在主函数中输入n个整数和输出调整后的n个数。2.解题思路:可采用指针法,可将数组中最后一位元素的值赋给中间变量暂存,然后将剩余数组中的元素通过指针依次后移一位......
  • [OI] 可持久化数据结构
    学了一年OI才看懂这句话:\(\logn\)是以什么为底的?其实没什么区别因为我们自动忽略常数,因此\(\log_{a}n=\frac{\log_{x}n}{\log_{x}a}=\log_{x}n\)可持久化数组可持久化数组是基于可持久化线段树的一种数据结构.它可以支持如下操作:单点修改查询历史版本在历史版......