前言:
折腾完了上一篇的增删改查,我们要往下一步走了。这一步可能相对难理解一些。但是,偏偏这些企业却很喜欢来考验面试者。哎,在群里看了几位大佬的面试,基本都是在考验我们的基础,基础稳了,就算难得那些不会也可以拿到offer。但是遗憾的是很多人都过度追求框架,对基础却有些忽略。犯了大忌,特别是坑爹的面试官,一来就直接上算法,什么二分查找,冒泡排序,选择排序等,不要钱的来,能不能好好交谈了。
不废话了,干活干活,撸起袖子就是撸代码,秀面试官一脸!
java数据结构与算法之排序和查找:
package com.ern.demo;
/**
*
* @author wen
*
*/
public class MyArray {
private static int[] a;
public MyArray() {
// 4 8 9 0 5 3 6 2 1
a = new int[10];
a[0] = 4;
a[1] = 8;
a[2] = 9;
a[3] = 0;
a[4] = 5;
a[5] = 3;
a[6] = 6;
a[7] = 2;
a[8] = 1;
a[9] = 7;
}
/**
* 二分查找(递归方式进行)
*
* @param args
* @param value
* @param low
* @param height
* @return
*/
public int selectTwo(int[] args, int value, int low, int height) {
// 查找前先排序
ArraySort3(args, low, height);
// 先判断输入的值是否符合规矩
if (value < args[low] || value > args[height] || low > height) {
return -1;
}
/**
* 找到中间值 例如10个数字,0 1 2 3 4 5 6 7 8 9 除以2找到中间的数( 0+9)/2=4
*/
int middle = (low + height) / 2;
/**
* 获取到中间的值,判断输入的值是大于还是小于数组中间的值 如果大于,往右边走,小于就往左走
*
* 例如: 10个数字,0 1 2 3 4 5 6 7 8 9 (1)小编我选7 (2)第四个即中间值是3
* (3)判断是否大于输入的值7,是的话往右走,不是往左走 (4)递归后接下来就是 的中间值是(1+9)/2=5
* (5)判断是否大于输入的值7,是的话往右走,不是往左走 (6)。。。。以此类推找到
*/
if (args[middle] > value) {
return selectTwo(args, value, low, height - 1);
} else if (args[middle] < value) {
return selectTwo(args, value, low + 1, height);
} else {
return middle;
}
}
/**
* 二分查找(非递归方式进行)
*
* @param args
* @param value
* @param low
* @param height
* @return
*/
public int selectTwo2(int[] args, int value, int low, int height) {
ArraySort3(args, low, height);
if (value < args[low] || value > args[height] || low > height) {
return -1;
}
// 原理和上面的一样。。只是不用递归的方法实现
while (low <= height) {
int middle = (low + height) / 2;
if (args[middle] < value) {
low = middle + 1;
} else if (args[middle] > value) {
height = middle - 1;
} else {
return middle;
}
}
return 0;
}
/**
* 查找相关元素的索引,考虑到相同元素
*
* @param args
* @param value
* @return
* @throws Exception
*/
public int[] select(int[] args, int value) throws Exception {
/**
* 遍历寻找有多少个相同,记录起来!!
*/
int count = 0;
for (int i = 0; i < args.length; i++) {
if (args[i] == value) {
count++;
}
}
/**
* 如果没有这个元素,就抛个异常玩玩
*/
if (count == 0) {
throw new Exception("没有找到相关元素");
}
/**
* 用来返回给他存在几个元素
*/
int[] f = new int[count];
// 用于数组增加
int flength = 0;
/**
* 再此遍历,找到相关索引,将他放入临时数组中
*/
for (int i = 0; i < args.length; i++) {
if (args[i] == value) {
f[flength] = i;
flength++;
}
}
return f;
}
/**
*
* 直接排序====== 将数组排序
*
* @param args
*/
public void ArraySort(int[] args) {
// 用一个临时变量,用来做中间人
int temp = 0;
for (int i = 0; i < args.length; i++) {
/**
* 这里的j=i+1的意思是,外层循环是第一个元素 不可能在和资金比较吧?
*
* 例如: 0 1 2 3 4 外层循环拿到数组里的第一个值是0 然后第二层循环,我们不可能还用0 和 0
* 比较是吧?没意义,所以我们i+1
*
*/
for (int j = i + 1; j < args.length; j++) {
/**
* 判断第一个是否大于后面的9个,是对换。外层循环就是控制第几个来比较! 例如: 4 5 1 6 3
*
* 外层循环拿到第一个 4 内层循环目的是 4 和 后面的 5 1 6 3 比较 如果 4大于 后面任何一个,就对换
* 第一次与后面对换 1 5 4 6 3 第二次与后面对换 1 5 4 6 3 。。。 都没有,就跳过,进入第二层循环
* 第一层结束后总体是: 1 5 4 6 3
*
* 接下来拿出第二个是5 第一次与后面对换 1 4 5 6 3 第二次与后面对换 1 3 5 6 4 。。。 以此类推。。。
*/
if (args[i] > args[j]) {
temp = args[i];
args[i] = args[j];
args[j] = temp;
}
}
}
/**
* 遍历出排序后所有元素
*/
for (int i = 0; i < args.length; i++) {
System.out.print(args[i] + " ");
}
}
/**
* 冒泡排序
*
* @param args
*/
public void ArraySort1(int[] args) {
/**
*
*/
for (int i = 0; i < args.length; i++) {
for (int j = 0; j < args.length - i - 1; j++) {
/**
* 冒泡排序真的特别无语,你们会懂的~~!!!
*
* 原理:第一个和第二个相比,第二个和第三个相比,以此进行排序, 排完后每轮会减掉最后一个。因为都最大了,,没必要在排序了吧
*
* 例如开始是这样滴: 8 7 9 0 6 3 5 1 2 第一次排序后 8和7交换了位置 : 7 8 9 0 6 3 5 1
* 2 第二次排序后 不变 第三次排序后 8和9交换了位置 : 7 8 0 9 6 3 5 1 2 以此类推,,,
*
* 外层第一轮结束后为: 7 8 0 6 3 5 1 2 9 第二轮开始:7 8 0 6 3 5 1 2 9
*
* 第一次排序后 8和0交换了位置 : 7 0 8 6 3 5 1 2 9 第二次排序后 8和6交换了位置 : 7 0 6 8
* 3 5 1 2 9 第三次排序后 8和3交换了位置 : 7 0 6 3 8 5 1 2 9 。。。以此类推
*
* 效率杠杆滴。。。但是作为经典排序。忍忍好了
*
*/
if (args[j] > args[j + 1]) {
int temp = args[j];
args[j] = args[j + 1];
args[j + 1] = temp;
}
}
}
/**
* 遍历数组并输出
*/
for (int i = 0; i < args.length; i++) {
System.out.print(args[i] + " ");
}
}
/**
* 选择排序(用于优化冒泡排序)
*
* @param args
*/
public void ArraySort2(int[] args) {
for (int i = 0; i < args.length; i++) {
/**
* 默认相信第一个是最小的
*/
int temp = args[i];
int index = i;
/**
* 遍历交换,如果找到比第一个还小的,记录下交换位置的索引和值
*/
for (int j = i + 1; j < args.length; j++) {
if (temp > args[j]) {
temp = args[j];
index = j;
}
}
/**
* 这里做交换,index!=i的原因是如果最后一个了
* 最后一个index和i是相等的了。。相等了就算了吧。比也没意思了
*/
if (index != i) {
args[index] = args[i];
args[i] = temp;
}
}
for (int i = 0; i < args.length; i++) {
System.out.print(args[i] + " ");
}
}
/**
* 快速排序(不是特别懂)
*
* 原理是拆分,分而治之。这样速度回快很多。例如有 10 20 50 30 29 我们以50为拆分点。拆分成2部分,一部分是10 20 一部分是30
* 29
*
* @param args
* 传入的数组
* @param low
* 最小,默认为0
* @param height
* 最大,应该为数组的长度
*/
public void ArraySort3(int[] args, int low, int height) {
int i, j, index;
if (low > height) {
return;
}
i = low;
j = height;
/**
* 默认拿的第一个为最小
*/
index = args[i];
while (i < j) {
/**
* 例子: 4 8 9 0 5 3 6 2 1
* 第一个while时 i=0 j=8 index==args[0]==4
* 第一轮 j=8
* 1 8 9 0 5 3 6 2 1
* i=1
* 之后是8大于4所以不走。
* i=1 j=8 所以
* j=7 i =1 args[8]=8
*
* 继续这么一步步的切,分成2个部分,每个部分在分。。。一下就排序好了。
*/
while (i < j && args[j] >= index) {
j--;
}
if (i < j) {
args[i++] = args[j];
}
while (i < j && args[i] < index) {
i++;
}
if (i < j) {
args[j--] = args[i];
}
}
args[i] = index;
ArraySort3(args, low, i - 1);
ArraySort3(args, i + 1, height);
}
public static void main(String[] args) {
MyArray array = new MyArray();
array.ArraySort3(a,0,a.length-1);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
}
}
上面的原理与执行过程,例子都有举出来。这里仅仅提供一个思路,如果有更好的方法欢迎私信小编。小编就没有画图来演示了。第一嫌麻烦。第二练习看文字来理解的功底。第三小编懒呀。。
总结:
冒泡排序的原理就是对比后兑换,而且执行N多次,效率杠杠滴低,无言以对。直接排序就是对比,然后两个互相换位置,这个还是比较好理解的。选择排序是默认选择一个作为最小,然后和其他对比调换位置,和直接差不多。快速排序这个玩意,气人就算了而且还是比较难理解的,它采用的方法是分而治之,就像是微服务,将一个大的整体分成一部分一部分拆出来。这样排序的效率就真的是杠杠滴。
二分查找的原理简单,就是取中间人(前提是排好序了),然后不断取中间的值来对比,相对来说比从到到尾撸一遍的循环好很多。
程序人生,与君共勉!