首页 > 其他分享 >【数据结构】ArrayList与顺序表

【数据结构】ArrayList与顺序表

时间:2024-07-20 12:54:27浏览次数:13  
标签:顺序 int ArrayList List pos add 数据结构 public

目录

1.前言

2.顺序表

2.1定义一个IList接口

2.2实现接口功能

2.3自定义异常类

2.4主程序代码

3.ArrayList

3.1ArrayList简介

3.2ArrayList的构造

3.3ArrayList常见操作

3.4ArrayList的遍历

 4.ArrayList的具体使用

4.1简单的洗牌算法

4.2杨辉三角 

 5.总结


1.前言

通过上篇博客的介绍,我们初步认识数据结构的基本知识,接下来与大家分享关于ArrayList与顺序表的相关知识。ArrayList是数组链表,也就是我们经常所说的顺序表。它是Java内置的,让我们更加方便地编写代码,下面我们就一起来了解ArrayList与顺序表的相关知识。

2.顺序表

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

2.1定义一个IList接口

public interface IList {
    //新增元素,默认在数组的最后面进行新增
    void add(int data);

    //在pos位置新增元素
    void add(int pos, int data);

    //判断是否包含某个元素
    boolean contains(int toFind);

    //查找某个元素的对应位置
    int indexOf(int toFind);

    //获取pos位置的元素
    int get(int pos);

    //给pos位置的元素设为value,相当于更新
    void set(int pos, int value);

    //删除第一次出现的关键字key
    void remove(int toRemove);

    //,获取顺序表的长度
    int size();

    //清空顺序表
    void clear();

    //打印顺序表,注意:该方法不是顺序表中的方法,为了方便看测试结果
    void display();

    //判断数组是否已满
    boolean isFull();
}

上面就是我们自己写的一个简单ArrayList的接口。

2.2实现接口功能

package arraylist;

import java.util.Arrays;

public class MyArrayList implements IList {
    public int[] elem;
    public int usedSize;

    public MyArrayList() {
        this.elem = new int[10];
    }

    @Override
    public void add (int data) {
        if (isFull()) {
            //数组满了对数组进行扩容
            elem = Arrays.copyOf(elem, 2 * elem.length);
        }
        this.elem[usedSize] = data;
        this.usedSize++;
    }

    @Override
    public void add(int pos, int data) {
        try {
            checkPos(pos);
        } catch (PosNotLegalException e) {
            e.printStackTrace();
        }
        if (isFull()) {
            elem = Arrays.copyOf(elem, 2 * elem.length);
        }
        //移到元素
        for (int i = usedSize - 1; i >= pos; i--) {
            elem[i + 1] = elem[i];
        }
        //插入元素
        elem[pos] = data;
        usedSize++;
    }

    //判断添加元素时pos是否合法
    private void checkPos(int pos) throws PosNotLegalException {
        if (pos < 0 || pos > usedSize) {
            throw new PosNotLegalException("add插入元素时,pos位置不合法!");
        }
    }

    //需要寻找usedSize次
    @Override
    public boolean contains(int toFind) {
        for (int i = 0; i < usedSize; i++) {
            if (elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int indexOf(int toFind) {
        for (int i = 0; i < usedSize; i++) {
            if (elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }

    @Override
    public int get(int pos) {
        try {
            checkPosOfGetAndSet(pos);
        } catch (PosNotLegalException e) {
            e.printStackTrace();
        }
        return elem[pos];
    }

    private void checkPosOfGetAndSet(int pos) throws PosNotLegalException {
        if (pos < 0 || pos >= usedSize) {
            throw new PosNotLegalException("get或者set获取元素时,pos位置不合法!");
        }
    }

    @Override
    public void set(int pos, int value) {
        try {
            checkPosOfGetAndSet(pos);
        } catch (PosNotLegalException e) {
            e.printStackTrace();
        }
        elem[pos] = value;
    }

    @Override
    public void remove(int toRemove) {
        //1.要检查是否存在要删除的关键字 toRemove
        int pos = indexOf(toRemove);
        if (pos == -1) {
            System.out.println("没有要删除的数字!");
            return;
        }
        for (int i = pos; i < usedSize - 1; i++) {
            elem[i] = elem[i + 1];
        }
        usedSize--;
    }

    @Override
    public int size() {
        return usedSize;
    }

    @Override
    public void clear() {
        usedSize = 0;
    }

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

    @Override
    public boolean isFull() {
        return this.usedSize == elem.length;
    }
}

2.3自定义异常类

package arraylist;

public class PosNotLegalException extends RuntimeException {
    public PosNotLegalException() {

    }

    public PosNotLegalException(String msg) {
        super(msg);
    }
}

2.4主程序代码

package arraylist;

import java.util.List;

public class Test {
    public static void main(String[] args) {
        //两种实例化
        IList iList = new MyArrayList();
        //MyArrayList myArrayList = new MyArrayList();
        iList.add(1);
        iList.add(2);
        iList.add(30);
        //iList.add(1,88);
        iList.display();
        iList.remove(2);
        iList.display();
    }
}

 运行结果:

 这就是我们自己写的一个简单的顺序表功能,在Java中内置了ArrayList,具有我们刚刚写的顺序表的功能,而且还为我们提供其他更加强大的功能。

3.ArrayList

3.1ArrayList简介

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

3.2ArrayList的构造

方法 解释
ArrayList() 无参构造
ArrayList(Collection<? extends E> c) 利用其他 Collection 构建 ArrayList
ArrayList(int initialCapacity)指定顺序表初始容量
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);

3.3ArrayList常见操作

方法 解释
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 subList(int fromIndex, int toIndex)截取部分 list

3.4ArrayList的遍历

ArrayList 可以使用三方方式遍历: for循环+ 下标foreach使用迭代器。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(20);
        list.add(30);
        System.out.println(list);


        //使用for循环遍历
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + " ");
        }
        System.out.println();

        //使用foreach遍历
        for (Integer x:list) {
            System.out.print(x + " ");
        }
        System.out.println();

        //使用迭代器遍历
        Iterator<Integer> l = list.listIterator();
        while(l.hasNext()) {
            System.out.print(l.next() + " ");
        }
        System.out.println();
    }
}

运行结果如下:

 4.ArrayList的具体使用

4.1简单的洗牌算法

public class Card {
    public int rank;//数字
    public String suit;//花色

    public Card(int rank, String suit) {
        this.rank = rank;
        this.suit = suit;
    }

    @Override
    public String toString() {
        return "{" + suit + " " + rank + "}";
    }
}
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Cards {
    public static final String[] suits = {"♥", "♠", "♣", "♦"};

    //4个花色 13张牌
    public List<Card> buyCard() {
        List<Card> cardList = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            for (int j = 1; j <= 13; j++) {
                int rank = j;
                String suit = suits[i];
                Card card = new Card(rank, suit);
                cardList.add(card);
            }
        }
        return cardList;
    }

    public void Shuffle(List<Card> cardList) {
        Random random = new Random();
        for (int i = cardList.size() - 1; i > 0; i--) {
            int randIndex = random.nextInt(i);
            swap(cardList, i, randIndex);

        }
    }

    private void swap(List<Card> cardList, int i, int j) {
        //Card tmp =cardList[i];
        Card tmp = cardList.get(i);
        //cardList[i]=cardList[j];
        cardList.set(i, cardList.get(j));
        //cardList[j]=tmp;
        cardList.set(j, tmp);
    }

    //3个人,每次轮流抓5张牌
    public void drawCard(List<Card> cardList) {
        List<Card> hand1 = new ArrayList<>();
        List<Card> hand2 = new ArrayList<>();
        List<Card> hand3 = new ArrayList<>();

        List<List<Card>> hands = new ArrayList<>();
        hands.add(hand1);
        hands.add(hand2);
        hands.add(hand3);

        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 3; j++) {
                Card card = cardList.remove(0);
                List<Card> tmpHand = hands.get(j);
                tmpHand.add(card);
            }
        }
        System.out.println("小明抓的牌" + hand1);
        System.out.println("小欣抓的牌" + hand2);
        System.out.println("小美抓的牌" + hand3);
    }
}
import java.util.List;

public class TestCard {
    public static void main(String[] args) {
        Cards cards = new Cards();
        List<Card> cardList = cards.buyCard();
        System.out.println("刚买回来的牌");
        System.out.println(cardList);
        cards.Shuffle(cardList);
        System.out.println("洗牌之后:");
        System.out.println(cardList);

        System.out.println("抓牌:");
        cards.drawCard(cardList);
        System.out.println("剩下的牌:");
        System.out.println(cardList);
    }
}

 运行结果如下:

4.2杨辉三角 

import java.util.ArrayList;
import java.util.List;

class Solution {
    public List<List<Integer>> generate1(int numRows) {
        List<List<Integer>> list = new ArrayList<>();
        for (int i = 0; i < numRows; i++) {
            List<Integer> row = new ArrayList<Integer>();
            for (int j = 0; j <= i; j++) {
                if (j == 0 || j == i) {
                    row.add(1);
                } else {
                    row.add(list.get(i - 1).get(j - 1)
                            + list.get(i - 1).get(j));
                }
            }
            list.add(row);
        }
        return list;
    }
    public List<List<Integer>> generate2(int numRows) {
        List<List<Integer>> ret = new ArrayList<>();
        //第一行数据为1
        List<Integer> list =new ArrayList<>();
        list.add(1);
        ret.add(list);
        //从第2行开始,计算每个list当中的数据
        for (int i = 1; i < numRows; i++) {
            List<Integer> curRow =new ArrayList<>();
            //每一行第一个数据都为1
            curRow.add(1);
            for (int j = 1; j < i; j++) {
                //获取上一行的数据
                List<Integer> preRow = ret.get(i-1);
                int x1 = preRow.get(j);
                int x2 =preRow.get(j-1);
                curRow.add(x1+x2);
            }
            //当前行最后一个数据为1
            curRow.add(1);
            ret.add(curRow);
        }
        return ret;
    }
}

public class Demo1_10 {
    //杨辉三角
    //给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。
    public static void main(String[] args) {
        Solution solution =new Solution();
        //System.out.println(solution.generate2(5));
        List<List<Integer>> lst = solution.generate1(5);
        for (int i = 0; i < lst.size(); i++) {
            for (int j = 0; j < lst.get(i).size(); j++) {
                System.out.print(lst.get(i).get(j) + " ");
            }
            System.out.println();
        }
    }

}

运行结果如下:

 5.总结

ArrayList具有以下的优缺点:

优点:根据指定下标去查找元素或更新元素的效率很高,时间复杂度为O(1)

缺点:在插入或删除数据时,不仅每一次都需要移动数据,如果要把数据插到0下标位置或删除0下标的数据,时间复杂度为O(n),而且在扩容的时候,默认是扩容1.5倍,当扩容空间只使用了一点时,会白白浪费许多空间。

如果经常要进行查找元素或更新元素顺序表便能大展身手,若在任意位置插入和删除比较多的场景下,ArrayList效率比较低,这时候就需要用到链表

标签:顺序,int,ArrayList,List,pos,add,数据结构,public
From: https://blog.csdn.net/m0_74336101/article/details/140557197

相关文章

  • 《数据结构》--顺序表
    C语言语法基础到数据结构与算法,前面已经掌握并具备了扎实的C语言基础,为什么要学习数据结构课程?--我们学完本章就可以实践一个:通讯录项目简单了解过后,通讯录具备增加、删除、修改、查找联系人等操作。要想实现通讯录项目必须有两个技术关键:(1)C语言语法基础(2)数据结构之顺序表/......
  • 数据结构(00)
    1.序:`数据结构`将与`菜鸟的Leetcode之路`不定时更新,也是一个系列的内容,将会包含许多的数据的逻辑结构,物理结构,数据运算。(具体怎么说,我也不太明白,我的理解是:对于不同类型数据,进行不同的排序和存储,通过指针和数组,方便后续算法对其`增加,删除,修改,查询`。)呃,正如英雄哥所言:数据结构......
  • 山东大学数据结构与算法实验8散列表(线性开型寻址/链表散列)
    A : 线性开型寻址题目描述要求使用线性开型寻址实现描述给定散列函数的除数D和操作数m,输出每次操作后的状态。有以下三种操作:插入x,若散列表已存在x,输出“Existed”,否则插入x到散列表中,输出所在的下标。查询x,若散列表不含有x,输出“-1”,否则输出x对应下标。......
  • 数据结构-线性表、链表
    一、线性表介绍1、线性结构​ 在数据元素存在非空有限集中:存在唯一的一个被称为“第一个”的数据元素存在唯一的一个被称为“最后一个”的数据元素除了第一个外,集合中每个数据元素都只有一个前趋元素除了最后一个外,集合中每个数据元素都只有一个后继元素2、线性表线性表......
  • PYTHON学习笔记(六、python数据结构--字典)
    (3)dict字典字典数据类型的含义是:根据一个信息查找另一个信息的方式构成了“键值对”,它表示索引用的键和对应的值构成对应的关系。1、字典的创建方式1)使用{ }直接创建字典使用{ }创建字典的语法结构如下:d={key1:value1,key2:value2......}例如:#使用{}创建字典d=......
  • 数据结构:栈
    数据结构:栈满足栈的特性,只有先进后出的特性,不能遍历,也就不能遍历打印,也不能随机访问。栈栈:栈是在处理数据时是先进后出、就是先进栈的数据最后一个出栈、最后一个进栈的数据第一个出栈、栈就类似于给一把手枪弹夹压子弹,给弹夹压子弹的顺序就如同数据进栈的顺序,第一颗子......
  • 数据结构(队列)
    文章目录一、概念与结构二、队列的实现QueueNode.hQueue.c初始化判断队列为空队尾,入队列队头,出队列取队头数据取队尾数据取队列有效元素个数销毁队列test.c一、概念与结构......
  • 数据结构_排序
    目录一、排序二、插入排序2.1直接插入排序2.2希尔排序三、选择排序3.1直接选择排序3.2堆排序四、交换排序4.1冒泡排序4.2快速排序五、归并排序六、排序算法分析总结一、排序排序:就是使一串记录序列,按照其中某个或某些关键字的大小,进行递增或递减的排列......
  • 【数据结构】学习day 1.1线性表中的顺序表
    1 "&"区别(c++)#include<stdio.h>voidtest(intx){   x=2024;   printf("intestx=%d\n",x);}intmain(){   intx=1;   printf("beforetestx=%d\n",x);   test(x);   printf("aftertestx=%d\n"......
  • 数据结构——哈希
    前言顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(logN),搜索的效率取决于搜索过程中元素的比价次数。理想的搜索方法:可以不经过任何比较,一次直接从表中得......