数据结构.数组

1.数组的概念和特点

数组就是一种容器(装数据的),用来存储相同类型的数据值。

数组的特点:

1.引用类型(或者可以认为数组即对象)
2.可以存同一个类型很多个数据
3.长度不可变(短板 需要用到扩容—这就用到后面说的链表的好处了,数组是静态的,链表才是真正意义上的动态数据结构)

2.数组的定义和初始化

1.数组的定义:
数据类型[] 数组名;//int[] a;
数据类型 数组名[]; //int a[];

2.数组的创建:三种方式
int[] a=new int[10];
int[] a={a,b,c,d};
int[] a=new int[]{a,b,c,d};

3.数组的索引(index):
[0,数组名.length)
第一个位置索引是0
最后一个位置索引是length-1

3.数组的遍历

1.for循环

int[] a={1,2,3,4};
        for (int i=0;i<a.length;i++){
            System.out.print(a[i]+"------");
        }

在这里插入图片描述

2.增强for循环

 int[] a={1,2,3,4};
        for (int arr:a){//arr是给要遍历的a数组临时取的名字
            System.out.print(arr+"-----");
        }

在这里插入图片描述

小总结:for循环知道索引,可以拿到想要的值,增强for循环没有索引,全部遍历出来

3.最简单的直接用人家提供的Arrays.toString(数组名)

 int[] a={1,2,3,4};
        System.out.print(Arrays.toString(a));

在这里插入图片描述

4.数组的基本操作(不多说 注解很详细)

    package com.ffyc.datastructure;

    import java.util.Arrays;
    import java.util.Objects;
    import java.util.Random;

    //数组
    public class MyArray<T> {//写成泛型  就可以存多种数据类型
        /*创建自己的数组  基于java中的数组 进行二次封装  制作属于我们自己的可变数组  操作增删改查*/

        /*泛型  然后增加是扩容(创建新数组)、删除缩容 */

        //1.创建数组 初始化
       private T[] data;//数组的数据容器 用来保存自己数组的
        private int size;//实际保存数据的个数   永远指向待插入位置的索引
        /*get/set方法  可获得数组和数组长度*/

        //构造方法 有参无参

        MyArray() {//无参
            this(20);//默认创建容量为20的数组
        }

        MyArray(int capacity) {//有参  创建一个数组 当然要指定容量了
        this.size=0;
        data= (T[]) new Object[capacity];//T是不可以直接new的 可以先newObjects 再强制类型转换创建成T

        }



        //2.数组的方法

        //2.1判断数组是否为空
        public boolean isEmpty(){
               return this.size==0;
        }

        //2.2获取数组中实际保存元素的个数
      /*  public int getSize(){
            return this.size;
        }*/
    //这个方法已经有了  直接用就可以

        //2.3 增 向数组末尾添加元素
        public void addTail(T ele){
            //直接调add 索引为size
            add(this.size,ele);
        }


        //2.3 增 向数组头部添加元素
        public void addHead(T ele){
            //直接调add  索引为0即可
            add(0,ele);
        }

        //2.3 增  向指定位置(任意位置)添加元素 牵扯元素后移 循环 从后面开始移
        /*添加操作:插前判断 插后加加    */
        public void add(int index,T ele){
            if (index<0||index>size){//判断数组索引位置是否有效
                throw new IllegalArgumentException("index is error");
            }
            //位置有范围  还有满了不能插入  都需要判断
            if (this.size==data.length){//判断数组是否已满
               /* throw new IllegalArgumentException("this array is full");*/
            //如果数组满  就扩容
       resize(2*data.length);//更改数组容器
            }

            //在index位置插 要将index及以后的都后移  从最后面开始移
            for (int i=size-1;i>=index;i--){
                data[i+1]=data[i];//后移操作  把把前一个位置上的数赋值给后面 空出一个位置(即就是待插入元素的位置)
            }
            data[index]=ele;
            this.size++;//记得长度++
        }



        //改变数组容器 可扩容也可缩容
        public void resize(int newCapacity){
            T[] newData= (T[]) new Object[newCapacity];//new一个新数组  然后复制进去(循环)
            for (int i=0;i<this.size;i++){
                newData[i]=data[i];
            }
            this.data=newData;//把新数组替换调原来的数组
        }

        //2.6  查   获取指定位置的元素
        public T getEleByIndex(int index){
            //判断数组越界
            if (index<0||index>=size){
                throw new IllegalArgumentException("index is error");
            }
            return data[index];
        }




        //2.5  改  修改指定位置的元素
        public void updataByIndex(int index,T ele){
            //判断数组越界
            if (index<0||index>=size){
                throw new IllegalArgumentException("index is error");
            }
            data[index]=ele;
        }


        //2.7  包含(搜索)操作  判断数组中是否包含指定元素  循环就可以
        public int isContains(T ele){
            for (int i=0;i<this.size;i++){
                if (this.data[i].equals(ele)){
                    return i;//找到返回索引
                }
            }
            return -1;//遍历完还没找到  就是不包含 返回-1
        }

        /*这里的删除只能删除第一次出现的*/
        //2.4 删  删除指定位置的元素  元素前移  长度-1
        public T remove(int index){
            //判断位置是否有效
            if (index<0||index>=size){
                throw new IllegalArgumentException("index is invalid");//无效索引
            }
            //位置有效就开始操作   前移
            T result=data[index];//一定要放在删除之前先保存
            for (int i=index+1;i<size;i++){//从待删元素的后一个元素开始前移
                data[index]=data[index+1];//前移
            }
            this.size--;
            data[size]=null;//前移占了删除位置  后面就空一个位置
            //返回删除元素的位置
            //删除之后进行缩容操作
            if (this.size==data.length/4&&data.length/2>0){//加条件data.length/2>0 因为缩容1/2是0  不能缩容到0  1/4 真正不需要那么多的时候才缩容  解决复杂度震荡(删一个增一个 又扩又缩)
                resize(data.length/2);
            }

            return result;
        }



        //2.4 头删
        public T removeHead() {
            if (isEmpty()){
                return null;
            }
         T result=this.data[0];//记录第一个元素队首元素
           //删除后 把后面的元素前移
            for (int i=1;i<this.size;i++){
             this.data[i-1]=this.data[i];
            }
            this.size-=1;
            //缩容
            if (this.size==data.length/4&&data.length/2>0){//加条件data.length/2>0 因为缩容1/2是0  不能缩容到0  1/4 真正不需要那么多的时候才缩容  解决复杂度震荡(删一个增一个 又扩又缩)
                resize(data.length/2);
            }
            return result;
        }

        //2.4  尾删
        public T removeTail(){
            if (isEmpty()){
                return null;//判断数组是否为空 为空就没得删了
            }
            T result=this.data[--this.size];//记录尾部的元素  size永远指向待插入元素的位置先-- 先--才是最后一个元素
            //缩容
            if (this.size==data.length/4&&data.length/2>0){//加条件data.length/2>0 因为缩容1/2是0  不能缩容到0  1/4 真正不需要那么多的时候才缩容  解决复杂度震荡(删一个增一个 又扩又缩)
                resize(data.length/2);
            }
            return result;
        }

        //2.4  删  删除指定元素 返回删除元素的位置
        public int removeEle(T ele){
            //判断待删除元素是否存在
             int index= isContains(ele);//判断元素是否存在 返回一个索引 存在就用这个索引直接删
            if (index==-1){
                return -1;
            }else {
                remove(index);
            }
            return index;//返回删除元素的位置
        }


        //2.8   遍历操作  把数组中每个元素进行输出  写到toString方法中
        @Override
        public String toString() {
         StringBuilder sb=new StringBuilder();
         sb.append("[");//开始的时候放左括号
            //遍历
            for (int i=0;i<this.size;i++){
                sb.append(data[i].toString());
                //逗号隔开
                if(i!=this.size-1){
                    sb.append(",");
                }
            }
            sb.append("]");//结束的时候追加右括号  就都在括号里了
            return sb.toString();
        }



        //下面get、set方法
        public T[] getData() {
            return data;
        }

        public void setData(T[] data) {
            this.data = data;
        }

        public int getSize() {
            return size;
        }

        public void setSize(int size) {
            this.size = size;
        }

        public static void main(String[] args) {
            MyArray<Integer> myArray=new MyArray<Integer>(10);
            int count=20;//嘿嘿  多少个都可以添加进去
            //添加操作  随机数添加
            Random random=new Random();
            for (int i=0;i<count;i++){
               myArray.addTail(random.nextInt(10));//加Integer.MAX_VALUE就都是整数
            }
            System.out.println("数组:"+myArray);

           //判断10是否在数组中
            System.out.println("2是否存在:"+(myArray.isContains(2)==-1?false:true));

    MyArray<String> strArray=new MyArray<>();
            strArray.addTail("qw");
            strArray.addTail("er");
            strArray.addTail("r");
            strArray.addTail("q");
            strArray.addTail("k");
            System.out.println("字符串:"+strArray);//默认调toString方法
            System.out.println("c是否存在:"+(strArray.isContains("c")==-1?false:true));
            strArray.add(2,"123");
            System.out.println("字符串:"+strArray);//默认调toString方法
        }
    }

测试结果:

在这里插入图片描述

5.操作的时间复杂度

O(1)<O(n)<O(lgn)<Onlogn<O(n^2)

增加和删除:遍历一遍数组 时间复杂度O(n)
查找和修改:已知索引O(1),位置索引O(n) 因为未知索引需要遍历一遍
增加的时候resize扩容:均摊复杂度 O(1)

均摊思想:
不同情况下时间复杂度出现级别差别,就比如未满是插入是O(1),满了插入要扩容O(n),基本是低级,偶尔高级,将高的均摊到低的 下来整体就是O(1)
n次O(1)的操作=1次O(n)的操作 平均就是1次O(1)

复杂度的震荡:
数组满了的时候新增就会扩容,扩容后又删除,用不到那么多空间就会缩容,频繁这样操作就会又扩又缩,太急着缩容了太勤快

解决办法:Lazy
让size==capacity/4时,才会缩容 即减半

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

团团kobebryant

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值