先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
=========================================================================
希尔排序是Donald Shell于1959年提出的一种排序算法,是对直接插入排序的改进之后的高效版本。
希尔排序需要准备一组数据作为增量序列。这组数据需要满足以下三个条件:
-
数据递减排列
-
数据中的最大值小于待排序数据的长度
-
数据中的最小值是
只要满足上述要求的数组都可以作为增量序列,但是不同的增量序列会影响到排序的效率。这是我们用 {5,3,1} 作为增量序列来进行讲解。
增量为5,就是第一个和第六个为一组进行比较,第二个和第七个一组进行比较,以此类推
我们知道,直接插入排序下列情况效率较高:
-
数据基本有序
-
待排序个数较少的时候(因为数据量小,所以 O(n) 和 O (n2)的差距并不大)
希尔排序就是利用了这样的性质来优化效率的。在希尔排序开始时增量较大,分组较多。每组的记录数目少,故各组内直接插入较快,后来增量逐渐缩小,分组数逐渐减小,各组的数据逐渐增多,但这时数据已趋于有序状态,所以进行插入得操作较少,排序过程也较快。
理论上来说任选一组增量都可以进行排序,因为最后的增量就是1,就相当于是最后肯定还会对数据整体进行一次插入排序。但是希尔排序算法效率增量序列的取值有关。下面列出3种常见的增量序列供大家草靠,为了方便以公式的形式表达,我们用升序的方式来写增量序列。
public class Solution {
public int[] MySort (int[] arr) {
int n = arr.length;
int gap = n / 2;
while (gap >= 1) {
for (int i = gap; i < n; i++) {
int temp = arr[i];
int j = i - gap;
while (j >= 0 && arr[j] > temp) {
arr[j + gap] = arr[j];
j = j - gap;
}
arr[j + gap] = temp;
}
gap = gap / 2;
}
return arr;
}
}
========================================================================
堆是一种完全二叉树,分为大根堆,小根堆两种。
-
可以O(1)取最大/小值;
-
可以O(logn)删除最大/小值;
-
可以O(logn)插入元素。
大(小)根堆始终满足一个性质,父亲节点的值大(小)于等于其所有子孙,那么显而易见的,整棵树中的根节点的值就是最大(小)的。
完全二叉树这种数据结构可以用数组实现:
排序数据其实是可以看作是一棵完全二叉树,如何快速地把一棵完全二叉树调整成小根堆呢?
我们假设完全二叉树中某节点 i 的左子树和右子树都满足小根堆的性质,假设 i 节点的左孩子是lefti,i 节点的右孩子是righti。那如果a[ i ] 大于 a [lefti] 或 a [righti]的话,那么以 i 节点为根节点的整棵子树就不满足小根堆的性质了。我们现在要进行一个操作:把以 i 为根节点的这棵子树调整成小根堆。
可以将最后一个数临时的补到堆顶的位置,然后判断他是否可以放在堆顶——即是否小于其两个儿子,如果不是则说明他应该往下交换,将其和两个儿子中的小的那个交换,交换之后继续和他的儿子进行判断和交换,一直交换到合适的位置。
这样就可以保证删除堆顶元素之后还维持小根堆的性质。其实也可以理解为把最后一个数补到堆顶位置之后,堆的大小减一,再进行一次MIN-HEAPIFY操作。
具体的图解可以看这篇博课 -->> Java实现堆排序和图解
我们先把待排序数组调整成堆,那么堆顶就是整个数组中的最小值。然后我们删除堆顶元素,删除堆顶元素的操作第一步要把最后一个数,临时补到堆顶的位置,这个时候对于堆这个数据结构来说,数组的最后一位其实就没意义了,但是对于实现这个数据结构的数组来说,最后一位还是在物理上存在的。那么我们可以把删除的堆顶元素赋值到数组的最后一位。相当于把最小值放到了数组的最后。这样的话依次删除堆顶元素就相当于依次把最小的值放在了最后。对于小根堆来说,所有元素都删除完毕了以后,整个数组就形成了降序。如果我们需要升序的话,就需要把数组调整成大根堆。
/*
注意:这里的数组是从0开始存储的,
所以我们取左儿子的时候是i*2+1
所以我们取右儿子的时候是i*2+2
*/
public class Solution {
//记录堆的大小
int headSize;
//分别取左右节点的下标
public int Left (int i) {
if (i * 2 + 1 >= headSize) return -1;
return i * 2 + 1;
}
public int Right (int i) {
if (i * 2 + 2 >= headSize) return -1;
return i * 2 + 2;
}
//调整大根堆的操作
public void minHeapify (int[] arr, int i) {
//得到i左右节点的下标
int left = Left(i);
int right = Right(i);
//比较大小
//最大值下标
int maxi = i;
if (left != -1 && arr[left] > arr[i]) {
maxi = left;
}
if (right != -1 && arr[right] > arr[maxi]) {
maxi = right;
}
if (maxi != i) {
swap(arr, i, maxi);
i = maxi;
minHeapify(arr, i);
}
}
public void Delete (int[] arr) {
swap(arr, headSize - 1, 0);
headSize–;
minHeapify(arr, 0);
}
public void swap(int arr[], int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public int[] MySort (int[] arr) {
int n = arr.length;
headSize = n;
for (int i = (n - 1) / 2; i >= 0; i–) {
minHeapify(arr, i);
}
for (int i = 0; i < n; i++) {
Delete(arr);
}
return arr;
}
}
=========================================================================
归并排序是分治法的典型应用,先来介绍一下分治法,分治法是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题…直到最后的子问题规模很小可以直接求解,再将子问题的解进行合并来得到原问题的解。
归并排序分解子问题的过程就是每一次把数组分成2份,直到数组的长度为1(因为只有一个数字的数组是有序的)。然后再将相邻的有序数组合并成一个有序数组,知道全部合到一起,整个数组就排序完毕了。现在要解决的问题就是如何将两个有序的数组合并成一个有序数组。其实就是每次比较两个数组当前最小的两个元素,哪个小就选哪个。
public class Solution {
//将排好序的两个数组,重新合并到新的数组里面
public void merge (int[] arr, int l, int r) {
int mid = (l + r) / 2;
// 新建两个数组,lenL、lenR分别为新数组的长度
int lenL = mid - l + 1;
int lenR = r - mid;
int[] L = new int[lenL];
int[] R = new int[lenR];
for (int i = 0; i < lenL; i++) {
L[i] = arr[l + i];
}
for (int i = 0; i < lenR; i++) {
R[i] = arr[mid + 1 + i];
}
int i = 0, j = 0;
for (int index = l; index <= r; index++) {
// 选左边数组中的值
if (j >= lenR || (i < lenL && L[i] < R[j])) {
arr[index] = L[i];
i++;
} else {
// 选右边数组中的值
arr[index] = R[j];
j++;
}
}
}
public void mergeSort (int[] arr, int l, int r) {
if (l < r) {
int mid = (l + r) / 2;
mergeSort(arr, l, mid);
mergeSort(arr, mid + 1, r);
// 排好序后,进行合并
// 从 l 到 mid 是排好序的
// 从 mid + 1 到 r 是排好序的,才会调用meger()方法
merge(arr, l ,r);
}
}
public int[] MySort (int[] arr) {
int n = arr.length;
mergeSort(arr, 0, n - 1);
return arr;
}
}
=========================================================================
快速排序的工作原理是:**从待排序数组中随便挑选一个数字作为基准数,把所有比它小的数字放在它的左边,所有比它大的数字放在它的右边。然后再对它左边的数组和右边的数组递归进行这样的操作。**全部操作完成以后整个数组就是有序的了。
把所有比基准数小的数字放在它的左边,所有比基准数大的数字放在它的右边。这个操作,我们称为“划分”(Partition)。
“划分”(Partition)的操作可以在O(n)的时间复杂度进行,有很多种方法可以进行这个操作.。
《算法导论》里给出的解法如下:
每次以数组中的最后一个数作为基准数。
public class Solution {
// 划分方法
public int partition (int[] arr, int l, int r) {
int i = l;
int x = arr[r]; // 取基准数字
for (int j = l; j < r; j++) {
if (arr[j] < x) {
swap(arr, i, j);
i++;
}
}
swap(arr, r, i);
return i;
}
public void quickSort (int[] arr, int l, int r) {
if (l < r) {
int mid = partition(arr, l, r);
quickSort(arr, l, mid - 1);
quickSort(arr, mid + 1, r);
}
}
public void swap(int arr[], int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public int[] MySort (int[] arr) {
int n = arr.length;
quickSort(arr, 0, n - 1);
return arr;
}
}
直接看图&代码 ↓
public class Solution {
// 划分方法
public int partition (int[] arr, int l, int r) {
int x = arr[l]; //基准数
总结
虽然面试套路众多,但对于技术面试来说,主要还是考察一个人的技术能力和沟通能力。不同类型的面试官根据自身的理解问的问题也不尽相同,没有规律可循。
上面提到的关于这些JAVA基础、三大框架、项目经验、并发编程、JVM及调优、网络、设计模式、spring+mybatis源码解读、Mysql调优、分布式监控、消息队列、分布式存储等等面试题笔记及资料
有些面试官喜欢问自己擅长的问题,比如在实际编程中遇到的或者他自己一直在琢磨的这方面的问题,还有些面试官,尤其是大厂的比如 BAT 的面试官喜欢问面试者认为自己擅长的,然后通过提问的方式深挖细节,刨根到底。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
不同类型的面试官根据自身的理解问的问题也不尽相同,没有规律可循。
[外链图片转存中…(img-jog0o74y-1713467689486)]
[外链图片转存中…(img-8hBQARTE-1713467689487)]
上面提到的关于这些JAVA基础、三大框架、项目经验、并发编程、JVM及调优、网络、设计模式、spring+mybatis源码解读、Mysql调优、分布式监控、消息队列、分布式存储等等面试题笔记及资料
有些面试官喜欢问自己擅长的问题,比如在实际编程中遇到的或者他自己一直在琢磨的这方面的问题,还有些面试官,尤其是大厂的比如 BAT 的面试官喜欢问面试者认为自己擅长的,然后通过提问的方式深挖细节,刨根到底。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-rpUpOi14-1713467689488)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!