前言:
🌈✨之前小怡给大家分享了数据结构的基础知识,今天小怡给大家分享数据结构里的顺序表。
1.线性表
线性表是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列……
线性表在逻辑上是线性结构,也就是说连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
2.顺序表
顺序表使用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
2.1 接口的实现
总共有这几个类:
具体代码如下:
MyArrayList类:
import java.util.Arrays;
public class MyArrayList implements IList{
public int[] array;
public int usedSize;
public MyArrayList(){
this.array=new int[10];
}
@Override
//默认放在 最后
public void add(int data) {
if(isFull()){
grow();
}
this.array[this.usedSize]=data;
this.usedSize++;
}
private void grow(){
this.array= Arrays.copyOf(this.array,2*this.array.length);
}
@Override
public void add(int pos, int data) {
try {
checkPos(pos);
if (isFull()){
grow();
}
//挪动元素
for (int i=usedSize-1;i>=pos;i--){
array[i+1]=array[i];
}
array[pos]=data;
usedSize++;
}catch (PosIllegal e){
System.out.println("插入元素pos位置不合法");
e.printStackTrace();
}
}
public boolean isFull(){
return this.usedSize==array.length;
}
private void checkPos(int pos){
if(pos<0||pos>usedSize){
throw new PosIllegal("Pos位置不合法");
}
}
@Override
public boolean contains(int toFind) {
for (int i=0;i<usedSize;i++){
if (array[i]==toFind){
return true;
}
}
return false;
}
//包含toFind返回下标
//否则返回-1
@Override
public int indexOf(int toFind) {
for (int i=0;i<usedSize;i++){
if (array[i]==toFind){
return i;
}
}
return 0;
}
private void checkPos2(int pos){
if(pos<0||pos>=usedSize){
throw new PosIllegal("Pos位置不合法");
}
}
@Override
public int get(int pos) {
try {
checkEmpty();
checkPos2(pos);
return array[pos];
}catch (PosIllegal e){
e.printStackTrace();
}catch (EmptyExcetion e){
e.printStackTrace();
}
return -1;
}
private void checkEmpty(){
if(isEmpty()){
throw new EmptyExcetion("顺序表为空");
}
}
public boolean isEmpty(){
return usedSize==0;
}
@Override
public void set(int pos, int value) {
try {
checkEmpty();
checkPos2(pos);
array[pos]=value;
}catch (PosIllegal e){
e.printStackTrace();
}catch (EmptyExcetion e){
e.printStackTrace();
}
}
@Override
public void remove(int toRemove) {
try {
checkEmpty();
int pos=indexOf(toRemove);
if (pos==-1){
return;
}
for (int i=pos;i<usedSize-1;i++){
array[i]=array[i+1];
}
usedSize--;
}catch (EmptyExcetion e){
e.printStackTrace();
}
}
@Override
public int size() {
return this.usedSize;
}
@Override
public void clear() {
usedSize=0;
}
public void display(){
for (int i=0;i<this.usedSize;i++){
System.out.println(array[i]+" ");
}
}
}
EmptyException类:
public class EmptyExcetion extends RuntimeException{
public EmptyExcetion(){
}
public EmptyExcetion(String msg){
super(msg);
}
}
PosIllegal类:
public class PosIllegal extends RuntimeException{
public PosIllegal(){
}
public PosIllegal(String msg){
super(msg);
}
}
Ilist接口:
public interface IList {
//新增元素,默认在数组最后新增
public void add(int data);
//在pos位置新增元素
public void add(int pos,int data);
//判定是否包含某个元素
public boolean contains(int toFind);
//查找某个元素对应的位置
public int indexOf(int toFind);
//获取pos位置的元素
public int get(int pos);
//给pos位置的元素设为value
public void set(int pos,int value);
//删除第一次出现的关键字key
public void remove(int toRemove);
//获取顺序表长度
public int size();
//清空顺序表
public void clear();
//打印顺序表
public void display();
public boolean isFull();
public boolean isEmpty();
}
2.2 区别
下面我们来比较一下这两种写法的区别:
List<Integer> list=new ArrayList<>();
只要实现这个接口的都能引用,向上转型;但是通过这个接口,只能调用 这个接口当中包含的方法;
ArrayList<Integer> list=new ArrayList<>();
通过list这个引用,可以调用当前类的所有可以被调用的方法。
2.3 优缺点
优点 :给定下标,查询速度很快;
缺点:删除、插入慢。
3.ArrayList简介
在集合框架中,ArrayList是一个普通的类,实现了List接口。
【说明】
- ArrayList 是以泛型方式实现的,使用时必须要先实例化;
- ArrayList 实现了RandomAccess接口,表明ArrayList 支持随机访问;
- ArrayList 实现了Clonable接口,表明ArrayList 是可以clone的;
- ArrayList 实现了Serializable接口,表明ArrayList 是支持序列化的;
- 和Vector不同,ArrayList 不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList ;
- ArrayList 底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表。
4.ArrayList 使用
4.1 ArrayList 的构造
方法 | 解释 |
---|---|
ArrayList () | 无参构造 |
ArrayList (Collection<?extends E>c) | 利用其它Collection构建ArrayList |
ArrayList (int initialCapacity) | 指定顺序表初始容量 |
【注意】
这里的?叫做通配符,<? extends E>的意思是通配符的上界,?要么是E,要么是E的子类。
【注意】
避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难。
4.2 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 |
4.3 ArrayList 的遍历
【注意】:
1.ArrayList最常使用的遍历方式是:for循环+下标以及foreach;
2.迭代器是设计模式的一种;
3.还有一种专门的listIteretor遍历。
3
4.4 ArrayList的扩容机制
ArrayList是一个动态类型的顺序表,即:在插入元素时后会自动扩容 。
1.检测是否真正需要扩容,如果是调用grow准备扩容;
2.预估需要库容的大小:
- 初步预估按照1.5倍大小扩容;
- 如果用户所需大小超过预估1.5倍的大小,则按照用户所需大小扩容;
- 真正扩容之前检测是否能扩容成功,防止太大导致扩容失败。
3.使用copyOf扩容。
5.ArrayList的具体使用
5.1 简单的洗牌算法
Card类:
public class Card {
public int rank;//牌面值
public String suit;//花色
public Card(String suit, int rank) {
this.suit = suit;
this.rank = rank;
}
public String toString(){
return String.format("[%s,%d]",suit,rank);
}
}
CardDemo类:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class CardDemo {
public static final String[] SUITS={"♠","♥","♣","♦"};
//买一副牌,52张
public static List<Card> buyCard(){
List<Card> cardList =new ArrayList<>(52);
for (int i = 0; i <4 ; i++) {
for (int j=0;j<13;j++){
int rank=j;
String suit=SUITS[i];
Card card=new Card(suit,rank);
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 index= random.nextInt(i);
swap(cardList,i,index);
}
}
private void swap(List<Card> cardList,int i,int j){
Card tmp=cardList.get(i);
cardList.set(i,cardList.get(j));
cardList.set(j,tmp);
}
public List<List<Card>> play(List<Card> cardList){
List<Card> hand0=new ArrayList<>();
List<Card> hand1=new ArrayList<>();
List<Card> hand2=new ArrayList<>();
List<List<Card>> hand=new ArrayList<>();
hand.add(hand0);
hand.add(hand1);
hand.add(hand2);
for (int i = 0; i < 5; i++) {
for (int j=0;j<3;j++){
Card card=cardList.remove(0);
hand.get(j).add(card);
}
}
return hand;
}
}
Test类:
public class Test {
public static void main(String[] args) {
CardDemo cardDemo = new CardDemo();
//1.买52张牌
List<Card> cardList = cardDemo.buyCard();
System.out.println(cardList);
//2.洗牌
cardDemo.shuffle(cardList);
System.out.println(cardList);
//3.3个人,轮番揭牌5张
List<List<Card>> ret=cardDemo.play(cardList);
for (int i=0;i<ret.size();i++){
System.out.println("第"+(i+1)+"个人的牌: "+ret.get(i));
}
System.out.println("剩下的牌:");
System.out.println(cardList);
}
}
结果是这样的:
🌈✨今天的分享到这里结束啦, 小怡和大家一起学习一起进步,“生活就像骑自行车,要想进步就得往前走”。