不良人系列--复兴数据结构(顺序表篇下)

个人主页:爱编程的小新

不良人经典中二语录:”诸位,可愿为本帅俯首”

目录

一. ArrayList的模拟实现

1.MyList接口

2.MyArrayList类

3.实现MyArrayList中的方法

(1). add(int value)

(2). add(int index,int value)

 (3). remove(int index)

(4). remove(Object value)

(5). get(int index)

 (6). set(int index,int value)

(7). clear( )

(8). contains(Object value)

(9). indexOf(int value)

(10). lastindexOf(int value)

(11). isEmpty( )

 二. 简单的洗牌算法

 1. Card类

2. CardDemo类

3. shuffleCard(洗牌)

4. 发牌


在上期我们讲述了顺序表的概念以及用法,那么本期我们来自己实现一个顺序表(测试数据统一用整形数据)

一. ArrayList的模拟实现

1.MyList接口

回顾上篇:【顺序表篇上】

首先我们知道ArrayList实现的List接口,但是我们本次是简单实现模拟实现一下ArrayList,所以这里我们定义一些ArrayList中常见的方法

MyList接口中的方法:

方法解释
boolean add (E e)在数组最后添加元素e
void add(int index,E e)将e插入数组下标为index的位置
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)获取数组中最后出现的指定元素下标
boolean isEmpty()判断数组是否为空

那么知道了MyList接口需要定义哪些方法后,我们接下来开始义我们的Mit接口:

public interface MyList {
    public void add(int value);//尾插
    public void add(int index,int value);//在指定位置插入
    public void remove(int index);//删除指定下标位置的元素
    public void remove(Object value);//删除第一次出现的指定元素
    public int get(int index);//获取下标index位置的元素
    public void set(int index,int value);//将下标index位置的元素设置为value
    public void clear();//清空顺序表
    public boolean contains(int value);//判断value是否存在顺序表中
    public int indexOf(int value);//返回第一个value的下标
    public int lastindexOf(int value);//返回顺序表中最后出现的value的下标
    public boolean isEmpty();//判断顺序表是否为空;
}

接口创建完成后,我们接下来创建我们的MyArrayList类,在MyArrayList类中重写MyList接口中的方法。

2.MyArrayList类

​
public class MyArrayList implements MyList{

    @Override
    public void add(int value) {
        
    }

    @Override
    public void add(int index, int value) {

    }

    @Override
    public void remove(int index) {

    }

    @Override
    public void remove(Object value) {

    }

    @Override
    public int get(int index) {
        return 0;

    }

    @Override
    public void set(int index, int value) {

    }

    @Override
    public void clear() {

    }

    @Override
    public boolean contains(int value) {
        return false;
    }

    @Override
    public int indexOf(int value) {
        return 0;
    }

    @Override
    public int lastindexOf(int value) {
        return 0;
    }

    @Override
    public boolean isEmpty() {
        return false;
    }
}

​

那么ArrayList类中一般情况下是采用数组存储。在数组上完成数据的增删查改,所以我们需要定义一些变量来帮助我们完成对数据的增删查改:

public class MyArrayList implements MyList{
    
    private int[] array;//数组
    private static final int capacity = 10;//数组默认容量,不能够被修改,使用static final修饰
    private int usedsize;//数组中已经存储的元素个数

    //构造无给定大小的数组
    public MyArrayList() {
        array = new int[capacity];
        usedsize = 0;
    }

    //构造给定大小的数组
    public MyArrayList(int size) {
        array= new int[size];
        usedsize = 0;
    }
}

3.实现MyArrayList中的方法

(1). add(int value)

添加元素前的注意事项:判断数组空间是否已经满了,满了则需要进行扩容。

    public void add(int value) {
        //如果数组可用空间满了则扩容
        if(isFull()){
            Expansion();
        }
        array[usedsize]=value;//将value插入array数组末尾
        usedsize++;//数组中已经存储的元素个数+1;

    }
    //扩容
    private void Expansion(){
        this.array= Arrays.copyOf(this.array,
                this.array.length<<1);
    }
    //判断
    public boolean isFull(){
        //如果数组中已经存储的元素个数与数组大小相同
        //则数组满了
        return array.length==usedsize;
    }

(2). add(int index,int value)

元素插入前的注意事项:

1. 判断插入的位置是否合法(不能小于0或者大于usedsize),否则进行报错

2. 判断数组空间是否已经满了,满了则需要进行扩容。

    public void add(int index, int value) {
        //判断插入位置是否合法
        if(index<0||index>usedsize){
            throw new IndexOutOfBoundsException("插入下标不合法!");
        }
        //判断数组空间是否满了
        if(isFull()){
            Expansion();
        }
        //从尾部开始移动元素
        for(int i=usedsize-1;i>=index;i--){
            array[i+1]=array[i];
        }
        //在index位置插入value;
        array[index]=value;
        usedsize++;
    }

我们来测试一下:

 (3). remove(int index)

删除指定下标位置的元素注意事项:

1. 判断删除位置的下标是否合法,不合法进行报错;

2. 删除元素后,数组存储的元素个数-1;

    public void remove(int index) {
        if(index<0||index>=usedsize){
            throw new IndexOutOfBoundsException("下标不合法");
        }
        //删除指定下标位置的元素
        for(int i=index;i<usedsize-1;i++){
            array[i]=array[i+1];
        }
        //数组中存储的元素个数-1
        usedsize--;
    }

(4). remove(Object value)

删除第一次出现的指定元素:

 public void remove(Object value) {
        //先判断数组中是否存在指定元素
        if(contains((int)value)==false){
            return ;
        }
        int index=0;
        for(int i=0;i<usedsize;i++){
            if(array[i]==(int)value){
               index=i;
            }
        }
        for(int i=index;i<usedsize-1;i++){
            array[i]=array[i+1];
        }
        usedsize--;
  }

public boolean contains(int value) {
        for(int i=0;i<usedsize;i++){
            if(array[i]==value){
                return true;
            }
        }
        return false;
    }

(5). get(int index)

获取下标index位置的元素:

 public int get(int index) {
        if(index<0||index>=usedsize){
            throw new IndexOutOfBoundsException("下标不合法!");
        }
        return array[index];
    }

 (6). set(int index,int value)

将下标index位置的元素替换成value:

public void set(int index, int value) {
        if(index<0||index>=usedsize){
            throw new IndexOutOfBoundsException("下标不合法!");
        }
        this.array[index]=value;
    }

(7). clear( )

清空顺序表:

 public void clear() {
        //将数组已经存储的元素个数置为0;
        this.usedsize=0;
    }

(8). contains(Object value)

判断value是否存在在顺序表中:

    public boolean contains(int value) {
        for(int i=0;i<usedsize;i++){
            if(array[i]==value){
                return true;
            }
        }
        return false;
    }

(9). indexOf(int value)

返回顺序表中第一个value的下标:

    public int  indexOf(int value) {
        if(contains(value)){
            for(int i=0;i<usedsize;i++){
                if(array[i]==value){
                    return i;
                }
            }
        }
        return -1;
    }

(10). lastindexOf(int value)

返回顺序表中最后出现的value的下标:

    public int lastindexOf(int value) {
        if(contains(value)){
            for(int i=usedsize-1;i>=0;i--){
                if(array[i]==value){
                    return i;
                }
            }
        }
        return -1;
    }

(11). isEmpty( )

判断顺序表是否为空:

public boolean isEmpty() {
        return usedsize==0;
    }

 以上就是我们模拟实现的ArrayList类中的方法啦~接下来我们来测试一下:

public class Main {
    public static void main(String[] args) {
        MyArrayList list=new MyArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        list.add(8);
        list.add(9);
        list.add(10);
        //初始的顺序表
        System.out.print("顺序表初始元素:");
        list.display();//打印顺序表中的元素
        //插入新的元素
        list.add(11);//在尾部插入11
        list.add(6,0);//在6下标的位置插入0
        System.out.print("顺序表插入后的元素:");
        list.display();
        //删除指定元素
        list.remove((Object)10);//删除顺序表中10这个元素
        list.remove(5);//删除下标为5的位置的元素
        System.out.print("顺序表删除后的元素:");
        list.display();
        //获取元素
        System.out.println("获取顺序表中下标为5的元素:"+list.get(5));
        //改变指定下标的元素
        System.out.println("改变前,7下标的元素:"+list.get(7));
        list.set(7,55);//将7下标的元素更改为55
        System.out.println("改变后,7下标的元素:"+list.get(7));
        System.out.print("改变后的顺序表:");
        list.display();
        //判断10在不在顺序表中
        System.out.println("10在不在顺序表中:"+list.contains(10));
        //返回第一个10的下标
        System.out.println("顺序表中第一个10的下标是:"+list.indexOf(10));
        //判断顺序表是否为空
        System.out.println("顺序表是否为空:"+list.isEmpty());

        //清空顺序表
        list.clear();
        System.out.println("清空顺序表后,顺序表是否为空:"+list.isEmpty());

    }
}

运行结果:

 二. 简单的洗牌算法

既然我们已经学习了顺序表,那么结合实际我们利用顺序表制作一个简单的洗牌算法~

实现思想:

1. 我们需要有一副牌,共有54张(包含大小王)

2. 洗牌:我们需要将这副牌的顺序进行打乱

3. 发牌:一共有三个人,每个人每轮摸一张牌,摸5轮

4. 最后我们查看一下3个人手里牌分别是什么

 1. Card类

首先我们需要定义一个Card类描述我们每张牌的花色和大小:

package shuffle;
public class Card {
    public String suit;//表示牌的花色
    public int size;//表示牌的大小
    
    public Card(String suit, int size) {
        this.suit = suit;
        this.size = size;
    }

    @Override
    public String toString() {
        return "{"+suit+size+"}";
    }
}

那么现在Card类创建完成后,我们就可以开始利用顺序表创建一副牌啦~

2. CardDemo类

那么在一副牌中有哪些特征呢?

1. 大小

2. 花色:♠️,♥️,♦️,♣️

现在来创建我们的一副牌:

public class CardDemo {
    public static final String Suits[]={"♠","♥","♣","♦"};//定义牌的花色
    public static List<Card> buydeck(){
        //ArrayList实现了List接口,所以这里可以使用List通过向上转型进行实例化
         List<Card> cardlist=new ArrayList<>();
         String str[]={"A","k","Q","J"};
         //将2-10的牌放入顺序表中
        for(int i=2;i<=10;i++){
            for(int j=0;j<4;j++){
                //定义每一张牌的大小和花色
                Card card=new Card(Suits[j],String.valueOf(i));
                //将每张牌添加到这副牌中
                cardlist.add(card);
            }
        }
        /*
            2-10的牌添加完成后
            现在添加A,k,Q,J;
        */
       for(int i=0;i<4;i++){
          for(int j=0;j<str.length;j++){
              Card card=new Card(Suits[i],str[i]);
              cardlist.add(card);
          }
       }
       //最后添加大小王
        Card card=new Card("","大王");
        cardlist.add(card);
        Card card2=new Card("","小王");
        cardlist.add(card2);
        return cardlist;
    }
    public static void main(String[] args) {
        List<Card> card=buydeck();
        System.out.println(card);

    }
}

最终结果:

那么现在一副牌就被我们创建出来了,现在就需要进行洗牌啦

3. shuffleCard(洗牌)

我们可以利用随机数生成器生成1-54之间的下标,然后我们从后往前将每张牌与随机生成位置下标的牌进行交换,这样我们就能够达到洗牌的效果啦:

    public static void shuffleCard(List<Card> cards){//洗牌
        //利用随机数随机生成交换的位置
        Random rand=new Random(1000000);
        for(int i=cards.size()-1;i>0;i--)
        {
            //生成的随机数(交换的位置的下标)范围不能大于一副牌中牌的数量
            int index= rand.nextInt(i);
            //将我们的第i个位置的牌跟第index位置的牌进行交换
            swap(cards,index,i);
        }
    }

    private static void swap(List<Card> cards, int j, int i){//交换牌的位置
        Card tmp=cards.get(i);
        cards.set(i,cards.get(j));
        cards.set(j,tmp);
    }
    public static void main(String[] args) {
        List<Card> card=buydeck();
        System.out.println(card);
        shuffleCard(card);
        System.out.println(card);
    }

运行结果:wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==编辑

4. 发牌

那么现在就只剩下我们的最后一步--发牌:

一共有三个人,摸5轮并且每轮只摸一张牌;

那么我们可以创建一个类似二维数组的顺序表来存放每个人手中不同的牌;

 public static void main(String[] args) {
        List<Card> card=buydeck();//生成一副牌
        System.out.print("刚初始化的牌:");
        System.out.println(card);
        shuffleCard(card);
        System.out.print("洗过后的牌:");
        System.out.println(card);
        //存放三个人手中的牌
        List<List<Card>> hand=new ArrayList<>();//用来存放三个人的牌,最后打印
        List<Card> hand1=new ArrayList<>();
        List<Card> hand2=new ArrayList<>();
        List<Card> hand3=new ArrayList<>();
        hand.add(hand1);
        hand.add(hand2);
        hand.add(hand3);
        for(int i=0;i<5;i++){
            for(int j=0;j<3;j++){
                //remove(0),我们每次拿出那副牌中的第一张牌;
                //拿完后并且删除这张牌;
               hand.get(j).add(card.remove(0));//存储第j个人拿到的牌
            }
        }
        for(int i=0;i<3;i++){
            System.out.println("第"+(i+1)+"个人的牌:"+hand.get(i));
        }
    }

 运行结果:

 结语

本篇简单实现了ArrayList中的方法,顺序表篇在这里也就告一段落啦~希望大家看完这两篇能够有个很好的收获,在此感谢大家的观看!!!

 

评论 108
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值