1 算法分析
1.1 时间复杂度
比较算法随着输入规模的增长量的规则
1.常数可以忽略;
2.最高次幂的常数因子可以忽略;
3.算法函数中最高次幂越小,算法效率越高。
常见时间复杂度总结
- 复杂程度排序:
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3) - 尽可能的追求O(1),O(logn),O(n),O(nlogn)这几种时间复杂度
- 如果发现算法的时间复杂度为平方阶、立方阶或者更复杂的,那我们可以认为这种算法是不可取的,需要优化
1.2 空间复杂度
基本数据类型内存占用情况
数据类型 | 内存占用字节数 |
---|---|
byte | 1 |
short | 2 |
int | 4 |
long | 8 |
float | 4 |
double | 8 |
boolean | 1 |
char | 2 |
- 计算机访问内存:每次1个字节
- 一个引用(机器地址):8个字节
例如: Date date = new Date(),则date这个变量需要占用8个字节来表示 - 一个对象的头信息:16字节
例如new Date(),除了Date对象内部存储的数据(例如年月日等信息)占用的内存,该对象本身也有内存开销,每个对象的自身开销是16个字节,用来保存对象的头信息。 - 一般内存的使用,如果不够8个字节,都会被自动填充为8字节,以8为单位
- 数组被限定为对象,一般会因为记录长度而需要额外的内存,一个原始数据类型的数组一般需要24字节的头信息(16个自己的对象开销,4字节用于保存长度以及4个填充字节)再加上保存值所需的内存
public class A {
public int a=1;
}
/*
通过new A()创建一个对象,其内存占用情况如下:
1、整型成员变量a占用4个字节
2、对象本身占用16个字节
3、由于4+16=20字节不是以8个字节为单位,所以会自动填充为24个字节
*/
1.3 算法稳定性
定义
数组arr中有若干元素,其中A元素和B元素相等,且A元素在B元素前面,如果使用某种排序算法排序后,能保证A元素依然在B元素前面,就可以说这个算法 稳定的
如果一组数据需要多次排序,稳定性是有意义的,可以保持第一次排序原有的意义而且可以减少系统开销
稳定的: 冒泡、插入、归并
不稳定的: 选择、希尔、快速
2 简单排序
排序方法 | 简述 |
---|---|
冒泡排序 | 相邻比较(太慢) |
选择排序 | 每次选最小(不稳) |
插入排序 | 分组,未排序组的元素与每一个已排序组的元素进行比较(样本小且基本有序时效率比较高) |
2.1 Comparable接口
//学生类
public class Student implements Comparable<Student>{
private String username;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"username='" + username + '\'' +
", age=" + age +
'}';
}
//定义比较规则
@Override
public int compareTo(Student o) {
return this.getAge()-o.getAge();
}
}
//测试类
public class Test {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.setUsername("zhangsan");
stu1.setAge(17);
Student stu2 = new Student();
stu2.setUsername("lisi");
stu2.setAge(19);
Comparable max = getMax(stu1, stu2);
System.out.println(max);
}
//测试方法,获取两个元素中的较大值
public static Comparable getMax(Comparable c1,Comparable c2){
int cmp = c1.compareTo(c2);
if (cmp>=0){
return c1;
}else{
return c2;
}
}
}
2.2 冒泡排序
public class BubbleSort {
//冒泡排序算法封装
public static void bubbleSort(int[] arr) {
int temp=0; //临时变量
boolean flag=false; //标识变量,是否进行过交换
for(int i=0;i<arr.length-1;i++) {
for(int j=0;j<arr.length-1-i;j++){
//如果前面的数比后面的数大,则交换
if(arr[j]>arr[j+1]){
flag=true;
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
if(!flag) //在一趟排序中一次都没有交换过
break;
else
flag=false; //重置后进行下一次判断
}
}
//测试
public static void main(String[] args) {
int arr[]={3, 0, -1, 10, 7};
bubbleSort(arr);
}
}
2.3 选择排序
public class SelectSort {
//选择排序算法封装
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length-1; i++) {
int minIndex = i;
int min = arr[i];
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
min = arr[j];
minIndex = j;
}
}
// 将最小值,放在最前面, 即交换
if (minIndex != i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
}
//测试
public static void main(String[] args) {
int [] arr = {101, 34, 119, 1, -1, 90, 123};
selectSort(arr);
}
}
2.4 插入排序
public class Insertion {
//对数组a中的元素进行排序
public static void sort(Comparable[] a){
for (int i=1;i<a.length;i++){
//当前元素为a[i],依次和i前面的元素比较,找到一个小于等于a[i]的元素
for (int j=i;j>0;j--){
if (greater(a[j-1],a[j])){
//交换元素
exch(a,j-1,j);
}else{
break;
}
}
}
}
//比较v元素是否大于w元素
private static boolean greater(Comparable v,Comparable w){
return v.compareTo(w)>0;
}
//数组元素i和j交换位置
private static void exch(Comparable[] a,int i,int j){
Comparable t = a[i];
a[i]=a[j];
a[j]=t;
}
}