基本排序算法
Java中常见的排序算法有7种:冒泡、插入、选择、快速、希尔、归并和堆
冒泡排序
核心思想是:相邻比较,交换位置
时间复杂度O(n**2),空间复杂度O(1),稳定的
public class Test1 {
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 temp=arr[k];
arr[k]=arr[k+1];
arr[k+1]=temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
快速排序
思路:通过一次排序将序列分为左右两部分,其中左半部分的值都小于右半部分的值,然后再对左右部分的数据进行排序,直到所有数据都有序
总结:时间复杂度O(NlogN),空间复杂度为O(1),不稳定
public class Test2 {
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 low, int high) {
if (low >= high)
return;
int pos = part(arr, low, high);
quickSort(arr, low, pos - 1);
quickSort(arr, pos + 1, high);
}
public static int part(int[] arr, int low, int high) {
int key = arr[low];
while (low < high) {
while (low < high && arr[high] >= key)
high--;
arr[low] = arr[high];
while (low < high && arr[low] <= key)
low++;
arr[high] = arr[low];
}
arr[low] = key;
return low;
}
}
查找算法
Java中常见的查找算法:顺序查找、折半查找、二叉树、哈希表、分块查找
顺序查找
时间复杂度O(n)
int[] arr={12,3,24,15,56};
int target=24;
int pos=-1;//如果查找不到则返回-1
for(int i=0;i<arr.length;i++){
if(target==arr[i]){
pos=i;
break;
}
}
折半查找
前提:数据必须有序
时间复杂度为O(logN)
public class Test1 {
public static void main(String[] args) {
int[] arr = new int[11];
Random r = new Random();
for (int i = 0; i < arr.length - 1; i++)
arr[i] = r.nextInt(100);
arr[arr.length - 1] = 36; // 折半查找的前提是数据必须有序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
int pos=binarySearch(arr, 34);
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) >> 1;
if (key > arr[mid])
min = mid + 1;
else if (key < arr[mid])
max = mid - 1; elsereturn mid; }return -1;
}
}
链表的实现
线性表在一个序列中除去头尾元素,每个元素都有一个直接前驱和直接后续,头没有前驱,尾没有后续有数组和链表两种实现
-
数组:物理上的连续存放、支持随机访问、读快但是增删慢
-
链表:物理上并不会连续存放、不支持随机访问、读慢但是增删快
-
如果频繁进行增删优先考虑使用链表,如果频繁进行随机访问优先考虑使用数组
class Node{
private int data;//具体存储数据
private Node next;//指向下一个元素的指针
}
链表和数组对比
数组使用连续的内存空间存储数据,可以有效地利用CPU缓存机制,预读数组中的数据,从而提高访问效率;链表在内存中不连续,没有办法支持预读处理,对CPU缓存不友好
数组大小固定,一旦声明就占用整块的连续内存空间,扩容复制非常耗时。链表不需要额外的存储空间【int】,链表中的元素Node需要额外的存储空间,会造成一定程度上的内存空间浪费,而且频繁的内存申请和释放,容易产生内存碎片
集合框架回顾
Collection接口:无序、允许重复,顶级接口(Iterable接口)
-
List接口是Collection接口的子接口,有序、允许重复
- ArrayList、Vector和LinkedList
-
Set接口是Collection接口的子接口,无序、不允许重复
- HashSet、LinkedHashSet、TreeSet
数组和集合的区别
-
长度的区别:数组长度固定,集合可变
-
内容的区别:数组可以是基本类型,也可以是引用类型;集合中只能是引用类型
-
元素内容:数组只能存储同一类型,集合中可以存储不同的数据类型
Collection接口中的方法
-
add(E e):boolean在集合末尾追加元素
-
remove(E e):boolean删除指定的元素
-
clear():void 清空
-
contains(Object):Boolean判断是否包含指定元素
-
isEmpty():boolean 判断集合为空
-
size():int元素个数
-
iterate():Iterator迭代集合中的所有元素
-
toArray():Object[]
遍历集合中的所有元素
for(Object tmp:collection){}
使用迭代器
Iterator it=collection.iterator();
while(it.hasNext()){
Object tmp=it.next();
}
List接口
-
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)
练习题
输入一个链表,反转链表后,输出新链表的表头
public ListNode reverseList(ListNode head){
if(head==null)
return null; //判断链表是否为空,为空的化直接返回null
ListNode prev=null; //前一个结点
ListNode next=null; //后一个结点
while(head!=null){
next=head.next;
head.next=prev;
prev=head;
head=next;
}
return prev;
}