【Java复健指南01】简介与数组

写在最前

学习Java已经是很久之前的事情了,因为技术栈的转变,很久没有使用Java正经地开发过项目。

对于该语言的理解也是停留在表面,因此萌生了重新学习的念头。一方面是为刷算法题打基础,另一方面也是想拓展一下自己的技术栈(要不然失业了都)

既然我的目标是“复健”,那么显然不可能完全重新学习记录一遍。当初学习Java的目的是为了开发Android和制作Minecraft的mod,一些Java的高级部分涉及不多。

因此,本次学习以Java每个部分(从数组往后的)的关键知识点作为展开,会着重记录:

  • 相应部分的一些易错点和对应的练习
  • 编程思想与处理问题的trick
  • 典型的算法题的解法、优化和总结(Java、Python版本)

开始吧~

【数组】

数组的分配方式

一维:

int[] arr = new int[5]; //动态分配

int arr[];
arr = new arr[5];//先定义,后使用

int[] arr = {1,2,3};//直接分配

二维:

int[][] arr = new int[3][2]; //基本用法

int[][] arr = new int[3][]; //后分配数组列数,可用于循环

// 动态初始化
int arr[];//声明二维数组
arr new int[2][3];//再开空间

int[][] arr = {{1,2},{6,7}};//直接分配

数组拷贝

对于基本的数据类型,其赋值过程为值拷贝,赋值完成后修改被赋值变量不会影响原变量的值

而数组不一样

数组被定义之后会开辟一块相应的内存空间,然后该空间的地址传回给数组变量arr1

当数组arr1被拷贝,arr1会复制当前的地址给被赋值的数组变量arr2(该地址指向的空间仍为之前为arr1开辟的那个

因此,当我们对arr2的值进行修改,会影响arr1的值,因为两者指向的实际地址空间一致

数组细节

  • 数组是多个相同类型数据的组合,实现对这些数据的统一管理

  • 数组中的元素可以是任何数据类型,包括基本类型和引用类型,但是不能混用

  • 数组创建后,如果没有赋值,有默认值如下:

    int 0, short 0, byte 0, long 0, float 0.0, double 0.0 ,boolean false, String null
    
  • 数组下标必须在指定范围内使用,否则报:下标越界异常,比如

    int arr=new int[5];//则有效下标为0-4
    
  • 使用数组的步骤
    (1)声明数组并开辟空间
    (2)给数组各个元素赋值
    (3)使用数组

一维数组练习

数组翻转

思路1:

​ 从数组的头部和尾部两个方向向数组中间位置推进,过程中不断交换数组元素

public class ArrayReverse{
	public static void main(String[] agrs){
		/*
		要求:把数组的元素内容反转。
		例如:arr {11,22,33,44,55,66}→{66,55,44,33,22,11}
		思路1:
		规律
		1.把arr[0]和arr[5]进行交换{66,22,33,44,55,11}
		2.把arr[1]和arr[4]进行交换{66,55,33,44,22,11}
		3.把arr[2]和arr[3]进行交换{66,55,44,33,22,11}
		4.一共要交换3次 = arr.length/ 2
		5.每次交换时,对应的下标是arr[i](0,1,2)和arr[arr.length - 1 -i](5,4,3)
		*/
		//定义一个数组
		int[] arr = {11,22,33,44,55,66,77};
                int temp = 0;//临时变量
                for(int i = 0; i < arr.length / 2; i++){
                    arr[arr.length - 1 - i] = temp;
                    arr[arr.length - 1 - i] = arr[i];
                    arr[i] = temp;
                }
                System.out.println("====翻转后的数组====");
		for(int i = 0; i<arr.length; i++){
			System.out.print(arr[i] + "\t");
		}

	}
}

两个注意点:

  • 循环范围是数组长度的一半。这里不论数组的元素个数是单/双数都没关系(反正取整都一样),单数的话中间的那个元素是不用动的(因为不是排序)
  • 循环过程中的元素下标。
    • i表示从数组头部开始向数组尾部的方向;
    • 数组长度-i表示从尾部到头部的方向;

思路2:逆序遍历。即逆序遍历待翻转的数组,然后再顺序存入一个新数组中,最后使原数组指向新数组

 public class ArrayReverse02{
	public static void main(String[] agrs){
		/*
		思路2:
		逆序遍历
		1、逆序遍历待翻转的数组
		2、顺序存入一个新数组内
		3、将原数组的地址指向新数组(旧数组垃圾回收)
		4、在循环中增加一个顺序增加的变量j
		*/
            int[] arr = {11,22,33,44,55,66,77};
            int[] arr2 = new int[arr.length];
            for(int i = arr.length - 1, j = 0; i > = 0; i--, j++){
                arr2[j] = arr[i];
            }
	    arr = arr2;//舍弃旧数组
        
            System.out.println("====翻转后的数组====");
	    for(int i = 0; i < arr.length; i++){
		System.out.print(arr[i] + "\t");
	    }

	}
}

一个注意点:

  • 在循环中,循环变量可以有两个;

冒泡排序

思路:

就是冒泡法的思路。遍历数组,当前的数与下一个数进行比较,若当前数大则与下一个数交换,继续比。若后一个数较大,则指针后移,重复之前的操作。最终的目的是将当前最大的数往数组的末尾移动,完成第一次移动后,我们需要找到第二大的数移动至数组的次末尾,重复上述过程直到排序完成。

因此,排序是分多轮进行的,每轮只能将一个数送至数组的末尾(相对意义上的末尾)

public class BubbleSort{
	public static void main(String[] agrs){
		/*
		将五个无序数24,68,80,57,13使用冒泡排序法排成一个
		从小到大的有序数列

		数组{24,69,80,57,13}
		第1轮排序:目标把最大数放在最后
		第1次比较[24,69,80,57,13]
		第2次比较[24,69,80,57,13]
		第3次比较[24,69,57,80,13]
		第4次比较[24,69,57,13,80]
		*/
		int[] arr = {24,69,80,57,13};
                int temp = 0;
                for(int i = 0; i < arr.length - 1; i++){
                    for(int j = 0; j < arr.length - 1 - i; j++){
                        if(arr[j]>arr[j+1]){
                            temp = arr[j+1];
                            arr[j+1] = arr[j];
                            arr[j] = temp;
                            /*
                              temp = arr[j];
			      arr[j] = arr[j+1];
			      arr[j+1] = temp;
                            */
                         }
        	     }
                System.out.println("\n====第"+(i+1)+"轮====");
		for(int j = 0;j < arr.length; j++) {
		    System.out.print(arr[j]+"\t");
		}
        } 
    }
}

几个注意点:

  • 从最基本(核心)的功能开始写,即实现数组前后两个数的比较和交换,然后再考虑重复上述过程
  • 使用临时变量交换的逻辑不要搞混
  • 从第二轮排序开始,其实需要比较的次数是不断变少的,这点体现再内层循环的条件中,即减掉外层循环当前的循环变量,这是一种常规思想

二维数组练习

打印杨辉三角

使用二维数组打印一个10行杨辉三角
			1
			1 1
			1 2 1
			1 3 3  1
			1 4 6  4  1
			1 5 10 10 5 1
		
		【提示】
			1.第一行有1个元素,第n行有n个元素
			2.每一行的第一个元素和最后一个元素都是1
			3.从第三行开始,对于非第一个元素和最后一个元素的元素的值
			  arr[i][j] = arr[i-1][j] + arr[i-1][j-1];

思路:先打印一个从上至下元素(数组长度)增加的三角,然后依据规律往里填数

public class YangHui{
	public static void main(String[] agrs){
		
        int[][] arr = new int[10][];
        for(int i = 0; i < arr.length; i++){
            arr[i] = new int[i + 1];//获得一堆三角形数组
            //判断当前的数是否为第三行后数组的第一个数或最后一个数
            for(int j = 0; j < arr[i].length){
                if(j == 0 || j == arr[i].length){
                	arr[i][j] = 1;
                }else{
			arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
                }
            }
            
        }
        System.out.println("杨辉三角");
		for(int i = 0; i < arr.length; i++){
			for(int j = 0; j < arr[i].length; j++){
				System.out.print(arr[i][j] + "\t");
			}
			System.out.println();
		}
	}
}

一个注意点:

  • 二维数组先定义外层,之后再定义内层数组元素是常规用法,这题中有体现

    • 例如

    • //创建二维数组,一共有3个一维数组,
      //但是每个一维数组还没有开辟数值空间
      int[][] arr = new int[3][];//列数不确定
      for(int i = 0; i < arr.length; i++){
      	//给每个一维数组开空间new
      	//如果没有给一维数组new ,那么arr[i]就是null
      	arr[i] = new int[i + 1];
      
      	//遍历一维数组,并给一维数组的每个元秦赋值
      	for(int j = 0; j < arr[i].length; j++){
      		arr[i][j] = i + 1;//赋值
      		}
      
      }
      

数组习题

习题一

已知有个升序的数组,要求插入一个元素,该数组顺序依然是升序,比如:[10,12,45,90],添加23后,数组为[10,12,23,45,90]

思路1:

1、定义一个变量用于接收插入的数
2、遍历数组,与待插入的数比较大小若插入的数小于数组当前遍历到的值,则插入

public class Homework04{
	public static void main(String[] agrs){
		//我的解法
		int[] arr = {10,12,45,90};
		int[] arrNew = new int[arr.length + 1];//用于存放扩充后元素的数组
		int ins = 89;//插入值
		int flag = 0;//用于确定是否插入值的标志位

		System.out.println("====插入元素前的arr====");
		for(int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}

		for(int i = 0; i < arr.length; i++){
			if(arr[i] > ins && flag == 0){
				arrNew[i] = ins;//满足条件,插入元素
				flag = 1;
				arrNew[i + 1] = arr[i];//将原本应在当前位置的元素顺延至后一个位置
			}else if (flag == 1) {
				arrNew[i + 1] = arr[i];
			}else{
				arrNew[i] = arr[i]; 
			}
		}
		arr = arrNew;

		System.out.println("====插入元素后的arr====");
		for(int i =0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}

	}
}

思路2(标准解法):

本质数组扩容+定位

1.我们先确定添加数应该插入到哪个索引
2.然后扩容

public class Homework04{
	public static void main(String[] agrs){
		//先定义原数组
		int[]arr = {10,12,45, 90};
		int insertNum = 23;
		int index = -1; //index就是要插入的位置
		//遍历arr数组,如果发现insertNum<=arr[i],说明i就是要插入的位置
		//使用index保留index = i;
		//如果遍历 完后,没有发现insertNum<=arr[i],说明index = arr.length
		//即:添加到arr的最后

		for(int i = 0; i < arr. length; i++) {
			if(insertNum<= arr[i]){
				index = i;
				break;//找到位置后,就退出
			}
		}

		//判断index的值
		if(index == -1) {//说明没有还没有找到位置
			index = arr. length;
		}
		// System.out.println("index=" + index);

		//扩容
		//先创建一个新的数组,大小arr.length + 1
		int[]arrNew = new int[arr.length + 1];
		//下面准备将arr的元素拷贝到arrNew ,并且要跳过index位置

		for(int i = 0, j = 0; i < arrNew.length; i++) {
			if( i != index ) {//说明可以把arr的元素拷贝到arrNew
				arrNew[i]= arr[j];
				j++;
			}else {//i这个位置就是要插入的数
				arrNew[i] = insertNum;
			}
		}
	}
}

习题二

随机生成10个整数(1_100的范围)保存到数组,并倒序打印以及求平均值、求最大值和最大值的下标并查找里面是否有8

public class Homework05{
	public static void main(String[] agrs){
		/*		
		我的思路:
		0、定义一个长度为10的数组
		1、(导入)随机数模块random
		2、通过循环调用random产生10个随机数并保存至数组
		3、定义存放平均值的变量average
		  定义存放最大/小值下标的变量Maxindex/Minindex
		*/

		int[]arr = new int[10];
		//(int)(Math.random() 100)+1 生产随机数1-100
		for(int i = e; i < arr.length; i++){
			arr[i]=(int)(Math.random()*100)+1;
		}

		System.out.println("====arr的元素情况=====");
		for(int i = 0; i < arr.length; i++){
			System.out.print(arr[i]+"\t");
		}

		System.out.println("in====arr的元素情况(倒序)=====");
		for(int i =arr.length -1; i >= 0; i--){
			System.out.print(arr[i]+ "\t");
		}
		//平均值、求最大值和最大值的下标
		//
		double sum = 0;
		int max = arr[0];
		int maxIndex = 0;
		for(int i = 1; i < arr. length; i++ ){
			
			sum += arr[i];

			if(max < arr[i]){//说明max不是最大值,就变化
			max = arr[i];
			maxIndex = i;
			}
		}
		System.out.println("\nmax=" + max + " maxIndex=" +maxIndex);
		System.out.print1n("\n平均值="+(sum / arr.length);


		//查找数组中是否有8->使用顺序查找
        int findNum = 8;
		int index = -1;//如果找到,就把下标记录到index
		for(int i = 0; i < arr.length; i+){
			if(findNum == arr[i){
				System.out.println(“找到数"+findNum + ”下标="+i);
				index = i;
				break;
			}
		}
		if(index == -1){
			System.out.println("没有找到数"+findNum );
		}
	}
}

注意:

本题中有两个常用的手法

1、找出数组中的最大/小值

设置一个变量保存最值,先指定数组的第一个值为最大值,设定一个变量用于记录最值下标。

遍历数组,然后将当前遍历值与设定最大值比较

若发现更大值则更新最值变量和下标变量即可

2、寻找数组中的某个值

设置一个变量用于存放要找的目标值

设置一个变量用于存放下标,初始值为-1

关键点

遍历数组,若找到目标数,返回提示并将下标保存

即刻结束循环遍历

若没有找到,遍历会结束,此时只需判断index是否仍为初始值即刻得知找没找到目标数

posted @ 2022-10-09 13:52  dayceng  阅读(82)  评论(0编辑  收藏  举报