排序算法
冒泡排序
//冒泡排序
public class Bubble {
//对数组a中的元素进行排序
public static void sort(Comparable[] a){
for (int i = a.length - 1; i > 0;i --){
for (int j = 0; j < i; j++){
if(greater(a[j],a[j+1])){
exch(a,j,j+1);
}
}
}
}
//比较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;
}
}
选择排序
//选择排序
public class Selection {
//对数组a进行排序
public static void sort(Comparable[] a){
for (int i = 0; i <= a.length - 2; i++) {
//加定本次遍历,最小值所在的索引是i
int minIndex = i;
for (int j = i+1; j < a.length; j++) {
if (greater(a[minIndex],a[j])){
minIndex = j;
}
}
//交换i索引处和minIndex索引处的值
exch(a,i,minIndex);
}
}
//比较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;
}
}
插入排序
//插入排序
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;
}
}
希尔排序
//希尔排序
public class Shell {
//对数组a元素进行排序
public static void sort(Comparable[] a){
int N = a.length;
//确认增长量h的最大值
int h = 1;
while (h < N / 2){
h = h * 2 + 1;
}
//当增长量h小于1.排序结束
while ( h>= 1){
//找到待插入元素
for (int i = h; i < N; i++) {
//a[i]就是待插入元素
//把a[i]插入到a[i-h],a[i-2h],a[i-3h]...序列中
for (int j = i; j >= h ; j-=h) {
//a[j]就是待插入元素,依次和a[j-h],a[j-2h],a[j-3h]进行比较,如果a[j]小,那么
//交换位置,如果不小于,a[j]大,则插入完成
if(greater(a[j - h],a[j])){
exch(a,j,j-h);
}else {
break;
}
}
}
h/=2;
}
}
/*
比较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;
}
}
归并排序
//归并排序
public class Merge {
private static Comparable[] assist;
//对数组a中元素进行排序
public static void sort(Comparable[] a){
assist = new Comparable[a.length];
int lo = 0;
int hi = a.length - 1;
sort(a, lo, hi);
}
//对数组a中从lo到hi的元素进行排序
private static void sort(Comparable[] a, int lo, int hi) {
if(hi <= lo){
return;
}
int mid = lo + (hi - lo) / 2;
//对lo到mid之间的元素进行排序;
sort(a,lo,mid);
//对mid+1到hi之间的元素进行排序;
sort(a, mid+1, hi);
//对lo到mid这组数据和mid到hi这组数据进行归并
merge(a,lo,mid,hi);
}
//对数组中,从lo到mid为一组,从mid+1到hi为一组,对这两组数据进行归并
private static void merge(Comparable[] a, int lo, int mid, int hi) {
//lo到mid这组数据和mid+1到hi这组数据归并到辅助数组assist对应的索引处
int i = lo;//定义一个指针,指向assist数组中开始填充数据的索引
int p1 = lo;//定义一个指针,指向第一组数据的第一个元素
int p2 = mid + 1;//定义一个指针,指向第二数据的第一个元素
//比较左边小组和右边小组中的元素大小,哪个小,就把哪个数据填充到assist数组中
while (p1 <=mid && p2 <=hi){
if (less(a[p1],a[p2])){
assist[i++] = a[p1++];
}else{
assist[i++] = a[p2++];
}
}
//上面的循环结束后,如果退出循环的条件是p1<=mid,则证明左边小组中的数据已经归并完毕,如果退
//出循环的条件是p2<=hi,则证明右边小组的数据已经填充完毕;
//所以需要把未填充完毕的数据继续填充到assist中,
// 下面两个循环,只会执行其中的一个
while (p1 <= mid){
assist[i++] = a[p1++];
}while (p2 <= hi){
assist[i++] = a[p2++];
}
//到现在为止,assist数组中,从lo到hi的元素是有序的,再把数据拷贝到a数组中对应的索引处
for (int index = lo; index <= hi ; index++) {
a[index] = assist[index];
}
}
//比较v元素是否小于w元素
private static boolean less(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;
}
}
快速排序
//快速排序
public class Quick {
public static void sort(Comparable[] a){
int lo = 0;
int hi = a.length - 1;
sort(a,lo,hi);
}
private static void sort(Comparable[] a, int lo, int hi) {
if(hi <= lo){
return;
}
//对a数组中,从lo到hi的元素进行切分
int partition = partition(a, lo, hi);
//对左边分组中的元素进行排序
sort(a,lo,partition-1);
//对右边分组中的元素进行排序
sort(a,partition+1,hi);
}
private static int partition(Comparable[] a, int lo, int hi) {
Comparable key = a[lo];//把最左边的元素当做基准值
int left = lo;//定义一个左侧指针,初始指向最左边的元素
int right = hi+1;//定义一个右侧指针,初始指向最右侧的元素下一个位置
//进行切分
while (true) {
//先从右往左扫描,找到一个比基准值小的元素
while (less(key, a[--right])) {//循环停止,证明找到了一个比基准值小的元素
if (right == lo) {
break;//已经扫描到最左边了,无需继续扫描
}
}
while (less(a[++left],key)){//循环停止,证明找到了一个比基准值大的元素
if(left == hi){
break;
}
}
if(left >= right){
break;//扫描完了所有元素,结束循环
}else{
exch(a,left,right);//交换left和right索引处的元素
}
}
//交换最后rigth索引处和基准值所在的索引处的值
exch(a,lo,right);
return right;//right就是切分的界限
}
//比较v元素是否小于w元素
private static boolean less(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;
}
}
二分查找(二分查找的前提, 数组必须有序)
/**
* 此方法用于使用二分查找的方式, 在数组中查询出指定值存在的索引并返回
*/
public static int binarySearch(int[] arr, int target) {
// 开始索引
int startIndex = 0;
// 结束索引
int endIndex = arr.length - 1;
// 循环要放在计算中间索引的前面, 因为每一次循环都要重新计算中间索引
while (startIndex <= endIndex) {
// 中间索引
int middleIndex = (startIndex + endIndex) / 2;
// 如果中间索引元素 大于 目标值
if (arr[middleIndex] > target) {
// 修改结束索引
endIndex = middleIndex - 1;
} else if (arr[middleIndex] < target) {
// 修改开始索引
startIndex = middleIndex + 1;
} else {
// 猜中了
return middleIndex;
}
}
// 如果循环结束, 说明没找到, 数组中不存在目标值
return -1;
}
排序算法空间和时间复杂度比较
异常处理
什么是异常:指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
异常分类
-
error:我们不能处理,只能尽量避免,例如:内存溢出,服务器宕机,数据库崩溃
-
Exception
- 编译时异常:除了RuntimeException,其他都是编译时异常,必须处理(如日期格式化异常)
- 运行时异常:RuntimeException和它的子类可以处理,但一般不会处理,因为运行时异常的出现一般是因为我们犯了错误,会修改代码(如数学异常)
Throwable
如何处理异常
-
throw
-
throws
-
try…catch
- 注意
-
try…catch…finally
自定义异常
- 是什么?:在开发中根据自己业务的异常情况来定义异常类.自定义一个业务逻辑异常:LoginException。一个登陆异常类。
- 如何定义:
异常名描述和处理
- ArrayIndexOutOfBoundsException:数组索引越界异常,访问了不存在的索引
- StringIndexOutOfBoundsException :
- IndexOutOfBoundsException
- NullPointerException::空指针异常,使用null
- ClassCastException:类型转换异常,A对象强转成B
- NoSuchElementException:没有这个元素异常,迭代器遍历中,已经没有元素了,继续调用next()方法
- ConcurrentModificationException:并发修改异常,使用迭代器遍历过程中,用集合的方法增删了集合中的元素
- ArithmeticException:数学运算异常,除0了
- ParseException:编译时异常解析异常,parse方法解析的时候,格式不匹配
多线程
并行和并发
- 并发:指两个或多个事件在同一时刻发生(同时发生)
- 并发:指两个或多个事件在同一时间段内发生(交替执行)
进程和线程
[{“src”:“xap:resources/284119c374493dfcfce55a02a4e861579f8bd42c1e769c85e3e7e45a66c8c7c7.png”,“width”:963,“height”:260}]
- 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
- 线程:是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
- 注意:
线程调度:
开始线程
-
继承Thread
-
Thread类的构造方法:
-
Thread类的常用方法:
-
方式:
-
-
重写runable:
- 匿名内部类
- 匿名内部类