线性表seqlist——增删查改

1.什么是线性表?

基于数组的顺序表就叫线性表,线性表属于动态数组,可以根据数据的大小调整长度grow,元素不仅逻辑连续,物理上也连续。(基于链表的线性表,只是数字之间逻辑连续)                               

2.为什么我们不直接用数组吗

因为数组的长度是固定的,假设定义了int[] data= new int[3],声明后就只能存放固定长度的数值。而我们用MyAaay的话,就可以扩展数组容量了。 

3.以下定义

因为存储元素在数组中,因此需要声明数组,来存放具体的数值4

import java.util.Arrays;
public class MyArray {
   
    private int[]data;
    //存放当前实际用了几个空间
    private int size;

    public MyArray() {
        data = new int[10];//默认开辟10个大小
    }

4.一些插入方法add,包括头插、尾插、按下标插入

我们先写按下标插入,因为头插和尾插也属于下标插入的一种。头插是index=0,

尾插是Index =size。

按照下标插入时,插入到index位置,首先判断是否越界然后才能插入。如何插入呢?将index以后的每一个元素向后移一个位置,空出index然后插入值value。这个过程中,要先判断数组容量是否足够,若越界需要扩容,扩容后可以插入。

<1>index插入

 public void addIndex(int index,int value) {
        //判断数组是否满了
        if (size == data.length) {
            grow();
        }


        //index <0 ||index>size判断Index合法性
        //判断index和size的大小关系不能使用data.length,length表示当前数组的最多保存个数,有可能数组的后半部分为空,
        //要使用size属性保证连续性
        if (index < 0 || index > size) {
            System.out.println("add index illeagal");
            return;
        }

        else {
            //将index位置空出来,方便元素插入
            for (int i = size-1; i >=index; i--) {
                data[i+1] = data[i];
            }
            data[index] = value;
            size++;

        }
    }

<2>我将扩容方法写在这里,因为插入要用

 private void grow() {
        //扩容方法设置私有,外界不需要知道
        //copyOf方法传入数组名称,以及新数组的长度
        int[] newData = Arrays.copyOf(data,data.length << 1);
        this.data = newData;
        //扩容后,原来的空间变为垃圾空间被释放
    }

<3>头插法addFirst

   public void addFirst(int value){
        //判断是否越界,如果超过定义的大小,需要扩容
        if(size == data.length){
            grow();
        }
 //       //在数组的头部插入
 //      //当数组不为空时,第一个位置有元素,需要将第一个位置空出来,元素必须从最后一个位置开始向后 
  //移动一个单位,否则就会覆盖原先位置元素
   //     for (int i = size -1; i >= 0; i--) {
   //       //i=0因为必须把第一个位置空出来
   //     data[i+1] = data[i];
   //}
   //此时data[0]空出来了
   // data [0]= value;
     //size++;
//以上是自己写的方法,利用addIndex可以实现优化
      addIndex(0,value);
    }

<4>尾插法addLast

 public MyArray(int capacity){
        data = new int[capacity];
    }
    public void addLast(int value){
        //先判断当前数组是否越界。
        // 假设我们定义的数组长度是3,此时size已经是3了,若要再尾插一个,就会越界
        if(size == data.length){
            //当前数组已满
            //数组要扩容
            grow();
 }

//        //在数组的头部插入
//        //当数组不为空时,第一个位置有元素,需要将第一个位置空出来,元素必须从最后一个位置开始 
//  向后移动一个单位,否则就会覆盖原先位置元素
 //       for (int i = size -1; i >= 0; i--) {
 //           //i=0因为必须把第一个位置空出来
//            data[i+1] = data[i];
//        }
 //       //此时data[0]空出来了
 //       data [0]= value;
 //       size++;
//上面是自己写的方法,通过addIndex达到优化的目的,仍然需要判断是否越界
        addIndex(0,value);
    }

5.一些查询方法get

查询可以分为两种,按照值查询,另一个是按照下标查询

<1>值查询,返回这个值得下标

 public int getByValue(int value){
        //遍历数组
        for (int i = 0; i <size; i++) {
            if(data[i]== value){
                return i;
            }
        }
        //此时循环走完,还没找到元素,说明value不存在
        return -1;
    }

<2>索引查询,返回这个下标对应的值

 public int get(int index){
        //牵扯到用户输入,需要判断合法性
        if(index <0 || index >size){
            System.err.println("get index illagal!");
            return -1;
        }
        //否则返回查询到的值
        return data[index];
    }

<3>contain判断是否存在

由于上面已经写了下值查询,在这里我们可以直接应用,若这个值存在就返回true

    public boolean contains(int value){
        int index = getByValue(value);
        if(index == -1){
            return false;
        }
        return true;
    }

6.一些修改方法set

根据索引修改原先元素,将指定位置元素修改为newValue,返回修改前的元素值(原先这个下标下的值)
 public int set (int index,int newValue){
        //判断合法性
        if(index <0 || index>= size){
            System.err.println("set index illegal!");
        }
        //否则返回这个下标下原先的元素
        int oldValue = data[index];
        data[index] = newValue;
        return oldValue;
    }

7.一些删除方法remove

删除方法分为两种,一种是下标删除,另外一种是值删除。值删除的情况比较特殊,一个数组中,可能出现同一个值连续出现,或者多次出现同一个值,需要分两个方法写。

<1>按照下标删除

找到对应的下标index,将index后的元素全部向前挪一个位置,直接覆盖Index,从index+1开始。

循环移动以后,size位置的元素值还在,徐亚将它删除,我们使用data[size]=0

public void removeIndex(int index){
        if(index<0 || index >= size){
            System.err.println("remove index illegal!");
            return;
        }
        //当size== data.length为了防止越界,保证程序健壮性,i< size-1
        for (int i = index; i <size -1; i++) {
            //i =size-1,最后一个位置
            data[i] = data[i+1];
        }
        size--;
        data[size] = 0;//删除原先数组的最后一个位置的元素
    }

<2>按照值删除

    <a>这个值出现一次的删除

 public void removeValueOnce(int value){
        for (int i = 0; i <size; i++) {
            if(data[i] == value){
                //此时i对应的索引是第一个值为value的结点
                removeIndex(i);
                return;
            }
            //若这个分支走完,还没找到值相同的结点,说明这个值不存在
        }
    }

 

  <b>这个值多次出现的删除。

个人觉得这个方法真的牛,它可以删除连续出现的一个值,也可以删除一个多次出现的不连续的值

我有点不明白这里是怎么体现的,但是它可以实现。

例如一个这样的数组1,2,2,2,2

出现这种连续的重复元素时,需要使用while(data[i] == value),同时i!= size

为什么用while而不是用for呢,因为for每此出现这个值都需要判断,如果使用while就可以让它自己进行判断,不需要我们写了,这是一个精妙的写法

public void removeAllValue(int value){
        for (int i = 0; i <size; i++) {
            while(i!= size && data[i] == value){
                removeIndex(i);
            }
        }

    }

<3>删除头结点

这里使用我们已经写好的方法

public void removeFirst(){
        removeIndex(0);
    }

<4>删除尾结点

这里使用我们已经写好的方法

我还写了一个测试类,如果要练习的话,可以全部依次拷贝,感受一下它的精妙。由于要测试,我们需要写一个打印方法,方便打印。

<1>这是打印方法toString

public String toString(){
        String ret = "[";
        //遍历data数组
        for (int i = 0; i <size; i++) {
            ret +=data[i];
            if(i!= size-1){
                ret += ",";
            }
        }
        ret += "]";
        return ret;
    }

<2>这是测试类,要写在同一个包里哦,直接拷贝就好了。

public class Test {
    public static void main(String[] args) {
        MyArray myArray = new MyArray(3);
//        myArray.addLast(1);
//        myArray.addLast(3);
//        myArray.addLast(5);
//        //存了3个数据,此时我们设定的大小已满
//        myArray.addLast(7);
//        //[1,3,5,7]
//        //自动扩容后,检测结果
//        System.out.println(myArray);
//        myArray.addFirst(10);
//        //[10,1,3,5,7]
//        System.out.println(myArray);
//        myArray.addIndex(1,22);
//        //[10,22,1,3,5,7]
//        System.out.println(myArray);
//        myArray.addIndex(0,33);//头插
//        myArray.addIndex(7,44);//尾插
//        //插入一个不合法下标,不连续了
//        myArray.addIndex(10,55);
//        // [33,10,22,1,3,5,7,44]
//        System.out.println(myArray);
//        System.out.println(myArray.contains(7));
//        //true
//        System.out.println(myArray.getByValue(22));
//        // 2
//        System.out.println(myArray.get(3));
//        //1
//        System.out.println(myArray.set(1,100));
//        //将下标为1位置的元素值改为100
//        System.out.println(myArray);
//        //[33,100,22,1,3,5,7,44]
//        myArray.removeFirst();
//        myArray.removeLast();
//        // 100,22,1,3,5,7
//        myArray.removeIndex(1);
//        // 100,1,3,5,7
//        System.out.println(myArray);


        //测试按照值删除元素
        myArray.addLast(1);
        myArray.addLast(2);
        myArray.addLast(3);
        myArray.addLast(2);
//        myArray.removeValueOnce(2);
//        // 1,2,2

        myArray.removeAllValue(2);
        System.out.println(myArray);
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值