写在最前

学习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是否仍为初始值即刻得知找没找到目标数

【Java复健指南01】简介与数组的更多相关文章

  1. 【Java复健指南09】项目练习全解--房屋出租系统

    一个基于文本界面的综合练习,主要用于串联和回忆知识点,比较简单 各个界面的设计样式 主菜单 =============房屋出租系统菜单============ 1 新 增 房 源 2 查 找 房 屋 ...

  2. 【Java复健指南15】链表LinkedList及其说明

    链表LinkedList by Java 之前有写过一些记录(引用),但是忘了乱了,现在重新梳理一遍 链表是Java中List接口的一种实现 定义(引用) 链表(linked list)是一种物理存储 ...

  3. Java Gradle入门指南之简介、安装与任务管理

        这是一篇Java Gradle入门级的随笔,主要介绍Gradle的安装与基本语法,这些内容是理解和创建build.gradle的基础,关于Gradle各种插件的使用将会在其他随笔中介绍.    ...

  4. Java单体应用 - Markdown - 01.简介

    原文地址:http://www.work100.net/training/monolithic-markdown.html 更多教程:光束云 - 免费课程 简介 序号 文内章节 视频 1 概述 2 特 ...

  5. Swift动画编程指南-01 简介

    大家好,我是老镇,这段时间家里和工作上发生了很多的事情,所以很长一段时间都没有出来搞什么小动作了.在接下来的一段时间内我会制作一些列关于使用Swift进行动画编程的视频,希望和大家胃口. 在iOS的世 ...

  6. 069 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 01 综合案例-数组移位-案例需求

    069 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 01 综合案例-数组移位-案例需求 本文知识点:综合案例-数组移位-案例需求 说明:因为时间紧张,本人写博客 ...

  7. 062 01 Android 零基础入门 01 Java基础语法 07 Java二维数组 01 二维数组应用

    062 01 Android 零基础入门 01 Java基础语法 07 Java二维数组 01 二维数组应用 本文知识点:二维数组应用 二维数组的声明和创建 ? 出现空指针异常 数组的名字指向数组的第 ...

  8. 【系列】Java多线程初学者指南(1):线程简介

    原文地址:http://www.blogjava.net/nokiaguy/archive/2009/nokiaguy/archive/2009/03/archive/2009/03/19/26075 ...

  9. Java工程师学习指南 完结篇

    Java工程师学习指南 完结篇 先声明一点,文章里面不会详细到每一步怎么操作,只会提供大致的思路和方向,给大家以启发,如果真的要一步一步指导操作的话,那至少需要一本书的厚度啦. 因为笔者还只是一名在校 ...

  10. Java工程师学习指南 入门篇

    Java工程师学习指南 入门篇 最近有很多小伙伴来问我,Java小白如何入门,如何安排学习路线,每一步应该怎么走比较好.原本我以为之前的几篇文章已经可以解决大家的问题了,其实不然,因为我之前写的文章都 ...

随机推荐

  1. [转帖]linux shell 脚本一些主要知识点整理

    文章目录 一./bin/sh 与 /bin/bash 的区别 二.vi与vim的区别 三.shell变量 四.Shell字符串 五.Shell函数 六.Shell基本运算符 1.Shell expr: ...

  2. Docker 安装Oracle12c的镜像修改字符集 并且进行启动的简单过程

    学习来自 昨天晚上转帖的文章 这里面添加一些自己的内容 首先获取配置文件 git clone https://github.com/oracle/docker-images.git 获取之后比较容易了 ...

  3. 金蝶Cosmic虚拟机简单使用与总结

    背景 知己知彼 简单学习下友商发出来的测试软件 看看有否对自己现在的工作有所指导 也看看对方的部署方式有啥优缺点 当然了仅是测试, 不是生产软件可能有失真. 注意 我没有测试序列号, 登录系统耗时很久 ...

  4. 总结: Redis 查看key大小的简单总结

    Redis 查看key大小的简单总结 第一步: 安装rdbtools 吐槽一下 python 非常不熟悉 第一步 安装epel以及python等工具 yum install epel-release ...

  5. 超级好用的elementui动态循环菜单

    <template> <div> <el-menu @select="selectMenu" :default-active="curren ...

  6. 一文总结现代 C++ 中的初始化

    本文尝试回答: 现代 C++ 有哪几种初始化形式?分别能够用于什么场景?有什么限制? MyClass obj(); 为什么没有调用默认无参构造函数创建一个对象? new int 和 new int() ...

  7. C/C++ 原生套接字抓取FTP数据包

    网络通信在今天的信息时代中扮演着至关重要的角色,而对网络数据包进行捕获与分析则是网络管理.网络安全等领域中不可或缺的一项技术.本文将深入介绍基于原始套接字的网络数据包捕获与分析工具,通过实时监控网络流 ...

  8. 1.7 完善自定位ShellCode

    在之前的文章中,我们实现了一个正向的匿名管道ShellCode后门,为了保证文章的简洁易懂并没有增加针对调用函数的动态定位功能,此类方法在更换系统后则由于地址变化导致我们的后门无法正常使用,接下来将实 ...

  9. Metasploit 生成各种后门

    Metasploit 是一款开源的安全漏洞检测工具,可以帮助安全和IT专业人士识别安全性问题,验证漏洞的缓解措施,同时该工具也是渗透测试环境中的利器,它支持多平台Payload的生成具有完全的跨平台性 ...

  10. linux 后台运行进程:& , nohup

    目录 后台执行 & nohup 查看后台运行的命令 jobs ps 关闭当前后台运行的程序 kill 前后台进程的切换与控制 ctrl + z 命令 fg 命令 bg 命令 思考 问题1-为什 ...