认识时间复杂度
常数时间的操作:一个操作如果和数据量没有关系,每次都是固定时间内完成的操作,这叫常数操作,如加减乘数,数组的寻址操作
时间复杂度作为一个算法流程中,常数操作数量的指标。常用O(读作big O)来表示。具体来说,在常数操作数量的表达式中,只要高阶项,不要低阶项,也不要高阶项的系数,剩下的部分如果记为f(N),那么时间复杂度为O(f(N))。
评价一个算法流程的好坏,先看时间复杂度的指标,然后再分析不同数据样本下的实际运行时间,也就是常数项时间。
额外复杂空间O(1)
完成一个算法时,如无序数组的排序,除了给出的数组本身的内存空间,完成这个数组排序如需要新建一个数组辅助完成本次排序,新建的数组所占的内存空间称为额外复杂空间,如新建的数组长度为n,则额外复杂空间为O(n),以此类推。
对数器
当我们设计一个算法时,并不能准确的验证该算法的正确性,此时,我们可以借助对数器这个方法,可以很大效率的帮助我们验证自己算法的准确度。这无疑对我们是一个很大的帮助。什么是对数器呢?
对数器的概念和使用
0、有一个你想要测的方法a。
1、实现一个绝对正确但是复杂度不好的方法b。
2、实现一个随机样本产生器。
3、实现对比的方法。
4、把方法a和方法b对比很多次来验证方法a是否正确。
5、如果有一个样本使得对比出错,打印样本分析是哪个方法出错。
6、当样本数量很多时对测试依然正确,可以确定方法a已经正确。
常见的排序方法
- 冒泡排序
public class Code_BubbleSort {
public static void bubbleSort(int [] arr) {
for(int i=0;i<arr.length;i++) {
if(arr == null || arr.length<2) {
return ;
}
for(int j=1;j<arr.length-i;j++) { //每次遍历都将最大的元素排到最后
if(arr[j-1]>arr[j]) {
swap(arr,j-1,j);
}
}
}
}
public static void swap(int []arr,int i,int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
分析:冒泡算法是常见的排序算法之一,排序简单,时间复杂度为O(n*n),对于大量的数据集不建议采用冒泡排序算法
- 选择排序
选择排序是将相邻的两个元素进行比较,找到元素最小的下标,进行数据交换。
public class Code_SelectSort {
public static void selectSort(int[] arr) {
if(arr == null || arr.length < 2) {
return;
}
for(int i=0;i<arr.length;i++) {
int minIndex = i;
for(int j = i+1;j<arr.length;j++) {
if(arr[j]<arr[minIndex]) {
minIndex = j;
}
if(minIndex != i) {
swap(arr, i, minIndex);
}
}
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
分析:时间复杂度为O(n * n),在现在的大部分架构设计或者是业务逻辑中很少用到选择排序算法了
- 插入排序
插入排序也是一种常见的排序方法,相对于冒泡排序和选择排序,插入排序在排序过程中,依次选择待排序元素与排序好的元素进行对比,如果小于当前元素及前面的元素,则将该元素插入到指定的位置。是一种比较抽象的排序方法
public class Code_InsertSort {
public static void insertSort(int [] arr) {
if(arr == null || arr.length < 2) {
return;
}
for(int i = 1;i<arr.length;i++) {
for(int j = i-1 ;j>=0 && arr[j] > arr[j+1] ;j--) {
swap(arr, j, j+1);
}
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
分析:时间复杂度为O(n * n),虽然比较抽象,但是插入排序还是会被经常运用于实现于数据排序的业务逻辑中
使用对数器来验证插入排序的正确性
public class TestInsertSort {
//正确方法
public static void rightMethod(int [] arr) {
Arrays.sort(arr);
}
// 产生随机的数组
public static int [] generateRandomArray(int size, int value) {
int [] arr = new int[(int)((size + 1) * Math.random())];
for(int i=0; i<arr.length; i++) {
arr[i] = (int) ((value + 1) * Math.random() - (int)(value * Math.random()));
}
return arr;
}
// 复制数组
public static int[] copyArray(int [] arr) {
if(arr == null) {
return null;
}
int [] array = new int[arr.length];
for(int I=0;i<arr.length;i++) {
array[I] = arr[i];
}
}
//插入排序
public static void insertSort(int [] arr) {
if(arr == null || arr.length < 2) {
return;
}
for(int i = 1;i<arr.length;i++) {
for(int j = i-1 ;j>=0 && arr[j] > arr[j+1] ;j--) {
swap(arr, j, j+1);
}
}
}
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 判断两个数组是否相等
public static boolean isEquals(int []arr1, int []arr2) {
if( (arr1 == null && arr2 !=null) || (arr1 != null && arr2 == null)) {
return false;
}
}
if(arr1 == null && arr2 == null) {
return false;
}
if(arr1.length != arr2.length) {
return false;
}
for(int i=0;i<arr1.length;i++) {
if(arr1[i] == arr2[I]) {
return true;
}
}
return false;
}
public static void display(int [] arr) {
for(int i=0;i<arr.length;i++) {
System.out.print(arr[i]+ " ");
}
System.out.println("");
}
public static void main(String []args) {
int testTime = 50000;
int size = 10;
int value = 100;
boolean succeed = true;
for(int i=0; i<testTime;i++) {
int [] arr1 = generateRandomArray(size,value);
int [] arr2 = copyArray(arr1);
int [] arr3 = copyArray(arr1);
insertSort(arr1);
rightMethod(arr2);
if(!isEquals(arr1,arr2)) {
succeed = false;
display(arr3);
break;
}
}
System.out.printLn(succeed ? "Nice": "What the Fuck");
}
}
网友评论