常用的时间复杂度
常数阶\(O(1)\)
说明: 只要代码中没有复杂的循环条件,无论代码的函数是多少,一律为常数阶\(O(1)\)
int i=1;
int j=3;
int m=0;
m=i+j;
....
对数阶 \(O(log_2n)\)
说明: 存在循环体,在不考虑循环体的代码执行情况,该循环体本该执行n次,但是循环体将改变循环变量i的大小,每执行一次,i就扩到两倍,即i=i*2,这样就导致循环体会加速趋近终止条件n;假设经过x次后,退出循环体,则有\(2^x>=n\),因此,\(x=log_2n\);同理,当\(i=i*3时,x=log_3n\),退出循环的速度更快,时间复杂度更小。
while(i
i=i*2;
}
线性阶\(O(n)\)
说明: 存在循环体。循环体内代码执行的次数随着规模n的变化而变化,并且是线性变化
for(int i=0;i
int j=o;
j++;
}
线性对数阶\(O(nlog_2n)\)
说明: 将时间复杂度为\(O(log_2n)\)的代码重复执行n次,即为线性对数阶\(O(nlog_2n)\)
//n为一个固定的常数
//i和j均为循环变量
while(i
while(j
j=j*2;
}
}
平方阶\(O(n^2)\)
说明: 复杂度为\(O(n)\)的代码执行了n次。
for(int i=0;i
for(int j=0;j
int m=0;
m++;
}
}
立方阶O(n^3)
说明 和平方阶原理一样,时间复杂度为\(O(n^2)\)的代码执行n次
for(int i=0;i
for(int j=0;j
for(int k=0;k
int m=0;
m++;
}
}
}
综上分析不难发现:时间复杂度的大小关系为:\(O(1)
程序员必备排序算法
程序猿必备的排序算法有:
插入排序
简单直接插入
希尔排序
选择排序
简单选择排序
堆排序
交换排序
冒泡排序
快速排序
归并排序
基数排序(桶排序)
冒泡排序(Bubble Sort)
基本原理: 将待排序的数组从左到右(下标从小到大), 依次选取元素,并和其相邻的元素比较大小,如果逆序,则交换两个元素的位置,每进行一轮,数组较大的元素会移动到数组的尾部,如同水中泡泡逐渐上浮一样。重重复进行多轮操作,直到数组有序为止。
图解案例
以3 9 -1 10 20 为例进行讲解
冒泡排序的几个关键点
进行arr.length-1趟排序
每一趟排序均会将前面未被排序的最大元素“冒泡”到后半部分
每一趟进行两两元素的比较,n个元素需要比较n-1次即可
由于每一趟的任务都是将前面未经排序的部分中较大的元素“冒泡”到后面,也就是说经过i趟之后,数组的后面的i个元素都是已经排好序的。因此第i趟只需要进行arr.lenth-1-i次比较即可
Java代码实现部分
/**
* 优化的地方,当某一趟中,发现没有进行过任何交换操作,则表明数组已经有序了,此时可以立即结束操作,不必要进行循环操作。
*
* */
public class BubbleSort{
public static void bubbleSort(int arr[]){
int temp = 0;
boolean flag = false;// 表示是否进行过交换
for (int i = 0; i < arr.length - 1; i++) {//进行arr.length-1趟排序
for (int j = 0; j < arr.length - 1 - i; j++) {//每一趟排序都经过arr.length-1-i次两两比较
if (arr[j] > arr[j + 1]) {
// 交换
flag = true;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
//优化代码
if (flag == false) {
// 没有发生过交换,表明是有序的
break;
} else {
flag = false;// 重置flag,进行下次判断
}
}