2024最新java详细学习路线及路线图(超详细),海归硕士面试3家大厂挂了2家怎么办

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

if(e.compareTo(current.element) <0) {

current = current.left;

}elseif(e.compareTo(current.element) >0) {

current = current.right;

}else{

returntrue;

}

}

returnfalse;

}

// 二叉查找树的插入

public boolean insert(Ee) {

// 如果之前是空二叉树 插入的元素就作为根节点

if(root ==null) {

root = createNewNode(e);

}else{

// 否则就从根节点开始遍历 直到找到合适的父节点

TreeNode parent =null;

TreeNode current = root;

while(current !=null) {

if(e.compareTo(current.element) <0) {

parent = current;

current = current.left;

}elseif(e.compareTo(current.element) >0) {

parent = current;

current = current.right;

}else{

returnfalse;

}

}

// 插入

if(e.compareTo(parent.element) <0) {

parent.left = createNewNode(e);

}else{

parent.right = createNewNode(e);

}

}

returntrue;

}

// 创建新的节点

protectedTreeNode createNewNode(Ee) {

returnnewTreeNode(e);

}

}

// 二叉树的节点

classTreeNode<EextendsComparable>{

Eelement;

TreeNode left;

TreeNode right;

publicTreeNode(Ee) {

element = e;

}

}

上面的代码15主要展示了一个自己实现的简单的二叉查找树,其中包括了几个常见的操作,当然更多的操作还是需要大家自己去完成。因为在二叉查找树中删除节点的操作比较复杂,所以下面我详细介绍一下这里。

二叉查找树中删除节点分析

要在二叉查找树中删除一个元素,首先需要定位包含该元素的节点,以及它的父节点。假设current指向二叉查找树中包含该元素的节点,而parent指向current节点的父节点,current节点可能是parent节点的左孩子,也可能是右孩子。这里需要考虑两种情况:

current节点没有左孩子,那么只需要将patent节点和current节点的右孩子相连。

current节点有一个左孩子,假设rightMost指向包含current节点的左子树中最大元素的节点,而parentOfRightMost指向rightMost节点的父节点。那么先使用rightMost节点中的元素值替换current节点中的元素值,将parentOfRightMost节点和rightMost节点的左孩子相连,然后删除rightMost节点。

// 二叉搜索树删除节点

publicboolean delete(Ee) {

TreeNode parent = null;

TreeNode current = root;

// 找到要删除的节点的位置

while(current != null) {

if(e.compareTo(current.element) <0) {

parent = current;

current = current.left;

}elseif(e.compareTo(current.element) >0) {

parent = current;

current = current.right;

}else{

break;

}

}

// 没找到要删除的节点

if(current == null) {

returnfalse;

}

// 考虑第一种情况

if(current.left== null) {

if(parent == null) {

root = current.right;

}else{

if(e.compareTo(parent.element) <0) {

parent.left= current.right;

}else{

parent.right= current.right;

}

}

}else{// 考虑第二种情况

TreeNode parentOfRightMost = current;

TreeNode rightMost = current.left;

// 找到左子树中最大的元素节点

while(rightMost.right!= null) {

parentOfRightMost = rightMost;

rightMost = rightMost.right;

}

// 替换

current.element = rightMost.element;

// parentOfRightMost和rightMost左孩子相连

if(parentOfRightMost.right== rightMost) {

parentOfRightMost.right= rightMost.left;

}else{

parentOfRightMost.left= rightMost.left;

}

}

returntrue;

}

平衡二叉树

平衡二叉树又称AVL树,它或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。

v2-e83764805abaca547303075e092a989a_b.jpg

平衡二叉树

AVL树是最先发明的自平衡二叉查找树算法。在AVL中任何节点的两个儿子子树的高度最大差别为1,所以它也被称为高度平衡树,n个结点的AVL树最大深度约1.44log2n。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

红黑树

红黑树是平衡二叉树的一种,它保证在最坏情况下基本动态集合操作的事件复杂度为O(log n)。红黑树和平衡二叉树区别如下:(1) 红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单。(2) 平衡二叉树追求绝对平衡,条件比较苛刻,实现起来比较麻烦,每次插入新节点之后需要旋转的次数不能预知。

[四、图]

简介

图是一种较线性表和树更为复杂的数据结构,在线性表中,数据元素之间仅有线性关系,在树形结构中,数据元素之间有着明显的层次关系,而在图形结构中,节点之间的关系可以是任意的,图中任意两个数据元素之间都可能相关。图的应用相当广泛,特别是近年来的迅速发展,已经渗入到诸如语言学、逻辑学、物理、化学、电讯工程、计算机科学以及数学的其他分支中。

相关阅读

因为图这部分的内容还是比较多的,这里就不详细介绍了,有需要的可以自己搜索相关资料。

(1) [《百度百科对图的介绍》]

(2) [《数据结构之图(存储结构、遍历)》]

这篇文章是常见数据结构与算法整理总结的下篇,上一篇主要是对常见的数据结构进行集中总结,这篇主要是总结一些常见的算法相关内容,文章中如有错误,欢迎指出。

一、概述

二、查找算法

三、排序算法

四、其它算法

五、常见算法题

六、总结

[一、概述]

以前看到这样一句话,语言只是工具,算法才是程序设计的灵魂。的确,算法在计算机科学中的地位真的很重要,在很多大公司的笔试面试中,算法掌握程度的考察都占据了很大一部分。不管是为了面试还是自身编程能力的提升,花时间去研究常见的算法还是很有必要的。下面是自己对于算法这部分的学习总结。

v2-d201e7cbcecfd4b82fa08f349586ae16_b.jpg

算法简介

算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。对于同一个问题的解决,可能会存在着不同的算法,为了衡量一个算法的优劣,提出了空间复杂度与时间复杂度这两个概念。

时间复杂度

一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数f(n),算法的时间度量记为 ** T(n) = O(f(n)) **,它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的渐近时间复杂度,简称时间复杂度。这里需要重点理解这个增长率。

举个例子,看下面3个代码:

1、{++x;}

2、for(i =1; i <= n; i++) { ++x; }

3、for(j =1; j <= n; j++)

for(j =1; j <= n; j++)

{ ++x; }

上述含有 ++x操作的语句的频度分别为1、n、n^2,

假设问题的规模扩大了n倍,3个代码的增长率分别是1、n、n^2

它们的时间复杂度分别为O(1)、O(n )、O(n^2)

空间复杂度

空间复杂度是对一个算法在运行过程中临时占用存储空间大小的量度,记做S(n)=O(f(n))。一个算法的优劣主要从算法的执行时间和所需要占用的存储空间两个方面衡量。

[二、查找算法]

查找和排序是最基础也是最重要的两类算法,熟练地掌握这两类算法,并能对这些算法的性能进行分析很重要,这两类算法中主要包括二分查找、快速排序、归并排序等等。

顺序查找

顺序查找又称线性查找。它的过程为:从查找表的最后一个元素开始逐个与给定关键字比较,若某个记录的关键字和给定值比较相等,则查找成功,否则,若直至第一个记录,其关键字和给定值比较都不等,则表明表中没有所查记录查找不成功,它的缺点是效率低下。

二分查找

简介

二分查找又称折半查找,对于有序表来说,它的优点是比较次数少,查找速度快,平均性能好。

二分查找的基本思想是将n个元素分成大致相等的两部分,取a[n/2]与x做比较,如果x=a[n/2],则找到x,算法中止;如果x<a[n/2],则只要在数组a的左半部分继续搜索x,如果x>a[n/2],则只要在数组a的右半部搜索x。

二分查找的时间复杂度为O(logn)

实现

//给定有序查找表array 二分查找给定的值data

//查找成功返回下标 查找失败返回-1

staticintfunBinSearch(int[]array,intdata){

intlow =0;

inthigh =array.length -1;

while(low <= high) {

intmid = (low + high) /2;

if(data ==array[mid]) {

returnmid;

}elseif(data

high = mid -1;

}else{

low = mid +1;

}

}

return-1;

}

[三、排序算法]

排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个按关键字有序的序列。下面主要对一些常见的排序算法做介绍,并分析它们的时空复杂度。

v2-4987ba79deb94fb62f99a22db14c9a33_b.jpg

常见排序算法

常见排序算法性能比较:

v2-0f5764219569310d16b961e53363352e_b.jpg

图片来自网络

上面这张表中有稳定性这一项,排序的稳定性是指如果在排序的序列中,存在前后相同的两个元素的话,排序前和排序后他们的相对位置不发生变化。

下面从冒泡排序开始逐一介绍。

冒泡排序

简介

冒泡排序的基本思想是:设排序序列的记录个数为n,进行n-1次遍历,每次遍历从开始位置依次往后比较前后相邻元素,这样较大的元素往后移,n-1次遍历结束后,序列有序。

例如,对序列(3,2,1,5)进行排序的过程是:共进行3次遍历,第1次遍历时先比较3和2,交换,继续比较3和1,交换,再比较3和5,不交换,这样第1次遍历结束,最大值5在最后的位置,得到序列(2,1,3,5)。第2次遍历时先比较2和1,交换,继续比较2和3,不交换,第2次遍历结束时次大值3在倒数第2的位置,得到序列(1,2,3,5),第3次遍历时,先比较1和2,不交换,得到最终有序序列(1,2,3,5)。

需要注意的是,如果在某次遍历中没有发生交换,那么就不必进行下次遍历,因为序列已经有序。

** 实现**

// 冒泡排序 注意 flag 的作用

staticvoidfunBubbleSort(int[]array){

boolean flag =true;

for(inti =0; i

flag =false;

for(intj =0; j

if(array[j] >array[j +1]) {

inttemp =array[j];

array[j] =array[j +1];

array[j +1] = temp;

flag =true;

}

}

}

for(inti =0; i

System.out.println(array[i]);

}

}

分析

最佳情况下冒泡排序只需一次遍历就能确定数组已经排好序,不需要进行下一次遍历,所以最佳情况下,时间复杂度为** O(n) **。

最坏情况下冒泡排序需要n-1次遍历,第一次遍历需要比较n-1次,第二次遍历需要n-2次,…,最后一次需要比较1次,最差情况下时间复杂度为** O(n^2) **。

简单选择排序

简介

简单选择排序的思想是:设排序序列的记录个数为n,进行n-1次选择,每次在n-i+1(i = 1,2,…,n-1)个记录中选择关键字最小的记录作为有效序列中的第i个记录。

例如,排序序列(3,2,1,5)的过程是,进行3次选择,第1次选择在4个记录中选择最小的值为1,放在第1个位置,得到序列(1,3,2,5),第2次选择从位置1开始的3个元素中选择最小的值2放在第2个位置,得到有序序列(1,2,3,5),第3次选择因为最小的值3已经在第3个位置不需要操作,最后得到有序序列(1,2,3,5)。

实现

staticvoidfunSelectionSort(int[]array){

for(inti =0; i

intmink = i;

// 每次从未排序数组中找到最小值的坐标

for(intj = i +1; j

if(array[j]

mink = j;

}

}

// 将最小值放在最前面

if(mink != i) {

inttemp =array[mink];

array[mink] =array[i];

array[i] = temp;

}

}

for(inti =0; i

System.out.print(array[i] +" ");

}

}

分析

简单选择排序过程中需要进行的比较次数与初始状态下待排序的记录序列的排列情况** 无关**。当i=1时,需进行n-1次比较;当i=2时,需进行n-2次比较;依次类推,共需要进行的比较次数是(n-1)+(n-2)+…+2+1=n(n-1)/2,即进行比较操作的时间复杂度为** O(n^2) ,进行移动操作的时间复杂度为 O(n) 。总的时间复杂度为 O(n^2) **。

最好情况下,即待排序记录初始状态就已经是正序排列了,则不需要移动记录。最坏情况下,即待排序记录初始状态是按第一条记录最大,之后的记录从小到大顺序排列,则需要移动记录的次数最多为3(n-1)。

简单选择排序是不稳定排序。

直接插入排序

简介

直接插入的思想是:是将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。

例如,排序序列(3,2,1,5)的过程是,初始时有序序列为(3),然后从位置1开始,先访问到2,将2插入到3前面,得到有序序列(2,3),之后访问1,找到合适的插入位置后得到有序序列(1,2,3),最后访问5,得到最终有序序列(1,2,3,5).

实现

staticvoidfunDInsertSort(int[]array){

intj;

for(inti =1; i

inttemp =array[i];

j = i -1;

while(j >-1&& temp

array[j +1] =array[j];

j–;

}

array[j +1] = temp;

}

for(inti =0; i

System.out.print(array[i] +" ");

}

}

分析

最好情况下,当待排序序列中记录已经有序时,则需要n-1次比较,不需要移动,时间复杂度为** O(n) 。最差情况下,当待排序序列中所有记录正好逆序时,则比较次数和移动次数都达到最大值,时间复杂度为 O(n^2) 。平均情况下,时间复杂度为 O(n^2) **。

希尔排序

希尔排序又称“缩小增量排序”,它是基于直接插入排序的以下两点性质而提出的一种改进:(1) 直接插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率。(2) 直接插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位。

归并排序

简介

归并排序是分治法的一个典型应用,它的主要思想是:将待排序序列分为两部分,对每部分递归地应用归并排序,在两部分都排好序后进行合并。

例如,排序序列(3,2,8,6,7,9,1,5)的过程是,先将序列分为两部分,(3,2,8,6)和(7,9,1,5),然后对两部分分别应用归并排序,第1部分(3,2,8,6),第2部分(7,9,1,5),对两个部分分别进行归并排序,第1部分继续分为(3,2)和(8,6),(3,2)继续分为(3)和(2),(8,6)继续分为(8)和(6),之后进行合并得到(2,3),(6,8),再合并得到(2,3,6,8),第2部分进行归并排序得到(1,5,7,9),最后合并两部分得到(1,2,3,5,6,7,8,9)。

实现

//归并排序

staticvoidfunMergeSort(int[]array){

if(array.length >1) {

intlength1 =array.length /2;

int[] array1 =newint[length1];

System.arraycopy(array,0, array1,0, length1);

funMergeSort(array1);

intlength2 =array.length - length1;

int[] array2 =newint[length2];

System.arraycopy(array, length1, array2,0, length2);

funMergeSort(array2);

int[] datas = merge(array1, array2);

System.arraycopy(datas,0,array,0,array.length);

}

}

//合并两个数组

staticint[] merge(int[] list1,int[] list2) {

int[] list3 =newint[list1.length + list2.length];

intcount1 =0;

intcount2 =0;

intcount3 =0;

while(count1 < list1.length && count2 < list2.length) {

if(list1[count1] < list2[count2]) {

list3[count3++] = list1[count1++];

}else{

list3[count3++] = list2[count2++];

}

}

while(count1 < list1.length) {

list3[count3++] = list1[count1++];

}

while(count2 < list2.length) {

list3[count3++] = list2[count2++];

}

returnlist3;

}

分析

归并排序的时间复杂度为O(nlogn),它是一种稳定的排序,java.util.Arrays类中的sort方法就是使用归并排序的变体来实现的。

快速排序

简介

快速排序的主要思想是:在待排序的序列中选择一个称为主元的元素,将数组分为两部分,使得第一部分中的所有元素都小于或等于主元,而第二部分中的所有元素都大于主元,然后对两部分递归地应用快速排序算法。

实现

// 快速排序

staticvoidfunQuickSort(int[] mdata,intstart,intend){

if(end > start) {

intpivotIndex = quickSortPartition(mdata, start, end);

funQuickSort(mdata, start, pivotIndex -1);

funQuickSort(mdata, pivotIndex +1, end);

}

}

// 快速排序前的划分

staticintquickSortPartition(int[]list,intfirst,intlast){

intpivot =list[first];

intlow = first +1;

inthigh = last;

while(high > low) {

while(low <= high &&list[low] <= pivot) {

low++;

}

while(low <= high &&list[high] > pivot) {

high–;

}

if(high > low) {

inttemp =list[high];

list[high] =list[low];

list[low] = temp;

}

}

while(high > first &&list[high] >= pivot) {

high–;

}

if(pivot >list[high]) {

list[first] =list[high];

list[high] = pivot;

returnhigh;

}else{

returnfirst;

}

}

分析

在快速排序算法中,比较关键的一个部分是主元的选择。在最差情况下,划分由n个元素构成的数组需要进行n次比较和n次移动,因此划分需要的时间是O(n)。在最差情况下,每次主元会将数组划分为一个大的子数组和一个空数组,这个大的子数组的规模是在上次划分的子数组的规模上减1,这样在最差情况下算法需要(n-1)+(n-2)+…+1= ** O(n^2) **时间。

最佳情况下,每次主元将数组划分为规模大致相等的两部分,时间复杂度为** O(nlogn) **。

堆排序

简介

在介绍堆排序之前首先需要了解堆的定义,n个关键字序列K1,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):(1) ki <= k(2i)且 ki <= k(2i+1) (1 ≤ i≤ n/2),当然,这是小根堆,大根堆则换成>=号。

如果将上面满足堆性质的序列看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有的非终端节点的值均不大于(或不小于)其左右孩子节点的值。

堆排序的主要思想是:给定一个待排序序列,首先经过一次调整,将序列构建成一个大顶堆,此时第一个元素是最大的元素,将其和序列的最后一个元素交换,然后对前n-1个元素调整为大顶堆,再将其第一个元素和末尾元素交换,这样最后即可得到有序序列。

实现

//堆排序

publicclassTestHeapSort{

publicstaticvoidmain(String[] args){

intarr[] = {5,6,1,0,2,9};

heapsort(arr,6);

System.out.println(Arrays.toString(arr));

}

staticvoidheapsort(intarr[],intn){

// 先建大顶堆

for(inti = n /2-1; i >=0; i–) {

heapAdjust(arr, i, n);

}

for(inti =0; i < n -1; i++) {

swap(arr,0, n - i -1);

heapAdjust(arr,0, n - i -1);

}

}

// 交换两个数

staticvoidswap(intarr[],intlow,inthigh){

inttemp = arr[low];

arr[low] = arr[high];

arr[high] = temp;

}

// 调整堆

staticvoidheapAdjust(intarr[],intindex,intn){

inttemp = arr[index];

intchild =0;

while(index *2+1< n) {

child = index *2+1;

// child为左右孩子中较大的那个

if(child != n -1&& arr[child] < arr[child +1]) {

child++;

}

// 如果指定节点大于较大的孩子 不需要调整

if(temp > arr[child]) {

break;

}else{

// 否则继续往下判断孩子的孩子 直到找到合适的位置

arr[index] = arr[child];

index = child;

}

}

arr[index] = temp;

}

}

分析

由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。堆排序时间复杂度也为O(nlogn),空间复杂度为O(1)。它是不稳定的排序方法。与快排和归并排序相比,堆排序在最差情况下的时间复杂度优于快排,空间效率高于归并排序。

[四、其它算法]

在上面的篇幅中,主要是对查找和常见的几种排序算法作了介绍,这些内容都是基础的但是必须掌握的内容,尤其是二分查找、快排、堆排、归并排序这几个更是面试高频考察点。(这里不禁想起百度一面的时候让我写二分查找和堆排序,二分查找还行,然而堆排序当时一脸懵逼…)下面主要是介绍一些常见的其它算法。

递归

简介

在平常解决一些编程或者做一些算法题的时候,经常会用到递归。程序调用自身的编程技巧称为递归。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。上面介绍的快速排序和归并排序都用到了递归的思想。

经典例子

斐波那契数列,又称黄金分割数列、因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*)。

//斐波那契数列 递归实现

staticlongfunFib(longindex){

if(index ==0) {

return0;

}elseif(index ==1) {

return1;

}else{

returnfunFib(index -1) + funFib(index -2);

}

}

上面代码是斐波那契数列的递归实现,然而我们不难得到它的时间复杂度是O(2^n),递归有时候可以很方便地解决一些问题,但是它也会带来一些效率上的问题。下面的代码是求斐波那契数列的另一种方式,效率比递归方法的效率高。

staticlongfunFib2(longindex){

longf0 =0;

longf1 =1;

longf2 =1;

if(index ==0) {

returnf0;

}elseif(index ==1) {

returnf1;

}elseif(index ==2) {

最后

既已说到spring cloud alibaba,那对于整个微服务架构,如果想要进一步地向上提升自己,到底应该掌握哪些核心技能呢?

就个人而言,对于整个微服务架构,像RPC、Dubbo、Spring Boot、Spring Cloud Alibaba、Docker、kubernetes、Spring Cloud Netflix、Service Mesh等这些都是最最核心的知识,架构师必经之路!下图,是自绘的微服务架构路线体系大纲,如果有还不知道自己该掌握些啥技术的朋友,可根据小编手绘的大纲进行一个参考。

image

如果觉得图片不够清晰,也可来找小编分享原件的xmind文档!

且除此份微服务体系大纲外,我也有整理与其每个专题核心知识点对应的最强学习笔记:

  • 出神入化——SpringCloudAlibaba.pdf

  • SpringCloud微服务架构笔记(一).pdf

  • SpringCloud微服务架构笔记(二).pdf

  • SpringCloud微服务架构笔记(三).pdf

  • SpringCloud微服务架构笔记(四).pdf

  • Dubbo框架RPC实现原理.pdf

  • Dubbo最新全面深度解读.pdf

  • Spring Boot学习教程.pdf

  • SpringBoo核心宝典.pdf

  • 第一本Docker书-完整版.pdf

  • 使用SpringCloud和Docker实战微服务.pdf

  • K8S(kubernetes)学习指南.pdf

image

另外,如果不知道从何下手开始学习呢,小编这边也有对每个微服务的核心知识点手绘了其对应的知识架构体系大纲,不过全是导出的xmind文件,全部的源文件也都在此!

image

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*)。

//斐波那契数列 递归实现

staticlongfunFib(longindex){

if(index ==0) {

return0;

}elseif(index ==1) {

return1;

}else{

returnfunFib(index -1) + funFib(index -2);

}

}

上面代码是斐波那契数列的递归实现,然而我们不难得到它的时间复杂度是O(2^n),递归有时候可以很方便地解决一些问题,但是它也会带来一些效率上的问题。下面的代码是求斐波那契数列的另一种方式,效率比递归方法的效率高。

staticlongfunFib2(longindex){

longf0 =0;

longf1 =1;

longf2 =1;

if(index ==0) {

returnf0;

}elseif(index ==1) {

returnf1;

}elseif(index ==2) {

最后

既已说到spring cloud alibaba,那对于整个微服务架构,如果想要进一步地向上提升自己,到底应该掌握哪些核心技能呢?

就个人而言,对于整个微服务架构,像RPC、Dubbo、Spring Boot、Spring Cloud Alibaba、Docker、kubernetes、Spring Cloud Netflix、Service Mesh等这些都是最最核心的知识,架构师必经之路!下图,是自绘的微服务架构路线体系大纲,如果有还不知道自己该掌握些啥技术的朋友,可根据小编手绘的大纲进行一个参考。

[外链图片转存中…(img-rOEb6lsq-1713424672859)]

如果觉得图片不够清晰,也可来找小编分享原件的xmind文档!

且除此份微服务体系大纲外,我也有整理与其每个专题核心知识点对应的最强学习笔记:

  • 出神入化——SpringCloudAlibaba.pdf

  • SpringCloud微服务架构笔记(一).pdf

  • SpringCloud微服务架构笔记(二).pdf

  • SpringCloud微服务架构笔记(三).pdf

  • SpringCloud微服务架构笔记(四).pdf

  • Dubbo框架RPC实现原理.pdf

  • Dubbo最新全面深度解读.pdf

  • Spring Boot学习教程.pdf

  • SpringBoo核心宝典.pdf

  • 第一本Docker书-完整版.pdf

  • 使用SpringCloud和Docker实战微服务.pdf

  • K8S(kubernetes)学习指南.pdf

[外链图片转存中…(img-QRBnHm5j-1713424672860)]

另外,如果不知道从何下手开始学习呢,小编这边也有对每个微服务的核心知识点手绘了其对应的知识架构体系大纲,不过全是导出的xmind文件,全部的源文件也都在此!

[外链图片转存中…(img-CnISdgl4-1713424672860)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-lzUU2Lm7-1713424672860)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值