文章目录
内存
Java将所占用的内存划分为了5块:栈内存、堆内存、方法区、本地方法栈、PC计数器(寄存器)
栈内存
用于存储变量的。变量在栈内存使用完成之后会立即移除出栈内存。
堆内存
用于存储对象(数组是一种特殊的对象)的。
元素在存入堆内存中之后会自动的赋予默认值:byte/short/int-0 long-0L float-0.0f double-0.0 char-‘\u0000’ boolean-false,其他类型的默认值都是null。
对象在用完之后是在不确定的某个时刻被回收。
logab = logcb/logca logabn = nlogab logab = loga + logb
数组
一维数组
- 存储同一类型的多个数据的容器—大小是固定的
- 有编号,下标是从0开始
- 定义格式:
数据类型[] 数组名 = new 数据类型[长度]; int[] arr = new int[5];
数据类型[] 数组名 = new 数据类型[]{元素1, 元素2, …}; — 不允许分开定义;
int[] arr;
arr = new int[5];
arr = new int[]{5,1,7,0,8,1,3};
//arr = {3,1,7,3,8,0,4};错的
数组的应用:
操作指定位置上的元素:数组名[下标]
获取数组的长度:数组名.length
遍历数组
// 方式一:下标是从0->length - 1
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
// 方式二:直接获取每一个位置上的元素
// 增强for循环
// 只能遍历数组但是不能改变数组中的元素
for(int i : arr){
System.out.println(i);
}
// 方式三:将数组中的元素一个个的拿出来拼接成字符串
String str = Arrays.toString(arr);
System.out.println(str);
获取数组中最值(最大值/最小值)
// 获取最大值
/*
int max = arr[0];
for(int i = 1; i < arr.length; i++){
if(max < arr[i])
max = arr[i];
}
System.out.println(max);
*/
int max = 0;
for(int i = 1; i < arr.length; i++){
if(arr[max] < arr[i])
max = i;
}
数组的排序
目录,再往上一拉
时间复杂度:在程序中找一段必然会执行的代码,将这段代码的执行时间认为是单位1,执行这个单位1需要的次数就是时间复杂度 - 时间复杂度不考虑系数,一般来说是找最高阶 -> O(nx), O((logn)x),O(nx(logn)y)
空间复杂度:这段程序执行所需要额外耗费的空间就是空间复杂度
扩展:冒泡排序和选择排序都是稳定的排序算法 — 排序算法的稳定与否的依据是相等的元素在排序的时候是否需要交换
import java.util.Arrays;
public class ArraySortDemo {
public static void main(String[] args){
int[] arr = {5,1,7,0,8,2,6};
// 冒泡排序
// 定义一个循环控制轮数
/*
for(int i = 1; i < arr.length; i++){
// 定义一个循环控制每一个轮的次数
for(int j = 1; j <= arr.length - i; j++){
if(arr[j - 1] > arr[j]){
int temp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = temp;
}
}
}
*/
// 选择排序
// 控制轮数
/*
for(int i = 1; i < arr.length; i++){
// 控制每一轮要比较的下标
for(int j = i; j < arr.length; j++){
// 拿选定的下标上的元素和比较的下标上的元素进行比较
if(arr[i - 1] > arr[j]){
int temp = arr[i - 1];
arr[i - 1] = arr[j];
arr[j] = temp;
}
}
}
*/
// 只能进行升序排序
// 扩展:底层用的是快速排序+归并排序
// 时间复杂度:O(nlogn)
Arrays.sort(arr);
}
反转数组
// 反转数组
// 方式一:
// 时间复杂度O(n),空间复杂度o(n)
/*
int[] newArr = new int[arr.length];
for(int i = arr.length - 1, j = 0; i >= 0; i--, j++){
newArr[j] = arr[i];
}
*/
// 方式二:头尾交换
// 时间复杂度O(n),空间复杂度o(1)
for(int i = 0, j = arr.length - 1; i <= j; i++, j--){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
System.out.println(Arrays.toString(arr));
}
数组元素的查找:
数组元素无序的前提下,获取一个元素的位置只能通过遍历的方式一一比较。
如果数组元素有序,使用二分查找 — 空间复杂度o(1),时间复杂度O(logn)
2x = n -> x = log2n -> logn — 默认以2为底数
import java.util.Scanner;
public class ArraySearchDemo {
public static void main(String[] args){
/*
int[] arr = {5,1,7,0,8,2,6};
Scanner s = new Scanner(System.in);
int n = s.nextInt();
// 定义一个变量记录位置
// 规定如果找不到这个元素,将下标记录-1
int index = -1;
for(int i = 0; i < arr.length; i++){
if(arr[i] == n){
index = i;
break;
}
}
System.out.println(index);
*/
// 二分查找/折半查找
// 空间复杂度:o(1)
int[] arr = {5,9,15,16,28,37,45,48,56,59,60};
Scanner s = new Scanner(System.in);
int n = s.nextInt();
// 记录最小值的下标
int min = 0;
// 记录最大值的下标
int max = arr.length - 1;
int mid = (max + min) / 2;
while(arr[mid] != n){
if(arr[mid] > n)
max = mid - 1;
else
min = mid + 1;
if(min > max){
mid = -1;
break;
}
mid = (min + max) / 2;
}
System.out.println(mid);
}
}
数组的复制和扩容
// 数组的扩容 --- 数组的复制 --- 产生一个新的数组,导致扩容之后的数组和原数组不是同一个
// System.arraycopy(要复制的数组, 要复制的起始下标, 存放的数组, 要存放的起始下标, 个数);
int[] arr = {3,6,1,7,9};
int[] newArr = new int[8];
System.arraycopy(arr, 0, newArr, 0, arr.length);
arr = newArr;
// 它的底层实现逻辑就是上面的代码 --- System.arraycopy(arr, 0, newArr, 0, arr.length);
arr = Arrays.copyOf(arr, 8);
二维数组
定义:
- 数据类型[][] 数组名 = new 数据类型[包含的一维数组的个数][每一个一维数组的长度];
- 数据类型[][] 数组名 = new 数据类型[包含的一维数组的个数][];
- int[][] arr = new int[5][]; 定义了一个能存储5个整型一维数组的二维数组 — 必须先保证这一位上的一维数组先给定大小,然后再给值
arr[0] = new int[3];
arr[1] = new int[7];
arr[2] = new int[2]; - 数据类型[][] 数组名 = {{数组1}, {数组2}, {数组3},…};
- 注意:[]如果在变量名之前那么紧跟数据类型,会影响其他的变量,也就意味着后面定义的变量实际上都是数组;但如果[]在变量名之后,那么[]只管跟着的这个变量不会去影响其他的变量。
// int[] x, y[],z;
// int[] y[];
// x是一维数组,y是二维数组
// int x[], y[], z;
遍历
// 遍历二维数组
/*
for(int i = 0; i < arr.length; i++){
for(int j = 0; j < arr[i].length; j++){
System.out.println(arr[i][j]);
}
}
*/
内存存储
杨辉三角
目录,再往上一拉
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
特点:每一行的开始和结束都是1;其余位置的元素是计算:
arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
输入一个数字n表示行数,输出对应的前n行
import java.util.Scanner;
public class ArrayExer {
public static void main(String[] args){
// 获取行数
Scanner s = new Scanner(System.in);
int row = s.nextInt();
// 定义二维数组来存储杨辉三角
int[][] arr = new int[row][];
// 遍历数组,向里填充元素
for(int i = 0; i < row; i++){
// 先给每一个一维数组定义大小
arr[i] = new int[i + 1];
// 遍历这个一维数组,向里填充元素
for(int j = 0; j <= i; j++){
// 判断头尾元素
if(j == 0 || j == i)
arr[i][j] = 1;
else
arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
// 填充完成之后打印这个填充的元素
System.out.print(arr[i][j] + "\t");
}
System.out.println();
}
}
}
需注意的小知识点
- 数组在赋值的时候给的也是地址
- 如果没有指定一维数组的大小,那么二维数组的位置上存储得是null