1.二分查找
代码
普通代码
public static int ErFenSearch(int[] a,int target) {
int low = 0,hight = a.length-1,m;
while (low<=hight){
//避免查找溢出
m = (hight - low)/2 + low;
if(a[m] == target){
return m;
}else if(a[m] < target){
low = m+1;
}else if(a[m] > target){
hight = m-1;
}
}
return -1;
}
优化效率
位运算比除法效率高,并且解决溢出问题
m = (hight - low)/2 + low;替换成 m = (hight + low)>>>1;
面试
面试题
技巧
- 奇数二分取中间
- 偶数二分取中间靠左
- 2n等于数组长度
- 问题转换成log2128,可以转换成log10128/log102
- 如果是整数,则为结果
- 如果为小数,则省去小数,整数加一
注:
在实际中,二分查找左右边界选取可能会不同,进而影响选择的答案
2.排序
1.冒泡排序
通过判断是否交换过元素进行初步优化
public static void maopao(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
//判断数组是否已经排好序,减少冒泡次数
boolean sw = false;
for (int j = 0; j < a.length - 1 - i; j++) {
if (a[j] > a[j + 1]) {
swap(a, j, j + 1);
sw = true;
}
}
if (!sw){
System.out.println("第"+(i+1)+"次排序结束,退出循环");
break;
}
}
}
通过记录最后一次交换的位置,进一步优化
public static void maopao2(int[] a) {
int lastNum = a.length - 1;
do {
//记录最后一次交换的位置
int last = 0;
for (int j = 0; j < lastNum; j++) {
if (a[j] > a[j + 1]) {
swap(a, j, j + 1);
last = j;
}
}
lastNum = last;
} while (lastNum != 0);
}
2.选择排序
每次选择最小值与当前值进行交换
public static void select(int[] a){
for (int i = 0; i < a.length -1; i++) {
int min = i;
for (int j = i;j< a.length;j++){
if(a[j]<a[min]){
min = j;
}
}
if(i!=min) {
swap(a, i, min);
}
}
}
与冒泡相比:
1.两者的时间复杂度都为O(n2)
2.选择一般快于排序,交换次数少
3.若集合的有序度高,冒泡优于选择
4.冒泡属于稳定算法,选择属于不稳定算法
3.插入排序
private static void charu(int[] a){
for (int i = 1; i < a.length; i++) {
//将待交换的值进行临时存储
int temp = a[i];
int j = i-1;
while (j>=0){
if (temp<a[j]){
a[j+1] = a[j];
}else {
//i之前的值已经排好序,减少比较次数
break;
}
j--;
}
a[j+1] = temp;
}
}
优化方式
- 待插入元素遇到比自己小的元素时,后序无须比较
- 插入时可以直接移动,而不是交换数据
与选择排序比较
- 两者平均时间复杂度都是O(n2)
- 大部分情况下插入优于选择
- 有序集合插入的时间复杂度为O(n)
- 插入属于稳定排序算法,选择属于不稳定排序算法
4.快速排序
单边循环实现快排
private static void kuaipai(int[] a, int low, int hight) {
if (low >= hight) {
return;
}
//快排基准点
int std = a[hight];
//基准点的边界
int i = low;
for (int j = low; j < hight; j++) {
if (a[j] < std) {
if (i != j) {
swap(a, i, j);
}
i++;
}
}
//交换基准点和边界值
if (i != hight) {
swap(a, i, hight);
}
kuaipai(a, low, i - 1);
kuaipai(a, i + 1, hight);
}
单边循环有边界作为标准
双边界循环
private static void kuaipai2(int[] a, int low, int high) {
int std = a[low];
int i = low;
int j = high;
while (i < j) {
//从右边找小于基准值
while (i < j && std < a[j]){
j--;
}
//从左边找大于基准值
//=防止交换基准值
while (i < j && std >= a[j]){
i++;
}
swap(a,i,j);
}
swap(a,low,i);
kuaipai(a, low, i - 1);
kuaipai(a, i + 1, high);
}
特点:
- 平均时间复杂度是O(nlog2n)最坏情况是O(n2)
- 数据量较大时,优势非常明显
- 属于不稳定排序