之前一直有学习java算法,不过没有系统的进行归纳和整理,今天算是下定决心,开始对之前了解的算法进行归纳总结。
有一些初学者朋友会问O(n²)是什么意思,首先,我们先了解一下O(n)是什么意思。
O(n)不是算法,它是一个函数,是一个表征算法时间复杂度的一个函数。
计算机科学中,算法的时间复杂度是一个函数,它定性描述了该算法的运行时间。这是一个关于代表算法输入值的字符串的长度的函数。时间复杂度常用大O符号表述,不包括这个函数的低阶项和首项系数。
使用这种方式时,时间复杂度可被称为是渐近的,它考察当输入值大小趋近无穷时的情况。
算法其实分时间复杂度和空间复杂度,这里我们先了解时间复杂度。
首先我们先准备一个混乱的数组
int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };
public static int[] selSort(int[] array) {
int minValueSub = 0;
for (int i = 0; i < array.length; i++) {
minValueSub = i;
for (int j = i + 1; j < array.length; j++) {
if (array[minValueSub] > array[j]) {
minValueSub = j;
}
}
if (minValueSub != i) {
int tmp = array[i];
array[i] = array[minValueSub];
array[minValueSub] = tmp;
}
System.out.println("排序次数:"+i);
display(array);
}
return array;
}
public static void selSortDis() {
int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };
System.out.println("未排序数组顺序为:");
display(array);
array = selSort(array);
System.out.println("经过选择排序后的数组顺序为:");
display(array);
}
public static void display(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
selSortDis();
}
接下来我们先说一下冒泡排序,在了解冒泡的时候我会说明O(n²)是怎么得来的:
这个名词的由来很好理解,一般河水中的冒泡,水底刚冒出来的时候是比较小的,随着慢慢向水面浮起会逐渐增大,这物理规律我不作过多解释,大家只需要了解即可。
冒泡算法的运作规律如下:
①、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
②、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数(也就是第一波冒泡完成)。
③、针对所有的元素重复以上的步骤,除了最后一个。
④、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
废话不多说,先上代码:
public static int[] bubbleSort(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if (array[i] > array[j]) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
System.out.println("排序次数:"+i);
display(array);
}
return array;
}
public static void bubbleSortDis() {
int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };
// 未排序数组顺序为
System.out.println("未排序数组顺序为:");
display(array);
array = bubbleSort(array);
System.out.println("经过冒泡排序后的数组顺序为:");
display(array);
}
// 遍历显示数组
public static void display(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
bubbleSortDis();
}
通过代码可以看到,冒泡排序的主体是两个for循环,而每轮比较的次数为(n-1),(n-2)...1。
总共的次数相当于1+2+...+(n-1)次,就是n*(n-1)/2,由于n大到一定程度时其他参数的大小并不重要,运算次数几乎只看n*n的大小,所以叫做O(n²)级别的算法。
有了冒泡排序的基础,接下来我们看一下选择排序:
选择排序是每一次从待排序的数据元素中选出最小的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
分为三步:
①、从待排序序列中,找到关键字最小的元素
②、如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换
③、从余下的 N - 1 个元素中,找出关键字最小的元素,重复(1)、(2)步,直到排序结束
接下来我们看一下选择排序的代码:
public static int[] selSort(int[] array) {
int minValueSub = 0;
for (int i = 0; i < array.length; i++) {
minValueSub = i;
for (int j = i + 1; j < array.length; j++) {
if (array[minValueSub] > array[j]) {
minValueSub = j;
}
}
if (minValueSub != i) {
int tmp = array[i];
array[i] = array[minValueSub];
array[minValueSub] = tmp;
}
System.out.println("排序次数:"+i);
display(array);
}
return array;
}
public static void selSortDis() {
int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };
System.out.println("未排序数组顺序为:");
display(array);
array = selSort(array);
System.out.println("经过选择排序后的数组顺序为:");
display(array);
}
// 遍历显示数组
public static void display(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
selSortDis();
}
由此可以看出,选择排序做了和冒泡排序一样多次比较,总共比较次数为n*(n-1)/2,不过选择排序对数组的操作次数更少,每次排序只是把两个下标的值交换,所以相对速度是比冒泡排序要快的。
最后我们看一下插入排序,直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止。我们今天就先不管别的插入排序,先讲一下直接插入排序。
具体做法就是每次拿出>1数量的数组的值进行比较,最开始拿出两个,依次累加,直接上代码:
public static int[] insertSort(int[] array) {
for (int i = 0; i < array.length; i++) {
while (i > 0 && array[i - 1] > array[i]) {
int tmp = array[i - 1];
array[i - 1] = array[i];
array[i] = tmp;
i--;
}
}
return array;
}
public static void display(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
public static void insertSortDis() {
int[] array = { 0, 2, 8, 9, 5, 7, 6, 1, 3 };
System.out.println("未排序数组顺序为:");
display(array);
array = insertSort(array);
System.out.println("经过插入排序后的数组顺序为:");
display(array);
}
public static void main(String[] args) {
insertSortDis();
}
在第一轮排序中,它最多比较一次,第二轮最多比较两次,一次类推,第N轮,最多比较N-1次。因此有 1+2+3+...+N-1 = N*(N-1)/2。
假设在每一轮排序发现插入点时,平均只有全体数据项的一半真的进行了比较,我们除以2得到:N*(N-1)/4。用大O表示法大致需要需要 O(N2) 时间级别。
总结一下:
上面讲的三种排序,冒泡、选择、插入用大 O 表示法都需要 O(N2) 时间级别。一般不会选择冒泡排序,虽然冒泡排序书写是最简单的,但是平均性能是没有选择排序和插入排序好的。
选择排序把交换次数降低到最低,但是比较次数还是挺大的。当数据量小,并且交换数据相对于比较数据更加耗时的情况下,可以应用选择排序。
在大多数情况下,假设数据量比较小或基本有序时,插入排序是三种算法中最好的选择。
最后把全部代码粘出来大家看一下:
package com.zy.test;
public class Sort {
public static int[] insertSort(int[] array){
for (int i = 0; i < array.length; i++) {
while(i>0&&array[i-1]>array[i]){
int tmp = array[i];
array[i-1] = array[i];
array[i-1] = tmp;
i--;
}
}
return array;
}
public static int[] bubbleSort(int[] array){
for (int i = 0; i < array.length; i++) {
for (int j = i+1; j < array.length; j++) {
if(array[i]>array[j]){
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
}
return array;
}
public static int[] selSort(int[] array){
int minValueSub = 0;
for (int i = 0; i < array.length; i++) {
minValueSub = i;
for (int j = i+1; j < array.length; j++) {
if(array[minValueSub] > array[j]){
minValueSub = j;
}
}
if(minValueSub!=i){
int tmp = array[i];
array[i] = array[minValueSub];
array[minValueSub] = tmp;
}
}
return array;
}
//遍历显示数组
public static void display(int[] array){
for(int i = 0 ; i < array.length ; i++){
System.out.print(array[i]+" ");
}
System.out.println();
}
public static void bubbleSortDis(){
int[] array = {0,2,8,9,5,7,6,1,3};
//未排序数组顺序为
System.out.println("未排序数组顺序为:");
display(array);
array = bubbleSort(array);
System.out.println("经过插入冒泡排序后的数组顺序为:");
display(array);
}
public static void selSortDis(){
int[] array = {0,2,8,9,5,7,6,1,3};
//未排序数组顺序为
System.out.println("未排序数组顺序为:");
display(array);
array = selSort(array);
System.out.println("经过选择排序后的数组顺序为:");
display(array);
}
public static void insertSortDis(){
int[] array = {0,2,8,9,5,7,6,1,3};
//未排序数组顺序为
System.out.println("未排序数组顺序为:");
display(array);
array = selSort(array);
System.out.println("经过插入排序后的数组顺序为:");
display(array);
}
public static void main(String[] args){
bubbleSortDis();
selSortDis();
insertSortDis();
}
}