【数据结构】ArrayList与顺序表

目录

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效率比较低,这时候就需要用到链表

  • 33
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值