相信很多同行小伙伴会因为许多原因想跳槽,不论是干得不开心还是想跳槽涨薪,在如此内卷的行业,我们都面临着“面试造火箭,上班拧螺丝”的局面,鉴于当前形势博主呕心沥血整理的干货满满的造火箭的技巧来了,本博主花费2个月时间,整理归纳java全生态知识体系常见面试题!总字数高达百万! 干货满满,每天更新,关注我,不迷路,用强大的归纳总结,全新全细致的讲解来留住各位猿友的关注,希望能够帮助各位猿友在应付面试笔试上!当然如有归纳总结错误之处请各位指出修正!如有侵权请联系博主QQ1062141499!
目录
1 JAVA中数组扩容的三种方式
① int[] arr2=new int[arr1.length*2] //新数组长度
for(int i=0;i<arr1.length;i++){ //复制
arr2[i]=arr1[i];
}
② int[] arr2=java.util.Arrays.copyOf(原数组名,新数组长度);
③ int[] arr2=new int[arr1.length*2]
System.arraycopy(原数组名,起始下标,新数组名,起始下标,复制长度);
2 冒泡排序(Bubble Sort)
冒泡排序是一种简单的排序算法。
步骤:
- 遍历比较相邻的两个元素,被比较的左边元素大于右边元素,则交换位置。第一轮遍历、比较、交换完,最后一个是最大的元素
- 若本次遍历中没有数据交换,代表排序结束,提前退出
- 有数据交换则再从第一个元素开始遍历、比较、交换,排除最后一个元素
- 重复 1、2、3 步骤,每次排除上次被遍历的最后一个元素,直到排序完成
public static void main(String[] args) {
int[] ints = {3, 4, 23, 11, 0, 3, 4};
bubbleSort(ints);
}
/**
* 冒泡排序算法
* 只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。
* 如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复n 次,
* 就完成了 n 个数据的排序工作。
**/
private static void bubbleSort(int[] ints) {
//临时交换的数据
int temp;
for (int i = 0; i < ints.length; i++) {
//j<ints.length-i-1,因为冒泡是把每轮循环中较大的数飘到后面
for (int j = 0; j < ints.length - i - 1; j++) {
if (ints[j] > ints[j + 1]) {
temp = ints[j];
ints[j] = ints[j + 1];
ints[j + 1] = temp;
}
}
System.out.println(Arrays.toString(ints));
}
}
打印结果:
[3, 4, 11, 0, 3, 4, 23]
[3, 4, 0, 3, 4, 11, 23]
[3, 0, 3, 4, 4, 11, 23]
[0, 3, 3, 4, 4, 11, 23]
[0, 3, 3, 4, 4, 11, 23]
[0, 3, 3, 4, 4, 11, 23]
[0, 3, 3, 4, 4, 11, 23]
3 插入排序(Insertion Sort)
思路:
- 将数组分为两个区域:已排序、未排序。
- 初始已排序区域只第一个元素
- 取未排序的区域的元素,在已排序的区域找到合适的位置插入
- 保证已排序区域的数据一直有序
- 重复这个过程,直到未排序区域为空
步骤:
- 从数组第二个数开始,往后逐个取数,跟前面的数进行比较
- 当所取的数,比前面的数大,停止比较,取一下个进行比较
- 当所取的数,比前面的数小,把比所取数大的数都往后挪一个,直到所取数大于被比较的数停止,最后把所取数插入到比它小的数的右边
代码:
public static void main(String[] args) {
int[] ints = {3, 4, 23, 11, 0, 3, 4};
insertionSort(ints);
}
/**
* 插入排序
*/
private static void insertionSort(int[] ints) {
for (int i = 1; i <ints.length; i++) {
int j = i - 1;
int value = ints[i];
for (; j >= 0; j--) {
if (ints[j] > value) {
ints[j+1] = ints[j];
} else {
break;
}
}
ints[j+1] = value;
System.out.println(Arrays.toString(ints));
}
}
}
打印
[3, 4, 23, 11, 0, 3, 4]
[3, 4, 23, 11, 0, 3, 4]
[3, 4, 11, 23, 0, 3, 4]
[0, 3, 4, 11, 23, 3, 4]
[0, 3, 3, 4, 11, 23, 4]
[0, 3, 3, 4, 4, 11, 23]
特征:
- 最好情况时间复杂度:O(n) 。即数组本身有序,如 1,2,3,4,5
- 最坏情况时间复杂度:O(n2) 。即数组本身完全逆序,如 5,4,3,2,1
- 平均时间复杂度:O(n2) 。在数组中插入一个数据的平均时间复杂度是 O(n),插入排序执行 n 次往数组中插入操作,所以平均时间复杂度是 O(n2)
- 空间复杂度是 O(1)。是原地排序
- 可以保持相等的值原有的前后顺序不变,是稳定排序
4 选择排序(Selection Sort)
思路:
- 数组区分已排序区域和未排序区域
- 每次从未排序区域找到最小的元素,通过和未排序区域第一个元素交换位置,把它放到已排序区域的末尾
步骤:
- 进行 数组长度-1 轮比较
- 每轮找到未排序区最小值的小标
- 如果最小值的下标非未排序区第一个,进行交换。此时未排序区第一个则变为已排序区最后一个
- 进行下一轮找未排序区最小值下标,直到全部已排序
代码:
public static void main(String[] args) {
int[] ints = {3, 4, 23, 11, 0, 3, 4};
selectionSort(ints);
}
/**
* 选择排序
*/
public static void selectionSort(int[] ints) {
//进行 数组长度-1 轮比较
int minIndex;
for (int i = 0; i < ints.length - 1; i++) {
minIndex = i;//取未排序区第一个数的下标
for (int j = i + 1; j < ints.length; j++) {
if (ints[j] < ints[minIndex]) {
//找到未排序区域最小值的下标
minIndex = j;
}
}
//找到的最小值是否需要挪动
if (i != minIndex) {
int temp = ints[i];
ints[i] = ints[minIndex];
ints[minIndex] = temp;
}
System.out.println(Arrays.toString(ints));
}
}
打印
[0, 4, 23, 11, 3, 3, 4]
[0, 3, 23, 11, 4, 3, 4]
[0, 3, 3, 11, 4, 23, 4]
[0, 3, 3, 4, 11, 23, 4]
[0, 3, 3, 4, 4, 23, 11]
[0, 3, 3, 4, 4, 11, 23]
特征:
- 空间复杂度为 O(1),是原地排序算法
- 最好情况时间复杂度为 O(n2)。即使是有序数组,也需要经过 n-1 轮找未排序区最小值下标
- 最坏情况时间复杂度为 O(n2)
- 平均情况时间复杂度为 O(n2)
- 非稳定排序,即排序后不能保证两个相等值的前后顺序未变。如:4,8,4,2,9。第一轮找到最小元素 2,跟第一个 4 交换位置,直到排序完成第一个 4 排在第二个 4 后面
5 希尔排序(Shell Sort)
插入排序经过改进之后的高效版本,也称缩小增量排序。1959 年提出,是突破时间复杂度 O(n2) 的第一批算法之一。缩小增量排序的最优增量选择是一个数学难题,一般采用希尔建议的增量,具体如下。
思路与步骤:
- 首次选择的增量(即步长,下同) step = 数组长度 / 2 取整;缩小增量 step ,每次减半,直到为 1 结束缩小;逐渐缩小的增量组成一个序列:[n/2, n/2/2, ... 1]
- 对数组进行 序列里增量的个数 趟排序
- 每趟排序,把增量作为间隔,将数组分割成若干子数组,分别对各子数组进行插入排序
- 当增量等于 1 时,排序整个数组后,排序完成
代码:
public static void main(String[] args) {
int[] ints = {3, 4, 23, 11, 0, 3, 4};
selectionSort(ints);
}
/**
* 希尔排序
*/
private static void shellSort(int[] ints) {
int length = ints.length;
int step = length / 2; //步长,默认取数组长度一半
int temp;
while (step > 0) {
for (int i = step; i < length; i++) { //从步长值为下标,开始遍历
temp = ints[i]; //当前值
int preIndex = i - step; //步长间隔上一个值的下标
//在步长间隔的的数组中,找到需要插入的位置,挪动右边的数
while (preIndex >= 0 && ints[preIndex] > temp) {
ints[preIndex + step] = ints[preIndex];
preIndex -= step;
}
//把当前值插入到在步长间隔的的数组中找到的位置
ints[preIndex + step] = temp;
}
step /= 2;
System.out.println(Arrays.toString(ints));
}
}
打印
[3, 0, 23, 6, 4, 33, 11]
[0, 3, 4, 6, 11, 23, 33]
特征:
- 空间复杂度为 O(1),是原地排序算法
- 最好、最坏、平均情况时间复杂度,都是 O(nlog2 n)
- 非稳定排序。因为进行了增量间隔分组排序,可能导致相等的值先后顺序变换
6 递归阶乘
n!=1×2×3×...×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。
亦即n!=1×2×3×...×n。阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n。
如5的阶乘为1*2*3*4*5=120,用代码实现如下:
public static void main(String[] args) {
System.out.println(recursionN(5));
}
/**
* 递归计算n的阶乘
* @param n
* @return
*/
private static int recursionN(int n) {
if (n <1) {
throw new IllegalArgumentException("参数必须大于0");
} else if (n == 1) {
return 1;
} else {
return n * recursionN(n - 1);
}
}
7 使用递归输出某个目录下所有子目录和文件
public static void main(String[] args) {
print(new File("E:/"));
}
private static void print(File file) {
System.out.println(file.getAbsolutePath());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
print(f);
}
}
}