基本排序算法总结

简介: 以下排序算法模版都会用Comparable接口数据类型,只要实现了Comarable接口的数据类型比如Integer、Double、String和其他许多高级数据类型(如File和URL),这些数据类型的数组可以作为参数调用排序方法。

以下排序算法模版都会用Comparable接口数据类型,只要实现了Comarable接口的数据类型比如Integer、Double、String和其他许多高级数据类型(如File和URL),这些数据类型的数组可以作为参数调用排序方法。


这里的输入不是Scanner cin = new Scanner(System.in),因为读取花费的时间太大,主要时间都在读取上面了,不如直接读入然后在进行转换操作来得快,所以采用BufferedReader br = new BufferedReader(new InputStreamReader(System.in));


但是也有弊端,比如存在文件中的数据有几万条或者更多,那么必定是有很多行数据,但是这么读取只能读取一行,就需要如下改进:

while ((line = cin.readLine()) != null) {

       ......

}


直接看关键排序代码即可, 写的是通用类型的排序,整型浮点型字符串都可以,只需修改输入定义的数组引用类型即可。


以下算法参考《算法(第四版)》


目录

冒泡排序

选择排序

插入排序

希尔排序

归并排序

快速排序

堆排序:


冒泡排序

最好情况(加了标记辅助的)时间复杂度O(n)

平均情况O(n*n)

最坏情况O(n*n)

importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
publicclassBubble_Sort {
publicstaticbooleanisLess(Comparablea, Comparableb) {
returna.compareTo(b) <0;
    }
publicstaticvoidbubbleSort(Comparable[] a) {
if (a==null||a.length<2) {
return;
        }
for (intend=a.length-1; end>0; --end) {
booleanflag=true; // 如果不要标记符,那么冒泡的最好情况也只能是O(n*n)了for (inti=0; i<end; ++i) {
if (isLess(a[i+1], a[i])) { // 升序swap(a, i+1, i);
flag=false;
                }
            }
if (flag)
break; // 已经有序了,最好情况时间复杂度O(n)        }
    }
publicstaticvoidswap(Object[] a, inti, intj) {
Objecttemp=a[i];
a[i] =a[j];
a[j] =temp;
    }
publicstaticvoidmain(String[] args) throwsIOException {
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
Stringline=br.readLine().trim();
br.close();
String[] s=line.split(" +"); // 输入全部转成字符串, 分割成数组元素intlen=s.length;
/*** 为什么不直接Scanner按照类型读取? 因为读取花费的时间太大,主要时间都在读取上面了,不如直接读入然后在进行转换操作来得快* 如果直接字符串排序就不需要接下来的转换操作了。*/Integer[] a=newInteger[len];
// 如果要排字符串用String[],排double用Double[],以此类推,就成了通用排序数组for (inti=0; i<len; ++i) {
a[i] =Integer.valueOf(s[i]);
        }
bubbleSort(a);
if (len!=0) {
System.out.print(a[0]);
        }
for (inti=1; i<len; ++i) {
System.out.print(" "+a[i]);
        }
    }
}

image.gif

选择排序

时间复杂度的最好最坏和平均情况都是O(n*n)


importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
publicclassSelection_Sort {
publicstaticbooleanisLess(Comparablea, Comparableb) {
returna.compareTo(b) <0;
    }
publicstaticvoidselectionSort(Comparable[] a) {
if (a==null||a.length<2) {
return;
        }
for (inti=0; i<a.length-1; ++i) {
intmin=i;
for (intj=i+1; j<a.length; ++j) {
min=isLess(a[j], a[min]) ?j : min; // 升序            }
if (min!=i) {
swap(a, i, min);
            }
        }
    }
publicstaticvoidswap(Object[] a, inti, intj) {
Objecttemp=a[i];
a[i] =a[j];
a[j] =temp;
    }
publicstaticvoidmain(String[] args) throwsIOException {
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
Stringline=br.readLine().trim();
br.close();
String[] s=line.split(" +"); // 输入全部转成字符串, 分割成数组元素intlen=s.length;
/*** 为什么不直接Scanner按照类型读取? 因为读取花费的时间太大,主要时间都在读取上面了,不如直接读入然后在进行转换操作来得快* 如果直接字符串排序就不需要接下来的转换操作了。*/Integer[] a=newInteger[len];
// 如果要排字符串用String[],排double用Double[],以此类推,就成了通用排序数组for (inti=0; i<len; ++i) {
a[i] =Integer.valueOf(s[i]);
        }
selectionSort(a);
if (len!=0) {
System.out.print(a[0]);
        }
for (inti=1; i<len; ++i) {
System.out.print(" "+a[i]);
        }
    }
}

image.gif

冒泡排序和选择排序实际一般用不到了,只是一个教学版本,但至少得掌握吧


插入排序

时间复杂度最好情况是O(n)

最坏和平均情况是O(n*n)


importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
publicclassInsertion_Sort {
publicstaticbooleanisLess(Comparablea, Comparableb) {
returna.compareTo(b) <0;
    }
publicstaticvoidInsertionSort(Comparable[] a) {
if (a==null||a.length<2) {
return;
        }
for (inti=1; i<a.length; ++i) {                      // 从前往后排序for (intj=i; j>0&&isLess(a[j], a[j-1]); --j) { // 前面数据一定已经排好序,刚刚开始比较发现a[j]>a[j+1],// 不满足就进行下一轮循环swap(a, j, j-1);                               // 因此最好情况是O(n),本身是有序数组,外层O(n),内层O(1)忽略            }
        }
    }
publicstaticvoidswap(Object[] a, inti, intj) {
Objecttemp=a[i];
a[i] =a[j];
a[j] =temp;
    }
publicstaticvoidmain(String[] args) throwsIOException {
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
Stringline=br.readLine().trim();
br.close();
String[] s=line.split(" +"); // 输入全部转成字符串, 分割成数组元素intlen=s.length;
/*** 为什么不直接Scanner按照类型读取? 因为读取花费的时间太大,主要时间都在读取上面了,不如直接读入然后在进行转换操作来得快* 如果直接字符串排序就不需要接下来的转换操作了。*/Integer[] a=newInteger[len];
// 如果要排字符串用String[],排double用Double[],以此类推,就成了通用排序数组for (inti=0; i<len; ++i) {
a[i] =Integer.valueOf(s[i]);
        }
InsertionSort(a);
if (len!=0) {
System.out.print(a[0]);
        }
for (inti=1; i<len; ++i) {
System.out.print(" "+a[i]);
        }
    }
}

image.gif

希尔排序


最好情况时间复杂度O(n^1.25)

最坏情况是O(n^5/3)而不是O(n^2),要优于插入排序

平均情况O(nlogn)~O(n^5/3)

透彻理解希尔排序的性能至今仍然是一项挑战,实际上希尔排序是至今唯一无法准确描述其对于乱序的数组的性能的排序方法


importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
publicclassShell_Sort {
publicstaticbooleanisLess(Comparablea, Comparableb) {
returna.compareTo(b) <0;
    }
publicstaticvoidshellSort(Comparable[] a) {
intn=a.length;
inth=1;
while (h<n/3)
h=3*h+1; // 递增序列1,4,13,40,121,364,1093......while (h>=1) {
for (inti=h; i<n; i++) {
for (intj=i; j>=h&&less(a[j], a[j-h]); j-=h) {
swap(a, j, j-h);
                }
// 可以打印交换过程,方便理解/** for (int k = 0; k < n; ++k) { System.out.print(a[k] + " "); }* System.out.println();*/            }
h/=3;
        }
    }
privatestaticbooleanless(Comparablev, Comparablew) {
returnv.compareTo(w) <0;
    }
privatestaticvoidswap(Object[] a, inti, intj) {
Objectswap=a[i];
a[i] =a[j];
a[j] =swap;
    }
publicstaticvoidmain(String[] args) throwsIOException {
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
Stringline=br.readLine().trim();
br.close();
String[] s=line.split(" +"); // 输入全部转成字符串, 分割成数组元素intlen=s.length;
/*** 为什么不直接Scanner按照类型读取? 因为读取花费的时间太大,主要时间都在读取上面了,不如直接读入然后在进行转换操作来得快* 如果直接字符串排序就不需要接下来的转换操作了。*/Integer[] a=newInteger[len];
// 如果要排字符串用String[],排double用Double[],以此类推,就成了通用排序数组for (inti=0; i<len; ++i) {
a[i] =Integer.valueOf(s[i]);
        }
shellSort(a);
if (len!=0) {
System.out.print(a[0]);
        }
for (inti=1; i<len; ++i) {
System.out.print(" "+a[i]);
        }
    }
}

image.gif

      希尔排序为了加快速度简单的改进了插入排序,交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。希尔排序的思想是使数组中任意间隔为h的元素都是有序的,这样的数组被称为h有序数组。实现希尔排序的一中方法是对于每个h,用插入排序将h个子数组独立的排序。但因为子数组是相互独立的,一个更简单的方法是h子数组中将每个元素交换到比它还大的元素之前去(将比它大的元素向右移动了一格)。只需要在插入排序的代码中将移动元素的距离由1改为h即可。这样,希尔排序的实现就转化为了一个类似于插入排序但使用不同增量的过程。


      如何选择递增序列h呢?算法的性能不进取决于h,还取决于h之间的数学性质,比如它们的公因子等。有很多论文研究了各种不同的递增序列,但都无法证明某个递增序列是“最好的”。


归并排序


最好最坏平均的时间复杂度都是O(nlogn)



importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
publicclassMergeSort {
// 不把help[]声明为merge()方法的局部变量,是为了避免每次归并时,即使是归并很小的数组,都创建一个新的数组。// 如果这么做,那么创建新数组将成为归并排序运行时间的主要部分。更好的解决方案是把help[]变为sort方法的局部变量,// 并将它作为参数传递给merge()方法publicstaticComparable[] help;
publicstaticvoidmergeSort(Comparable[] a) {
if (a==null||a.length<2) {
return;
        }
help=newComparable[a.length];
sort(a, 0, a.length-1);
    }
publicstaticvoidsort(Comparable[] a, intlo, inthi) {
if (lo>=hi) {
return;
        } // 为什么不直接(lo+hi)>>1呢,因为lo+hi可能溢出,而hi-lo不溢出,lo+((hi-lo)>>1)是小于hi的,也不溢出,更安全intmid=lo+ ((hi-lo) >>1); // 对于java最好(lo + hi) >>> 1sort(a, lo, mid);
sort(a, mid+1, hi);
merge(a, lo, mid, hi);
    }
publicstaticbooleanisLess(Comparablea, Comparableb) {
returna.compareTo(b) <0;
    }
publicstaticvoidmerge(Comparable[] a, intlo, intmid, inthi) {
intj=lo, k=mid+1;
for (inti=lo; i<=hi; ++i) {
help[i] =a[i];
        }
for (inti=lo; i<=hi; ++i) {
if (j>mid) {
a[i] =help[k++];
            } elseif (k>hi) {
a[i] =help[j++];
            } elseif (isLess(help[k], help[j])) {
a[i] =help[k++];
            } else {
a[i] =help[j++];
            }
        }
    }
publicstaticvoidmain(String[] args) throwsIOException {
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
Stringline=br.readLine().trim();
br.close();
String[] s=line.split(" +"); // 输入全部转成字符串, 分割成数组元素intlen=s.length;
/*** 为什么不直接Scanner按照类型读取? 因为读取花费的时间太大,主要时间都在读取上面了,不如直接读入然后在进行转换操作来得快* 如果直接字符串排序就不需要接下来的转换操作了。*/Integer[] a=newInteger[len];
// 如果要排字符串用String[],排double用Double[],以此类推,就成了通用排序数组for (inti=0; i<len; ++i) {
a[i] =Integer.valueOf(s[i]);
        }
mergeSort(a);
if (len!=0) {
System.out.print(a[0]);
        }
for (inti=1; i<len; ++i) {
System.out.print(" "+a[i]);
        }
    }
}

image.gif

      归并排序比希尔排序快吗??在实际的应用中,它们的运行时间之间的差距在常数级别之内(希尔排序使用的是经过验证的递增序列),因此相对性能取决于具体的实现。


      理论上来说,还没有人能够证明希尔排序对于随机数据的运行时间是线性对数级别的,因此存在平均情况下希尔排序的性能的渐进增长率更高的可能性,在最坏的情况下,这种差距的存在已经被证实了,但这对实际应用没有影响。


快速排序

原地排序:空间复杂度为O(1),相对于归并排序来说,占用非常小的内存便可以实现很高效的排序的效果


平均状态下的时间复杂度为O(nlogn), 最好O(nlogn),最坏O(n*n)


importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.util.Random;
publicclassQuickSort {
publicstaticvoidmain(String[] args) throwsIOException {
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
Stringline=br.readLine().trim();
br.close();
String[] s=line.split(" +"); // 输入全部转成字符串, 分割成数组元素intlen=s.length;
/*** 为什么不直接Scanner按照类型读取? 因为读取花费的时间太大,主要时间都在读取上面了,不如直接读入然后在进行转换操作来得快* 如果直接字符串排序就不需要接下来的转换操作了。*/Integer[] a=newInteger[len];
// 如果要排字符串用String[],排double用Double[],以此类推,就成了通用排序数组for (inti=0; i<len; ++i) {
a[i] =Integer.valueOf(s[i]);
        }
quickSort(a);
if (len!=0) {
System.out.print(a[0]);
        }
for (inti=1; i<len; ++i) {
System.out.print(" "+a[i]);
        }
    }
privatestaticRandomrandom=newRandom(System.currentTimeMillis());
privatestaticvoidquickSort(Comparable[] a) {
shuffle(a); // 随机任意打乱顺序,消除对输入的依赖,之后会讲为什么quickSort(a, 0, a.length-1);
    }
privatestaticvoidquickSort(Comparable[] a, intlo, inthi) {
if (hi<=lo)
return;
intj=partition(a, lo, hi);
quickSort(a, lo, j-1);
quickSort(a, j+1, hi);
    }
privatestaticintpartition(Comparable[] a, intlo, inthi) {
inti=lo, j=hi+1;
Comparablev=a[i];
while (true) {
while (less(a[++i], v))
if (i>=hi)
break;
while (less(v, a[--j]))
if (j<=lo)
break;
if (i>=j)
break;
swap(a, i, j); // 将第一个大于v的数--a[i]和第一个小于v的数--a[j]交换        }
swap(a, lo, j);
returnj;
    }
privatestaticvoidswap(Comparable[] a, inti, intj) {
Comparabletemp=a[i];
a[i] =a[j];
a[j] =temp;
    }
privatestaticbooleanless(Comparablecom, Comparablev) {
returncom.compareTo(v) <0;
    }
privatestaticvoidshuffle(Object[] a) {
validateNotNull(a); // 判断数组是否为空intn=a.length;
for (inti=0; i<n; i++) {
intr=i+uniform(n-i);
Objecttemp=a[i];
a[i] =a[r];
a[r] =temp;
        }
    }
publicstaticintuniform(intn) {
if (n<=0)
thrownewIllegalArgumentException("argument must be positive: "+n);
returnrandom.nextInt(n);
    }
privatestaticvoidvalidateNotNull(Objectx) {
if (x==null) {
thrownewIllegalArgumentException("argument is null");
        }
    }
}

image.gif

有一个能被证明的命题就是:快速排序最多需要约(N*N)/ 2次比较,但随机打乱能够预防这种情况。


问:随机将数组打乱似乎占用了排序用时的一大部分时间,这么做值得吗?

   值得。这能够防止出现最怀情况并使运行时间可以预计。Hoare在1960年提出这个算法的时候就推荐了这种方法——它是一种(也是第一批)偏爱随机性的算法。


下面给出三向切分的快速排序作为参考:

对于大量重复元素, 时间复杂度可降到O(N)


privatestaticvoidquickSort3Way(Comparable[] a, intlo, inthi) {
if (hi>=lo)
return;
intlt=lo, i=lo+1, gt=hi;
Comparablev=a[lo];
while (i<=gt) {
intcmp=a[i].compareTo(v);
if (cmp<0)
swap(a, lt++, i++);
elseif (cmp>0)
swap(a, i, gt--);
else++i;
        } // 现在a[lo...lt-1] < v = a[lt..gt] < a[gt + 1...hi]成立quickSort3Way(a, lo, lt-1);
quickSort3Way(a, gt+1, hi);
    }

image.gif

      对于大量重复元素的数组,它将排序时间从 线性对数级别 降低到了线性级别这种对于重复元素的适应性使得三向切分的快速排序成为排序库函数的最佳算法选择——需要将包含大量重复元素的数组排序的用例很常见。


堆排序:

下沉排序(数值大的下沉,这样就是升序,如果数值小的下沉,那么就是降序)

最好最坏平均时间复杂度都为O(nlogn),空间复杂度为O(1)


升序代码:

importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
publicclassHeapSort {
publicstaticvoidmain(String[] args) throwsIOException {
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
Stringline=br.readLine().trim();
br.close();
String[] s=line.split(" +"); // 输入全部转成字符串, 分割成数组元素intlen=s.length;
/*** 为什么不直接Scanner按照类型读取? 因为读取花费的时间太大,主要时间都在读取上面了,不如直接读入然后在进行转换操作来得快* 如果直接字符串排序就不需要接下来的转换操作了。*/Integer[] a=newInteger[len];
// 如果要排字符串用String[],排double用Double[],以此类推,就成了通用排序数组for (inti=0; i<len; ++i) {
a[i] =Integer.valueOf(s[i]);
        }
heapSort(a);
if (len!=0) {
System.out.print(a[0]);
        }
for (inti=1; i<len; ++i) {
System.out.print(" "+a[i]);
        }
    }
privatestaticvoidheapSort(Comparable[] a) {
intN=a.length;
for (intk=N>>1; k>=1; --k) { // 堆的构造,从树底端开始往上恢复堆有序sink(a, k, N);
        }
while (N>1) { // 从上往下沉,让数组变成升序(下沉排序)swap(a, 1, N--); // 第一个一定是最大的,换到数组最后sink(a, 1, N); // 剩下的元素继续恢复堆有序        }
    }
privatestaticvoidsink(Comparable[] a, intk, intn) {
while ((k<<1) <=n) { // (k << 1) <= N说明一定有左孩子intj=k<<1; // 左孩子下标if (j<n&&less(a, j, j+1)) // j < N说明一定有右孩子,如果左孩子小于右孩子的值++j; // 下标转移到右孩子if (less(a, j, k)) // 如果k结点的孩子中的最大值还是比k结点的值小,不用下沉了,已经堆有序break;
swap(a, k, j); // 和孩子中的最大值交换k=j; // 现在这个元素已经在刚刚的j位置上,继续记录这个元素的位置,继续判断看能否继续下沉        }
    }
privatestaticvoidswap(Object[] a, intk, intj) { // 第k和第j个元素交换,因为是下标所以-1Objecttemp=a[k-1];
a[k-1] =a[j-1];
a[j-1] =temp;
    }
privatestaticbooleanless(Comparable[] a, intj, inti) {
returna[j-1].compareTo(a[i-1]) <0;
    }
}

image.gif

测试结果:

-2 5 34 768 12  678 32 675 0 345 -1 12

-2 -1 0 5 12 12 32 34 345 675 678 768

降序代码:

(仅仅将less换成了greater)


importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.InputStreamReader;
publicclassHeapSort {
publicstaticvoidmain(String[] args) throwsIOException {
BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
Stringline=br.readLine().trim();
br.close();
String[] s=line.split(" +"); // 输入全部转成字符串, 分割成数组元素intlen=s.length;
/*** 为什么不直接Scanner按照类型读取? 因为读取花费的时间太大,主要时间都在读取上面了,不如直接读入然后在进行转换操作来得快* 如果直接字符串排序就不需要接下来的转换操作了。*/Integer[] a=newInteger[len];
// 如果要排字符串用String[],排double用Double[],以此类推,就成了通用排序数组for (inti=0; i<len; ++i) {
a[i] =Integer.valueOf(s[i]);
        }
heapSort(a);
if (len!=0) {
System.out.print(a[0]);
        }
for (inti=1; i<len; ++i) {
System.out.print(" "+a[i]);
        }
    }
privatestaticvoidheapSort(Comparable[] a) {
intN=a.length;
for (intk=N>>1; k>=1; --k) { // 堆的构造,从树底端开始往上恢复堆有序sink(a, k, N);
        }
while (N>1) { // 从上往下沉,让数组变成降序(下沉排序)swap(a, 1, N--); // 第一个一定是最小的,换到数组最后sink(a, 1, N); // 剩下的元素继续恢复堆有序        }
    }
privatestaticvoidsink(Comparable[] a, intk, intn) {
while ((k<<1) <=n) { // (k << 1) <= N说明一定有左孩子intj=k<<1; // 左孩子下标if (j<n&&greater(a, j, j+1)) // j < N说明一定有右孩子,如果左孩子大于右孩子的值++j; // 下标转移到右孩子if (greater(a, j, k)) // 如果k结点的孩子中的最小值还是比k结点的值大,不用下沉了,已经堆有序break;
swap(a, k, j); // 和孩子中的最小值交换k=j; // 现在这个元素已经在刚刚的j位置上,继续记录这个元素的位置,继续判断看能否继续下沉        }
    }
privatestaticvoidswap(Object[] a, intk, intj) { // 第k和第j个元素交换,因为是下标所以-1Objecttemp=a[k-1];
a[k-1] =a[j-1];
a[j-1] =temp;
    }
privatestaticbooleangreater(Comparable[] a, intj, inti) {
returna[j-1].compareTo(a[i-1]) >0;
    }
}

image.gif

测试结果:

-2 5 34 768 12  678 32 675 0 345 -1 12

768 678 675 345 34 32 12 12 5 0 -1 -2


命题1:用下沉操作由N个元素构造堆只需要少于2N次比较以及少于N次交换

命题2:将N个元素排序,堆排序只需要少于(2NlgN+2N)次比较(以及一半次数的交换),其中2N项来自堆的构造,2NlgN项来自于每次下沉操作最大可能需要2NlgN次比较。




============================Talk is cheap, show me the code============================

目录
相关文章
|
存储 Ubuntu 安全
百度搜索:蓝易云【Ubuntu系统离线安装Telnet服务教程。】
确保在进行任何系统配置更改之前备份重要的数据,并在操作过程中小心谨慎,以免造成不必要的问题。
351 0
|
Java 程序员
收藏!阿里毕玄16篇文章,深度讲解Java开发、系统设计、职业发展
阿里毕玄结合自己的经历深度讲解Java开发、系统设计、职业发展等问题,快来一键收藏吧。
35137 1
|
12月前
|
JavaScript 前端开发
JS几种拼接字符串的方法
JS几种拼接字符串的方法
184 1
|
11月前
|
算法 搜索推荐 数据库
二分搜索:高效的查找算法
【10月更文挑战第29天】通过对二分搜索的深入研究和应用,我们可以不断挖掘其潜力,为各种复杂问题提供高效的解决方案。相信在未来的科技发展中,二分搜索将继续发挥着重要的作用,为我们的生活和工作带来更多的便利和创新。
173 1
|
开发框架 前端开发 中间件
开源PHP项目
【9月更文挑战第2天】开源PHP项目
213 4
|
存储
【初阶数据结构】深入解析循环队列:探索底层逻辑
【初阶数据结构】深入解析循环队列:探索底层逻辑
287 0
|
SQL IDE JavaScript
"揭秘高效代码Review秘籍:如何像侦探一样挖掘隐藏错误,提升团队编程实力,你不可错过的实战指南!"
【8月更文挑战第20天】代码Review是软件开发中提升代码质量与团队协作的关键环节。本文详细介绍高效代码Review流程:从明确范围与标准开始,到逐行审查与工具辅助,再到积极沟通与闭环管理,辅以示例确保清晰易懂。通过实践这些步骤,不仅能减少错误,还能促进知识共享,为构建高质量软件打下坚实基础。
290 2
|
Ubuntu
ubuntu引导修复
ubuntu引导修复
195 0
|
存储 Java 程序员
【C语言入门】C语言入门:探索编程世界的基础概念
【C语言入门】C语言入门:探索编程世界的基础概念
273 2
|
SQL Java 程序员
马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day1最快 最全(1)
马程序员2024最新SpringCloud微服务开发与实战 个人学习心得、踩坑、与bug记录Day1最快 最全(1)
389 1