引言

现在目前我们的一个变量,最多就保存一个数据,显然不科学。目前需要一个方案来解决这个问题,可以保存多个数据的容器。在几乎所有的编程语言中都提供了数组这么一个概念,数组它是一种基础的数据结构(列表数据结构)。

一. 数组概念

1.1 基本概念

数组它是存放 一组类型相同,个数有限的数据的容器。数组也是变量,由于它的数据结构的特点可以保存多个数据,数组在内存中,往往是块连续有限的空间。

1.2 图形理解

4.数组 - 图1

二 . 数组的声明与赋值

数组它是一种引用数据类型,它的存储需要使用到两块内存空间(堆和栈),基本数据类型只需要栈空间

2.1 数组声明语法

声明:
声明并分配空间 int[] a = new int[5];
先声明 再分配空间 int a =[]; a =new int[5]; 局部变量存在栈中

声明并赋值(繁) int [] b; b=new int[]{11,22,33,44,55};
声明并赋值(简) int [] c = {1,2,3,4,5};

2.2 数组内存分配

4.数组 - 图2
数组初始化后,会为元素赋予初始值,比如整型数组默认为0 浮点数数组默认为0.0 引用数据类型数组为 null。

三 . 数组的组成

3.1 数组元素寻址

数组由各个元素构成,各个元素依次排列,每个元素都有一个寻址下标,选址下标自动生成,从0开始。首地址结合下标通过偏移就可以寻址到每个元素,这里有一个问题就是,如果偏移的过程中,超过了下标,会造成数组下标越界问题。最大下标为数组长度-1。

元素的访问: 对元素的赋值和取值,数组名[ 下标 ]

3.2 获得数组长度

数组的长度: 数组名.length ;

3.3 数组下标越界

Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 这个异常就是数组下标超出了范围。

下标的范围:0 - 数组长度减一
数组默认值:(没有赋值的情况下)
整数:0
小数:0.0
字符:\u0000
布尔:false
其他:null

  1. public static void main(String[] args) {
  2. int[] scores = new int[5];
  3. //存数据:赋值
  4. scores[0] = 1;
  5. scores[1] = 2;
  6. scores[2] = 3;
  7. scores[3] = 4;
  8. scores[4] = 5;
  9. //取数据:
  10. System.out.println( scores[0] );
  11. System.out.println( scores[1] );
  12. System.out.println( scores[2] );
  13. System.out.println( scores[3] );
  14. System.out.println( scores[4] );
  15. }

四 . 数组的遍历

数组遍历,指的是将元素依次访问一遍,通常这个过程需要借助循环实现,这里介绍两种常见遍历数组的方式

4.1 通过普通for循环

借助循环的连续的循环变量作为下标。

  1. public static void main(String[] args) {
  2. int[] scores = new int[5];
  3. //存数据:赋值
  4. scores[0] = 1;
  5. scores[1] = 2;
  6. scores[2] = 3;
  7. scores[3] = 4;
  8. scores[4] = 5;
  9. //取数据:
  10. System.out.println( scores[0] );
  11. System.out.println( scores[1] );
  12. System.out.println( scores[2] );
  13. System.out.println( scores[3] );
  14. System.out.println( scores[4] );
  15. //数组遍历(把每个元素都访问一遍 != 输出 )
  16. System.out.println("---遍历方式1--"); //天意:循环计数器可以是连续的,恰好用在这里当下标
  17. for( int i =0 ; i< scores.length ; i++ ){
  18. System.out.println( scores[i] );
  19. }
  20. Arrays.sort()
  21. Scnnar sc = new Scanner()
  22. sc.nextInt();
  23. }

4.2 通过增强for循环foreach

此方法是一种语法糖,也就是编写上的形式方便,底层依然采用普通for实现

  1. public static void main(String[] args) {
  2. int[] scores = new int[5];
  3. //存数据:赋值
  4. scores[0] = 1;
  5. scores[1] = 2;
  6. scores[2] = 3;
  7. scores[3] = 4;
  8. scores[4] = 5;
  9. //取数据:
  10. System.out.println( scores[0] );
  11. System.out.println( scores[1] );
  12. System.out.println( scores[2] );
  13. System.out.println( scores[3] );
  14. System.out.println( scores[4] );
  15. //数组遍历 (增强for循环 语法糖= 编译的时候会过程叫 解语法糖,会采用基础原生的方式实现 )
  16. System.out.println("---遍历方式2--");
  17. for( int element : scores ){
  18. System.out.println(element);
  19. }
  20. }

五. 数组应用

5.1 基本使用

5.2 数组作为参数

5.3 数组作为返回值

  1. /**
  2. 数组作为返回值类型
  3. */
  4. public class ArrayUesdReturn {
  5. //编写一个程序,生成一个数字验证码 (4位)
  6. public static int[] createCode(){
  7. int[] codeArray = new int[4];
  8. Random rd = new Random();
  9. for(int i=0;i<4;i++){
  10. int n = rd.nextInt(10);
  11. codeArray[i]=n;
  12. }
  13. System.out.println("codeArray的地址"+codeArray);
  14. return codeArray;
  15. }
  16. public static void main(String[] args) {
  17. int[] result = createCode(); // ctrl
  18. System.out.println("result的地址"+result);
  19. ArrayUsedArgs.printArray(result);
  20. }
  21. }

5.4 值传递与地址传递

  • 对于基本数据类型,传参为值的拷贝,当然返回的也是值的拷贝。
  • 对于引用数据类型, 传参实际是地址传递,当然返回的也是地址。 ```java public class ValueAndRefrence {
  1. public static void main(String[] args) {
  2. int age = 10;
  3. change(age);
  4. System.out.println(age); // 10
  5. int[] brr = {10,20};
  6. change2(brr);
  7. System.out.println(brr[0]+" "+brr[1]);// 100 20
  8. }
  9. public static void change(int num ){
  10. num = 100;
  11. }
  12. public static void change2(int[] arr){
  13. arr[0] = 100;
  14. }

}

  1. <a name="WEN3D"></a>
  2. #### 5.5 数组的扩容
  3. 什么是扩容?<br />扩容指的是扩展存储空间容量,
  4. 为什么要扩容?<br />数组是的容量是声明是就确定了的(定死了)后续不可以被修改,但是我们实际情况又需要更多的容量。这里的"扩容"是一种通过其他手段实现的。因为数组本身长度声明后是不可改变的。
  5. ```java
  6. 旧:
  7. 第一种:
  8. int [] c = {1,2,3,4,5};
  9. int [] new_c = new int [10];
  10. for(int i=0;i<c.length;i++)
  11. {
  12. new_c[i]=c[i];
  13. }
  14. for (int i = 0; i <new_c.length ; i++)
  15. {
  16. System.out.println(new_c[i]);
  17. }
  18. 第二种:
  19. System.arraycopy(原数组,原数组起始,新数组,新数组起始,取到元素的个数);
  20. System.arraycopy(c,0,new_c,0,5);
  21. 第三种:
  22. java.util.Arrays.copyOf(原数组,新长度);
  23. int[] new_c = Arrays.copyOf(c,10);
  24. c=new_c;
  25. //第一种扩容
  26. System.out.println("第一种扩容");
  27. int [] c = {1,2,3,4,5};
  28. int [] new_c = new int [10];
  29. for(int i=0;i<c.length;i++){
  30. new_c[i]=c[i];
  31. }
  32. for (int i = 0; i <new_c.length ; i++)
  33. {
  34. System.out.println(new_c[i]);
  35. }
  36. //第二种扩容
  37. System.out.println("第二种扩容");
  38. int[] new_c2=new int[5];
  39. System.arraycopy(c,1,new_c2,0,3);
  40. for (int i = 0; i <new_c2.length ; i++)
  41. {
  42. System.out.println(new_c2[i]);
  43. }
  44. //第三种扩容
  45. System.out.println("第三种扩容");
  46. int[] new_c3 = Arrays.copyOf(c,10);
  47. for (int i = 0; i <new_c3.length ; i++)
  48. {
  49. System.out.println(new_c3[i]);
  50. }

5.6 数组元素删除

  1. //封装一个删除方法(可能并不完美哈)
  2. public static void delete( String[] data , int index ){
  3. System.arraycopy( data, index+1,data,index,data.length-1-index );
  4. int l = data.length-1;
  5. for(int i=data.length-1;i>0;i--){
  6. if( data[l]==null ){
  7. }else{
  8. data[l]= null;
  9. break;
  10. }
  11. }
  12. }

六 . 数组排序与查找

数组排序指的是采用某种算法来将元素按一定次序排列整齐,数组的查找,根据指的元素判断其在数组中的位置

6.1 冒泡排序

4.数组 - 图3

取相邻的两个元素比较如果前者大于后则交换,一趟的结果为找出了这趟的最大值,且交换到最最后 ,一致重复趟数直到完成。

相邻两个值比较大小,互换位置
N个数字来排队
两两相比小考前
外层循环N-1
内层循环N-1-i

  1. int temp;
  2. for (int i = 0; i <a.length-1 ; i++)
  3. {//0 1 2 3
  4. for (int j = 0; j <a.length-i-1 ; j++)
  5. {//0 0 1 2 3 4 1 0 1 2 3 2 0 1 2
  6. if(a[j]>a[j+1])
  7. {
  8. temp=a[j];
  9. a[j]=a[j+1];
  10. a[j+1] = temp;
  11. }
  12. }
  13. }
  14. for (int e:a)
  15. {
  16. System.out.println(e);
  17. }

6.2 选择排序

固定一个值与其他值比较大小,互换位置
4.数组 - 图4

  1. int[] a = {1,3,3,7,5,8,9};
  2. for (int i = 0; i <a.length-1 ; i++)
  3. {
  4. int min =i;
  5. for (int j = i+1; j <a.length ; j++)
  6. {
  7. if(a[j]<a[i]){
  8. min= j;
  9. }
  10. if(min!=i){
  11. int tmp = a[i];
  12. a[i] = a[min];
  13. a[min] = tmp;
  14. }
  15. }
  16. }
  17. for (int e:a)
  18. {
  19. System.out.print(e);
  20. }

6.3 插入排序

4.数组 - 图5

  1. public static void insert( int[] data){
  2. //根据元素个数确定趟数 为什么是1 开始,假设第一个是排好
  3. for( int i=1; i< data.length;i++ ){
  4. //从未排序区取一个取一个元素data[i+1] 和 已经排序区 比较寻找和位置
  5. for( int j=i ; j>0;j-- ){
  6. // 1 ,2 3 4 8 3|
  7. //如果我们选择的这个数 小于当前元素则交换
  8. if( data[j] < data[j-1] ){
  9. int t = data[j];
  10. data[j]= data[j-1];
  11. data[j-1]=t;
  12. }
  13. }
  14. }
  15. }

6.4 使用JDK排序

jdk排序:Java.util.Arrays.sort() 默认排序升序

  1. int[] a = {1,6,3,7,5,8,9};
  2. Arrays.sort(a);
  3. for (int e:a) {
  4. System.out.print(e);
  5. }

6.5 快速排序原理

4.数组 - 图6

  1. 快速排序,特点就是块, 一般的情况 O(n*lgN ) 最坏情况是n^2
  2. 它是一种分治的思想。分区( 把数据 分为两个子区, 小于基准数的排列到 左边 大于基准数的排列在右边。 )
  3. 重复重复上述动作分区( 引入递归 )
  1. 确定一个基准数。(左边第一个数)
  2. 从左往右扫,如果小于基准数则继续前行,直到找到第一个大于基准数的值。则保存这个数到右边。
  3. 从右向左扫,如果大于基准数着继续前行,直到找到第一个小于基准数的值,着包装这个数到左边。
  4. 重复上诉过程,即可把数据分为两区。

4.数组 - 图7

  1. public static void main(String[] args) {
  2. int[] data = {38,22,44,23,14,32,28,66,25,88,77,44};
  3. quickSort(data, 0, data.length - 1);
  4. System.out.println(Arrays.toString(data));
  5. }
  6. public static void quickSort( int data[] , int left, int right ){
  7. if( left<right ){
  8. int index = division(data,left,right);
  9. quickSort(data,left,index-1);
  10. quickSort(data,index+1,right);
  11. }
  12. }
  13. public static int division(int[] data , int left, int right){
  14. int pivot = data[left];
  15. while (left < right){
  16. while ( left < right && data[right] >= pivot )
  17. --right;
  18. data[left] = data[right];
  19. while (left<right && data[left] <= pivot )
  20. ++left;
  21. data[right]=data[left];
  22. }
  23. data[left]=pivot;
  24. return left;
  25. }

从数组中找到目标数据,如果寻找,又涉及到相关的算法,典型查找方法,比如线性 查找,或者折半查找。

6.6 线性查找

就是从头到尾查找,如果元素非常多,效率就不高。

  1. package find;
  2. import java.util.Arrays;
  3. //查找
  4. public class FindDemo {
  5. public static void main(String[] args) {
  6. String[] team = { "诸葛亮","刘备","关羽","大乔","小乔","曹操" };
  7. int index = lineFind(team,"吕布");
  8. System.out.println(index);
  9. //原数组
  10. int[] data = {1,3,46,367,312,11,567,44,22,56};
  11. //排序
  12. Arrays.sort(data);
  13. System.out.println(Arrays.toString(data));
  14. int index2 = binarySerach(data, 56);
  15. //int index2 = Arrays.binarySearch(data, 56);
  16. System.out.println(index2);
  17. }
  18. // 线性查找:更通用,可适用于各种数据类型
  19. public static int lineFind(String[] data, String key){
  20. for(int i=0; i<data.length; i++){
  21. if( data[i].equals(key) ){
  22. return i;
  23. }
  24. }
  25. return -1;
  26. }
  27. }

6.7 折半查找

就是 通过已经排好序的数组,先判断中间值,如果相等则返回,否则不断缩小查找范围

  1. package find;
  2. import java.util.Arrays;
  3. //查找
  4. public class FindDemo {
  5. public static void main(String[] args) {
  6. //原数组
  7. int[] data = {1,3,46,367,312,11,567,44,22,56};
  8. //排序
  9. Arrays.sort(data);
  10. System.out.println(Arrays.toString(data));
  11. int index2 = binarySerach(data, 56);
  12. //int index2 = Arrays.binarySearch(data, 56);
  13. System.out.println(index2);
  14. }
  15. // 二分查找:针对的是数字查找,且要求数字必须先排序。
  16. public static int binarySerach( int[] data , int key ){
  17. int left = 0; //左起点
  18. int right = data.length-1;//右终点
  19. //只要 左起点下标未超过右终点 继续,否则说明 移动交叉了不存在查找的数据 停止查找。
  20. while( left<=right ){
  21. //计算中间值下标
  22. int min = (left+right)/2;
  23. // 判断与中间值的大小
  24. if( key == data[min]){ // 查到了
  25. return min;
  26. }else if( key < data[min] ){ // 在左半轴查找
  27. right = min-1;
  28. }else{ // 在右半轴查找
  29. left = min+1;
  30. }
  31. }
  32. //没有找到
  33. return -1;
  34. }
  35. }

七 . 二维数组(了解)

7.1 概念

二维数组从空间上看是有行列组成的结构,但是实际在计算机中,二维数组本质上还是一个一维数组,只是这个一维数组的每个元素,都是一个数组。

7.2 内存理解

4.数组 - 图8
数组的每个元素保存的右是 另一个数组的地址。

7.3 创建和声明二维数组

  1. int[][] num = new int[3][5];
  2. num[0][1] = 20;
  3. num[0][2] = 30;
  4. num[0][3] = 40;
  5. num[1][2] = 20;
  6. num[2][4] = 10;
  7. for (int i = 0; i <num.length ; i++) {
  8. for (int j = 0; j < num[i].length; j++) {
  9. System.out.print(num[i][j]+"\t");
  10. }
  11. System.out.println();
  12. }

4.数组 - 图9

7.4 二维数组遍历

  1. public static void main(String[] args) {
  2. int[][] data = new int[3][3];
  3. //元素的访问:赋值
  4. data[0][0] = 1;
  5. data[0][1] = 2;
  6. data[0][2] = 3;
  7. data[1][0] = 4;
  8. data[1][1] = 5;
  9. data[1][2] = 6;
  10. data[2][0] = 7;
  11. data[2][1] = 8;
  12. data[2][2] = 9;
  13. // 普通for
  14. for(int i=0;i<data.length;i++){
  15. for(int j=0;j< data[i].length;j++ ){
  16. System.out.print(data[i][j]+"\t");
  17. }
  18. System.out.println();
  19. }
  20. // 增强for
  21. for( int[] arr : data ){
  22. for( int e :arr ){
  23. System.out.print(e+"\t");
  24. }
  25. System.out.println();
  26. }
  27. }

课后习题:

打印杨辉三角

  1. static void yanghui(int a){
  2. int[][] arr = new int[a][a];
  3. for (int i = 0; i <a ; i++) {
  4. arr[i][0]=1;
  5. arr[i][i]=1;
  6. }
  7. for (int i = 2; i <a ; i++) {
  8. for (int j = 1; j <i ; j++) {
  9. arr[i][j]=arr[i-1][j-1]+arr[i-1][j];
  10. }
  11. }
  12. for (int i = 0; i <arr.length ; i++) {
  13. for (int j = 0; j <arr.length-i-1; j++) {
  14. System.out.print(" ");
  15. }
  16. for (int j = 0; j <= i; j++) {
  17. System.out.print(arr[i][j]+" ");
  18. }
  19. System.out.println();
  20. }
  21. }
  1. public class Array2 {
  2. public static void main(String[] args)
  3. {
  4. int [] b; b=new int[]{11,22,33,44,55};
  5. avg(b);
  6. xiabiao(b);
  7. MaxAndMin(b);
  8. Reserve();
  9. weizhi();
  10. Day();
  11. sum_OuShu();
  12. }
  13. /*
  14. * 计算传入数组平均值
  15. * */
  16. static void avg(int[] a){
  17. double sum=0;
  18. double avg=0;
  19. for (int i = 0; i < a.length; i++)
  20. {
  21. sum+=a[i];
  22. }
  23. avg=sum/a.length;
  24. System.out.println("b数组的平均值为:"+avg);
  25. }
  26. /*
  27. * 计算传入数的下标
  28. * */
  29. static void xiabiao(int[] b){
  30. Scanner sc =new Scanner(System.in);
  31. System.out.print("请输入一个数:");
  32. int num =sc.nextInt();
  33. for (int i = 0; i < b.length; i++)
  34. {
  35. if (num==b[i]) System.out.println(num+"的下标为:"+i);
  36. }
  37. }
  38. /*
  39. * 找到最大值和最小值
  40. * */
  41. static void MaxAndMin(int[] b){
  42. int max = b[0];
  43. int min = b[0];
  44. for (int i = 0; i <b.length ; i++)
  45. {
  46. if(b[i]>max) max=b[i];
  47. if(b[i]<min) min=b[i];
  48. }
  49. System.out.println("MAX is "+max);
  50. System.out.println("MIN is "+min);
  51. }
  52. /*
  53. * 将数组元素颠倒
  54. * */
  55. static void Reserve(){
  56. int[] b; b=new int[]{11,22,33,44,55};
  57. int[] c =new int[b.length];
  58. for (int i = 0; i <b.length ; i++) {
  59. c[b.length-i-1]=b[i];
  60. }
  61. System.out.println("原数组");
  62. for (int i = 0; i <b.length ; i++) {
  63. System.out.print(b[i]+"\t");
  64. }
  65. System.out.print("\n反转");
  66. System.out.println();
  67. for (int i = 0; i <c.length ; i++) {
  68. System.out.print(c[i]+"\t");
  69. }
  70. System.out.println();
  71. }
  72. /*
  73. * 输出积分最少的数 和 位置
  74. * */
  75. static void weizhi(){
  76. int[] a = {18,25,7,36,13,2,89,63};
  77. int min = a[0];
  78. for (int i = 0; i <a.length ; i++)
  79. {
  80. if(a[i]<min) min=a[i];
  81. }
  82. for (int i = 0; i < a.length; i++)
  83. {
  84. if (min==a[i]) System.out.println("最少的积分为:"+min+"所在的下标为:"+i+1);
  85. }
  86. }
  87. /*
  88. * 输一个日期,输出这个日期是这年的第几天
  89. * */
  90. static void Day() {
  91. Scanner sc = new Scanner(System.in);
  92. System.out.print("请输入年份:");
  93. int year =sc.nextInt();
  94. System.out.print("请输入月份:");
  95. int month = sc.nextInt();
  96. System.out.print("请输入天数:");
  97. int day = sc.nextInt();
  98. if((year%4==0&&year%100!=0)||year%400==0){
  99. int sum=0;
  100. int[] arr1 = {31,29,31,30,31,30,31,31,30,31,30,31};
  101. for (int i = 0; i < month-1; i++) {
  102. sum+=arr1[i];
  103. }
  104. sum=sum+day;
  105. System.out.println(year+"年"+month+"月"+day+"日"+"是一年中的+"+sum+"天");
  106. }else{
  107. int sum=0;
  108. int[] arr2 = {31,28,31,30,31,30,31,31,30,31,30,31};
  109. for (int i = 0; i < month-1; i++) {
  110. sum+=arr2[i];
  111. }
  112. sum=sum+day;
  113. System.out.println(year+"年"+month+"月"+day+"日"+"是一年中的"+sum+"天");
  114. }
  115. }
  116. /*
  117. * 求出下标为偶数和
  118. * */
  119. static void sum_OuShu(){
  120. Scanner sc = new Scanner(System.in);
  121. int[] arr = new int[10];
  122. for (int i = 0; i <10 ; i++) {
  123. System.out.print("请输入第"+(i+1)+"个数字:");
  124. arr[i] = sc.nextInt();
  125. }
  126. int sum=0;
  127. for (int i = 0; i <arr.length ; i+=2) {
  128. sum+=arr[i];
  129. }
  130. System.out.println("下标为偶数的元素之和为:"+sum);
  131. }
  132. }

补充