数据结构之数组

数组的定义

  1. 数组的定义
    数组就是用来存储同一类型若干数据的容器。它其实就是内存中一块连续的存储空间
  2. 语法
    数据类型 [] 数组名 = new 数据类型 [长度]; //一般这么使用
    数据类型 数组名 [] = new 数据类型 [长度];
    数据类型 [] 数组名 = new 数据类型 [] {xx,aa,dd,…}
    注意: 数组名实际就是变量名,数组是一种引用类型:数据类型 [] 。new 运算符在堆中分配一组连续的存储空间,可以存储 长度 个数据类型的元素. 把这块存储空间的引用(起始地址)赋值给数组名, 数组名存储的是堆中数组的起始地址
  3. 数组初始化
    1. 先定义数组,再给数组的元素赋值,这叫数组的动态初始化
    2. 在定义数组的同时就给数组元素赋值,这叫数组的静态初始化
      int [] data3 = new int [] {4,5,6,7}; 还可以简化为int [] data3 = {4,5,6,7};
      注意:
      1. 静态初始化时,不需要指定数组的长度, 数组长度由数组初始化元素的个数决定
      2. 简化形式仅用于数组的静态初始化,不能用于数组的重新赋值
    3. 定义了数组之后 ,系统会给数组的元素默认初始化
      数值类型数组,所有元素默认初始化为0
      字符类型数组,所有元素默认初始化为码值为0的字符,’\u0000’
      布尔类型数组,所有元素默认初始化为false
      引用类型数组,所有元素默认初始化为null

数组元素的访问

通过数组的索引值(下标)访问数组的元素
数组的索引值是从0开始的, 即数组的最大的元素下标是: 数组的长度-1
访问数组元素:数组名[索引值] = 值;
为什么通过索引值可以访问到数组的元素?
可以通过数组的索引值(下标)计算出每个数组的元素的地址(偏移量).
在这里插入图片描述

数组作为参数与返回值类型

public class Test04ArrayArgs{
    public static void main(String[] args) {
        //调用getArray()方法,该方法返回int[]类型的数组, 可以定义int[]类型的 数组保存方法的返回值
        int [] data = getArray();

        //打印data数组中的元素
        printArray( data );
    };
    //2) 定义方法,打印整数数组的元素, 需要通过参数来接收一个数组
    public static void printArray(int[] data) {
        //把data参数接收的数组元素打印到屏幕上
        for (int x : data) {
            System.out.print( x + " ");
        }
        System.out.println();
    }
    //1)定义方法, 返回一个长度为10的整数数组,该数组进行随机初始化[0,100)范围内的整数
    public static  int [] getArray(){
        int [] data = new int[10];
        //给data数组元素进行初始化
        for (int i = 0; i < data.length; i++) {
            double xx = Math.random();       //Math类的静态方法random()返回[0,1)范围内的随机小数
            data[i] =  (int)(xx*100);
        }
        //返回data数组
        return  data;       //data是int []类型, 方法返回值类型应该是int[]
    }
}

变长参数

特点:

  1. 变长参数可以接收任意个数据,在 方法体中,可以把 变长参数 当作数组使用
  2. 在定义方法时, 在方法参数列表中最后一个参数可以定义为变长参数
  3. 一个方法最多只能有一个变长参数
  4. 变长参数在参数类型与参数名中间使用三小点 表示
public class Test05args {
    public static void main(String[] args) {
        //在调用方法时,可以传递任意个数据
        sum();
        sum(1);
        sum(1,2,3,4,5);
        //在调用方法时,也可以传递数组
        int [] arr = {6,6,6,6,6};
        sum(arr);
    }
    //定义方法,可以计算任意个整数的和, 需要通过参数来接收任意个整数, 就可以使用变长参数
    public static void sum( int ... data){
        int sum = 0 ;       //保存累加和
        //在 方法体中,可以把 变长参数 当作数组使用
        for (int i = 0; i < data.length; i++) {
            sum += data[i];
        }
        System.out.println("sum=" + sum);
    }
}

数组扩容

定义了数组之后 ,数组存储元素的个数就确定了, 如果想要存储更多的数据, 就需要对数组进行扩容.
原理:定义一个更大的数组, 把原来数组中的元素复制到新数组中
数组扩容使用到的两个方法:

  1. Arrays.copyOf( 源数组, 新数组的长度) //这个方法的实现也是依靠System.arraycopy这个方法
  2. System.arraycopy(源数组, 源数组起始位置, 目标数组, 目标数组的起始位置, 复制元素的个数);
public class Test06ArrayCopy {
    public static void main(String[] args) {
        //完全手工扩容
		//test01();
        //System.arraycopy()数组复制
		//test02();
        //直接调用Arrays.copyeOf()
        test03();
    }
    
	//方式一:手动扩容2倍大小
    private static void test01() {
        //1)定义数组
        int [] data = {1,2,3,4,5};
        //定义更大的数组
        int [] anotherArray = new int[data.length * 2 ];    //新数组的长度是原来数组长度的两倍
        //把原来数组中的内容复制到新数组中
        for(int i = 0 ;  i<data.length; i++){
            anotherArray[i] = data[i];
        }
        //让原来的数组名指向新的数组
        data = anotherArray;
        //打印data数组
        System.out.println(Arrays.toString(data));
    }
    
	//方式二:使用System.arraycopy
    private static void test02() {
        //1)定义数组
        int [] data = {1,2,3,4,5};
        //定义更大的数组, 新数组的长度是原来数组长度的1.5倍
        int [] anotherArray = new int[data.length + data.length / 2 ];
        //把原来数组中的内容复制到新数组中,
		// System.arraycopy(源数组, 源数组起始位置, 目标数组, 目标数组的起始位置, 复制元素的个数);
        System.arraycopy(data, 0, anotherArray, 0, data.length);
        /*
            System类的arraycopy方法使用native修饰, 只有方法的声明没有方法体,该方法的方法体可能是用C++实现的
            Java的JNI(Java native Interface)技术,可以使得在java程序中可以调用其他语言编写的代码
         */
        //让原来的数组名指向新的数组
        data = anotherArray;
        //打印data数组
        System.out.println(Arrays.toString(data));
    }
    
    //方式三:使用Arrays.copyOf
	private static void test03() {
        //1)定义数组
        int [] data = {1,2,3,4,5};
        //Arrays.copyOf( 源数组,  新数组的长度)
        data = Arrays.copyOf(data, data.length * 2 );
        System.out.println(Arrays.toString(data));
    }
}

数组特点

  1. 优点:
    访问快. 通过索引值计算出每个元素的地址
  2. 缺点:
    插入/删除慢. 在插入/删除时,可能需要扩容,复制/移动大量的元素

适用于以访问为主,较少添加/删除的场景.
数组插入元素

public class Test07ArrayInsert {
    public static void main(String[] args) {
       int [] data = {11,22,33,44,55,66};
       //调用insert方法, 向数组中插入元素, 再让原来的data数组名指向insert方法返回的新数组
       data = insert(data, 2, 666);
       System.out.println(Arrays.toString(data));
    }
    //定义方法,向数组的指定位置插入元素,需要通过参数来接收一个数组, 接收一个位置, 接收一个要插入的元素
    public static int[] insert(int [] array, int i , int key){
        //向array数组中的i位置插入元素key
        //1)定义一个更大的数组
        int [] anotherArray = new int[array.length + 1 ];
        //2)把原数组[0,i)范围的元素复制到新数组[0,i)范围中
        System.arraycopy(array, 0, anotherArray, 0, i );
        //3)在新数组i位置插入元素key
        anotherArray[i] = key;
        //4)把原数组[i,length)范围的元素复制到 新数组[i+1, lenght+1)
        System.arraycopy(array, i, anotherArray, i+1, array.length - i);
        //5)让原来的即数组名指向新的数组, 对形参array重新赋值,对实参没有关系
//        array = anotherArray;
//        System.out.println("in method: " + Arrays.toString(array));
        //5)需要返回新的数组
        return anotherArray;
    }
}

示意图
在这里插入图片描述

数组的相关算法

冒泡排序算法

在这里插入图片描述
代码实现:

public class Test01 {
    public static void main(String[] args) {
        int [] data = {55,33,66, 44,22,11};
        System.out.println(Arrays.toString(data));
        System.out.println("=======================================");

        //由小到大
        //从前向后两两比较,如果前面的数比后面的大,就交换, 把大的数交换到后面
        //数组 有 n 个数, 比较 n-1 轮
        for(int x = 0 ; x < data.length -1 ; x++){          // 比较的轮次
            for(int i = 0 ; i < data.length-1- x ; i++){
                if ( data[i] > data[i+1]){
                    int t = data[i];
                    data[i] = data[i+1];
                    data[i+1] = t;
                }
                System.out.println(Arrays.toString(data));
            }
            System.out.println("--------------------------------------");
        }
    }
}

选择排序算法

在这里插入图片描述
代码实现

public class Test02 {
    public static void main(String[] args) {
        int[] data = {55, 33, 66, 44, 22, 11};
        System.out.println(Arrays.toString(data));
        System.out.println("=======================================");
        //在当前数中选择最小的交换到前面
        for( int x = 0 ; x < data.length-1; x++){
            int min  = x;       //保存当前数最小元素的下标
            for(int i = min + 1 ;  i< data.length; i++){
                if ( data[i] <data[min]){
                    min = i;
                }
            }
            //把min标识的元素与x位置的元素交换
            if (min != x ){
                int t = data[min];
                data[min] = data[x];
                data[x] = t;
            }
            System.out.println( Arrays.toString(data));
        }
    }
}

二分查找算法

在这里插入图片描述
代码实现

public class Test03 {
    public static void main(String[] args) {
        int [] data = {11,22,33,44,55,66,77};
        
        System.out.println( binarySearch(data, 11));
        System.out.println( binarySearch(data, 77));
        System.out.println( binarySearch(data, 44));
        System.out.println( binarySearch(data, 50));
    }
    //定义方法,二分查找,返回数组中指定元素的索引值
    public static int binarySearch(int [] array, int key ){
        int from = 0 ;
        int to = array.length - 1;
        int mid = (from+to)/2;
        while ( from <= to ){
            if ( array[mid] == key ){
                return  mid;
            }else if (array[mid] > key){    //在左一半
                to = mid-1;
                mid = (from+to)/2;
            }else {         //右一半
                from = mid + 1 ;
                mid = (from+to)/2;
            }
        }
        return -1;
    }
}

Arrays工具类

java.util.Arrays类,提供了一组操作数组的方法

返回值类型方法名用途
static ListasList(T… a)把数组转换成list列表
static intbinarySearch(int [] a,int key)二分查找
static boolean []copyOf(boolean [] original ,int newlength)数组复制
static int []copyOfRange(int [] original , int from , int to)
static StringdeepToString(Object [] a)打印二维数组
static voidfill(int[] a, int fromIndex, int toIndex, int val)
static voidparallelSort(int[] a)并行排序,社和数据元素非常多的情况
static voidsort(int[] a)排序
static StringtoString(int[] a)将数组元素转换成字符串
public class Test04 {
    public static void main(String[] args) {
        //1)定义数组
        int [] data = {55,33,11 ,77,22 };

        //2)对数组排序
        Arrays.sort(data);

        //3)打印数组元素
        System.out.println( Arrays.toString(data));         //[11, 22, 33, 55, 77]

        //4)数组扩容
        data = Arrays.copyOf(data, data.length * 2 );
        System.out.println( Arrays.toString(data));         //[11, 22, 33, 55, 77, 0, 0, 0, 0, 0]

        //5)填充 把数组中 [ 4,8 ) 范围的元素填充为66
        Arrays.fill(data, 4, 8, 66);
        System.out.println( Arrays.toString(data));     //[11, 22, 33, 55, 66, 66, 66, 66, 0, 0]

        //6)数组容量缩减
        data = Arrays.copyOf(data, data.length - 3);
        System.out.println( Arrays.toString(data));     //[11, 22, 33, 55, 66, 66, 66]

        //7)对排序数组进行二分查找
        System.out.println( Arrays.binarySearch(data, 11));     //0
        System.out.println( Arrays.binarySearch(data, 66));     //5
        System.out.println( Arrays.binarySearch(data, 50));     //-4 返回负数表示不存在
    }
}

二维数组

在定义时使用一对方 括弧[] 就是一维数组;
在定义时使用两对方括弧[][] 就是二维数组.

二维数组的每个元素又是一个一维数组
二维数组的定义格式: 数据类型[][] 数组名 = new 数据类型[二维数组长度][];

public class Test05 {
    public static void main(String[] args) {
        //定义一维数组
        int [] data1 = {1,2,3,4,5};
        int [] data2 = {6,7,8};
        int x = 10;
        int y = 20;
        //在静态初始化时,可以是常量,也可以是变量, 只要数组中元素是int类型即可
        int [] data3 = { x, y };
        //数据类型就是存储元素 的类型
        int [] [] mydata = { data1, data2, data3};
        //1)当前mydata数组中存储的data1,data2,data3又是一个一维数组 ,mydata数组称为二维数组

		//2)二维数组的定义格式:  数据类型[][] 数组名 = new 数据类型[二维数组长度][];
        //定义二维数组, 长度是5, 数组中存储int类型数据
        int [][] mydata2 = new int[5][];
        //mydata2数组 有 5个元素, 每个元素是int []类型的, 它 是一种引用类型, 各个元素默认默认为null
        for (int[] ints : mydata2) {
            System.out.println( ints );         //null
        }

        //3)在定义二维数组时,也可以指定一维 数组的长度, 系统会给一维数组进行默认初始化
        int [][] mydata3 = new int[5][3];
        for (int[] ints : mydata3) {
//         System.out.println( ints );       //ints是一维数组名, 存储的是一维数组的引用,不为null
            //mydata3的每个元素ints是一维数组 , 还可以继续遍历ints一维数组中的元素
            for (int anInt : ints) {
                System.out.print( anInt + " \t ");
            }
            System.out.println();       //换行
        }

        //4)给二维 数组元素赋值, 赋值int[]一维数组
        mydata3[0] = data1;
        mydata3[1] = data2;
        mydata3[2] = new int[]{6,6,6,6,6,6};
//        mydata3[3] = {8,8,8};       //这种简化形式仅用于数组的静态初始化

        //5)使用for循环遍历
        for (int i = 0; i < mydata3.length; i++) {
            //mydata3[i]二维数组元素是一维 数组, 还需要继续for循环遍历,就把mydata3[i]看作是一个一维数组名即可
            for (int j = 0; j < mydata3[i].length; j++) {
                System.out.print( mydata3[i][j] + "\t");
            }
            System.out.println();
        }

        //6)二维数组的静态初始化, 就是在定义数组的同时给数组元素赋值,静态初始化不需要指定数组的长度
        int [][]mydata4 = new int[][]{ data1, data2, data3};
        //可以简化为
        int [][] mydata5 = {data1, data2, data3};
        //或者:
        int [][] mydata6 = { {1,2,3,4,5,6,7} , {4,5,6,7,8}, {9,9,9}};
        //或者
        int [][] mydata7 = { data1, new int[]{6,6,6,6,6}, {7,8,9}};

        //7)可以调用Arrays.deeptoString()把二维数组的元素转换为字符串
        System.out.println(Arrays.deepToString(mydata5));
        System.out.println(Arrays.deepToString(mydata6));
        System.out.println(Arrays.deepToString(mydata7));
    }
}

对象数组

数组中存储的是对象, 称为对象数组

public class Test06 {
    public static void main(String[] args) {
        //1)定义数组存储Student对象
        Student[] data = new Student[100];
        //一般情况下, 会定义一个变量记录数组中元素的数量, 每次添加元素时,size就加1
        int size = 0 ;

        //2)添加元素
        //注意,对象数组元素其实存储的是对象的引用
        //数组一般顺序存储
        data[size] = new Student("lisi", 20, 98);      //new创建一个新的Student对象,把该对象的引用赋值给data[0]元素
        size++;         //1

        data[size] = new Student("wangwu", 40, 68);
        size++;         //2

        data[size] = new Student("zhaoliu", 30, 88);
        size++;         //3
        
        data[size++] = new Student("feifei", 18, 59 );
        data[size++] = new Student("laodu", 35, 10 );

        //3)打印数组中存储的Student对象, 只需要遍历添加的元素即可, 不需要遍历所有的元素
        for (int i = 0; i < size ; i++) {
            System.out.println( data[i]);
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值