排序算法
冒泡排序:相邻比较,交换位置
实际复杂度O(n^2),空间复杂度O(1),稳定的
public static void main(String[] args) {
int [] arr = new int[10];
Random r = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i]=r.nextInt(100);
}
System.out.println(Arrays.toString(arr));
//冒泡排序
for (int i = 1; i < arr.length; i++) {
for (int k = 0; k < arr.length-i; k++) {
if (arr[k]>arr[k+1]) {
int tmp =arr[k];
arr[k]=arr[k+1];
arr[k+1]=tmp;
}
}
}
System.out.println(Arrays.toString(arr));
}
快速排序:通过一次排序将序列分为左右两部分,其中左半部分的值都小于右半部分的值,然后再对左右部分的数据进行排序,直到所有数据都有序。
总结:时间复杂度O(NlogN),空间复杂度为O(1),不稳定
public static void main(String[] args) {
int [] arr = new int[10];
Random r = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i]=r.nextInt(100);
}
System.out.println(Arrays.toString(arr));
//快速排序测试
quicksort(arr, 0, arr.length-1);
System.out.println(Arrays.toString(arr));
}
//快速排序
public static void quicksort(int arr [],int begin,int end ) {
if (begin<end) {
int low =begin;
int high =end;
int povit=arr[low];
while (low<high) {
while (low<high && arr[high]>=povit) {
high--;
}
arr[low]=arr[high];
while (low<high && arr[low]<=povit) {
low++;
}
arr[high]=arr[low];
}
arr[low]=povit;
quicksort(arr, begin, low-1);
quicksort(arr, low+1, end);
}
}
查找算法:
顺序查找:时间复杂度O(n)
public static void main(String[] args) {
int [] arr = new int[10];
Random r = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i]=r.nextInt(100);
}
int target=24;
arr[4]=target;
int pos=-1;
for (int i = 0; i < arr.length; i++) {
if (target==arr[i]) {
pos=i;
break;
}
}
System.out.println(Arrays.toString(arr));
System.out.println(pos);
}
折半查找
前提:数据必须有序
时间复杂度为O(logN)
public static void main(String[] args) {
int [] arr = new int[10];
Random r = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i]=r.nextInt(100);
}
System.out.println(Arrays.toString(arr));
arr[4]=25;
//折半查找的前提是数据必须有序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
int pos = binarySearch(arr, 25);
System.out.println(pos);
}
//折半查找
public static int binarySearch(int [] arr,int key ) {
int min=0;
int max=arr.length-1;
int mid=-1;
while (min<max) {
mid=(min+max)/2;
if (arr[mid]<key) {
min=mid;
}else if(arr[mid]>key) {
max=mid;
}else {
return mid;
}
}
return -1;
}
链表的实现:
线性表在一个序列中除去头尾元素,每个元素都有一个直接前驱和直接后续,头没有前驱,尾没有后续有数组和链表两种实现
数组:物理上的连续存放、支持随机访问、读快但是增删慢
链表:物理上并不会连续存放、不支持随机访问、读慢但是增删快
如果频繁进行增删优先考虑使用链表,如果频繁进行随机访问优先考虑使用数组
链表和数组对比
数组使用连续的内存空间存储数据,可以有效地利用CPU缓存机制,预读数组中的数据,从而提高访问效率;链表在内存中不连续,没有办法支持预读处理,对CPU缓存不友好。
数组大小固定,一旦声明就占用整块的连续内存空间,扩容复制非常耗时。链表不需要额外的存储空间【int】,链表中的元素Node需要额外的存储空间,会造成一定程度上的内存空间浪费,而且频繁的内存申请和释放,容易产生内存碎片。
集合框架回顾
Collection接口:无序、允许重复,顶级接口(Iterable接口)
List接口是Collection接口的子接口,有序、允许重复(ArrayList、Vector和LinkedList)
Set接口是Collection接口的子接口,无序、不允许重复(HashSet、LinkedHashSet、TreeSet)
Collection接口中的方法 | List接口中的方法 |
add(E e):boolean在集合末尾追加元素 remove(E e):boolean删除指定的元素 clear():void 清空 contains(Object):Boolean判断是否包含指定元素 isEmpty():boolean 判断集合为空 size():int元素个数 iterate():Iterator迭代集合中的所有元素 toArray():Object[] | add(int index,Object obj):void在指定位置上添加元素 get(int index):object可以获取位置上的元素 remove(int index):Object 删除指定位置上的元素,并返回删除的数据 set(int index,Object obj):Object 修改指定位置上的元素,并返回原始数据 indexOf(Object):int查找元素的下标位置 |
实现类
ArrayList底层实现是数组,查询快、增删慢,线程不安全,效率高,可以存储重复元素
LinkedList底层实现是双向链表,查询慢、增删快【定位位置O(n)】,线程不安全,效率高,可以存储重复元素
Vector底层实现数组,查询快、增删慢,线程安全,效率较低,可以存储重复元素
ArrayList
内部实现是数组,实现了RandomAccess接口,支持随机访问功能,不是一个线程安全的容器
具体元素的移动和拷贝都是通过System.arrayCopy实现的
构造器:ArrayList()内部存储数据的数组为空数组
elementData保存数据
capacity容器 ArrayList(int),默认容积10
当容器容积不足时,会自动进行扩容处理,容积增大50%
modcount快速失败
add方法:添加元素时首先仅从范围检查,然后和建议分配的大小值进行比较,如果大于默认大小则进行扩容。扩容时首先将原始数组的大小提升到1.5倍,称为新数组大小,然后进行元素的拷贝
remove方法
线程安全的替代方案:Collections.sychronizedList CopyOnWriteArrayList
LinkedList
双向链表,没有长度限制
删除remove(Object)虽然删除操作时间复杂度为O(1),但是定位元素的时间复杂度为O(n)