基本,二分,插值,斐波那契
基本查找
public class A01_BasicSearchDemo1 {
public static void main(String[] args) {
int[] arr = {131, 127, 147, 81, 103, 23, 7, 79};
int number = 82;
System.out.println(basicSearch(arr, number));
}
public static boolean basicSearch(int[] arr, int number){
for (int i = 0; i < arr.length; i++) {
if(arr[i] == number){
return true;
}
}
return false;
}
}
练习题1
//课堂练习1:
//需求:定义一个方法利用基本查找,查询某个元素在数组中的索引
//要求:不需要考虑数组中元素是否重复
public class A01_BasicSearchDemo2 {
public static void main(String[] args) {
int[] arr = {131, 127, 147, 81, 103, 23, 7, 79};
int number = 82;
basicSearch(arr, number);
}
public static int basicSearch(int[] arr, int number) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == number) {
System.out.println("找到了数字" + number);
return i;
}
}
System.out.println("没有找到数字" + number);
return -1;
}
}
练习题2
//课堂练习2:
//需求:定义一个方法利用基本查找,查询某个元素在数组中的索引
//要求:需要考虑数组中元素有重复的可能性
//{131, 127, 147, 81, 103, 23, 7, 79, 81}
//我要查找81,想要返回的是所有索引 3 8
public class A01_BasicSearchDemo2 {
public static void main(String[] args) {
int[] arr = {131, 127, 147, 81, 103, 23, 7, 79, 81};
int number = 81;
basicSearch2(arr, number);
}
public static void basicSearch2(int[] arr, int number) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == number) {
list.add(i);
}
}
System.out.print("我要查找" + number + ",想要返回的是所有索引");
if (list.isEmpty()) {
System.out.println("没有找到数字" + number);
} else {
for (int j : list) {
System.out.print(" " + j);
}
}
}
}
二分查找/折半查找
//二分查找/折半查找
//核心:
//每次排除一半的查找范围
//需求:定义一个方法利用二分查找,查询某个元素在数组中的索引
//数据如下:{7, 23, 79, 81, 103, 127, 131, 147}
public class A02_BinarySearchDemo1 {
public static void main(String[] args) {
int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};
int number = 7;
System.out.println(binarySearch(arr, number));
}
public static int binarySearch(int[] arr, int number){
//定义两个变量记住要查找到的范围
int min = 0;
int max = arr.length - 1;
//利用循环去查找要找的数据
while (true) {
if (min > max) {
return -1;
}
//找到min和max的中间位置
int mid = (min + max) / 2;
//拿着mid指向的元素跟要找的元素进行比较
//要找的元素在左面,要找的元素在右面,number和指向的元素一样
if (arr[mid] > number) {
max = mid - 1;
} else if (arr[mid] < number) {
max = mid + 1;
} else {
return mid;
}
}
}
}
插值查找
数组数据要均匀否则降低效率
斐波那契查找
分块.分块扩展,哈希查找
分块查找
查找方法
/*
分块查找
核心思想:
块内无序,块间有序
实现步骤:
1.创建数组blockArr存放每一个块对象的信息
2.先查找blockArr确定要查找的数据属于哪一块
3.再单独遍历这一块数据即可
*/
public static void main(String[] args) {
int[] arr = {16, 5, 9, 12, 21, 18,
32, 23, 37, 26, 45, 34,
50, 48, 61, 52, 73, 66};
//创建三个块对象
Block b1 = new Block(21, 0, 5);
Block b2 = new Block(45, 6, 11);
Block b3 = new Block(73, 12, 17);
//定义数组用来管理三个块的对象
Block[] blockArr = {b1, b2, b3};
//定义一个变量用来记录要查找的元素
int number = 37;
//调用方法,传递索引表,数组,要查找的元素
int index = getIndex(blockArr, arr, number);
//打印一下
System.out.println(index);
}
//定义一个方法,用来确定number在哪一块当中
public static int findIndexBlock(Block[] blockArr, int number) { //100
for (int i = 0; i < blockArr.length; i++) {
if (number <= blockArr[i].getMax()) {
return i;
}
}
return -1;
}
//利用分块查找的原理,查询number的索引
//确定number在索引表中的位置
private static int getIndex(Block[] blockArr, int[] arr, int number) {
int indexBlock = findIndexBlock(blockArr, number);
if (indexBlock == -1) {
return -1;
}
int startIndex = blockArr[indexBlock].getStartIndex();
int endIndex = blockArr[indexBlock].getEndIndex();
for (int i = startIndex; i <= endIndex; i++) {
if (arr[i] == number) {
return i;
}
}
return -1;
}
扩展的分块查找(无规律的数据)
public static void main(String[] args) {
int[] arr = {27,22,30,40,36,13,19,16,20,7,10,43,50,48};
//创建三个块对象
Block b1 = new Block(40, 0, 4,22);
Block b2 = new Block(20, 5, 8,16);
Block b3 = new Block(10, 9, 10,7);
Block b4 = new Block(50, 11, 13,43);
//定义数组用来管理三个块的对象
Block[] blockArr = {b1, b2, b3, b4};
//定义一个变量用来记录要查找的元素
int number = 16;
//调用方法,传递索引表,数组,要查找的元素
int index = getIndex(blockArr, arr, number);
//打印一下
System.out.println(index);
}
public static int findIndexBlock(Block[] blockArr, int number) { //100
for (int i = 0; i < blockArr.length; i++) {
if (number <= blockArr[i].getMax() && number >= blockArr[i].getMin()){
return i;
}
}
return -1;
}
扩展的分块查找(查找的过程中还需要添加数据)
3.冒泡排序和选择排序
常见算法(排序算法)
冒泡排序
/*
冒泡排序:
核心思想:
1,相邻的元素两两比较,大的放右边,小的放左边。
2,第一轮比较完毕之后,最大值就已经确定,第二轮可以少循环一次,后面以此类推。
3,如果数组中有n个数据,总共我们只要执行n-1轮的代码就可以。
*/
public static void main(String[] args) {
//1.定义数组
int[] arr = {2, 4, 5, 3, 1};
//2.利用冒泡排序将数组中的数据变成 1 2 3 4 5
//外循环:表示我要执行多少轮。 如果有n个数据,那么执行n - 1 轮
for (int i = 0; i < arr.length - 1; i++) {
//内循环:每一轮中我如何比较数据并找到当前的最大值
//-1:为了防止索引越界
//-i:提高效率,每一轮执行的次数应该比上一轮少一次。
for (int j = 0; j < arr.length - 1 - i; j++) {
//i 依次表示数组中的每一个索引:0 1 2 3 4
if(arr[j] > arr[j + 1]){
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
printArr(arr);
}
private static void printArr(int[] arr) {
//3.遍历数组
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
选择排序
/*
选择排序:
1,从0索引开始,跟后面的元素一一比较。
2,小的放前面,大的放后面。
3,第一次循环结束后,最小的数据已经确定。
4,第二次循环从1索引开始以此类推。
*/
public static void main(String[] args) {
/*
选择排序:
1,从0索引开始,跟后面的元素一一比较。
2,小的放前面,大的放后面。
3,第一次循环结束后,最小的数据已经确定。
4,第二次循环从1索引开始以此类推。
*/
//1.定义数组
int[] arr = {2, 4, 5, 3, 1};
//2.利用选择排序让数组变成 1 2 3 4 5
/* //第一轮:
//从0索引开始,跟后面的元素一一比较。
for (int i = 0 + 1; i < arr.length; i++) {
//拿着0索引跟后面的数据进行比较
if(arr[0] > arr[i]){
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
}
}*/
//最终代码:
//外循环:几轮
//i:表示这一轮中,我拿着哪个索引上的数据跟后面的数据进行比较并交换
for (int i = 0; i < arr.length -1; i++) {
//内循环:每一轮我要干什么事情?
//拿着i跟i后面的数据进行比较交换
for (int j = i + 1; j < arr.length; j++) {
if(arr[i] > arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
printArr(arr)
}
}
4.插入排序和递归算法
插入排序
/*
插入排序:
将0索引的元素到N索引的元素看做是有序的,把N+1索引的元素到最后一个当成是无序的。
遍历无序的数据,将遍历到的元素插入有序序列中适当的位置,如遇到相同数据,插在后面。
N的范围:0~最大索引
*/
public static void main(String[] args) {
int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
//1.找到无序的哪一组数组是从哪个索引开始的。 2
int startIndex = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] > arr[i + 1]) {
startIndex = i + 1;
break;
}
}
//2.遍历从startIndex开始到最后一个元素,依次得到无序的哪一组数据中的每一个元素
for (int i = startIndex; i < arr.length; i++) {
int j = i;
while (j > 0 && arr[j] < arr[j - 1]) {
int temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
printArr(arr);
}
}
递归算法
//需求:利用递归求1-100之间的和
//100 + 99 + 98 + 97 + 96 + 95 .... + 2 + 1
//大问题拆解成小问题
//1~100之间的和 = 100 + (1~99之间的和)
//1~99之间的和 = 99 + (1~98之间的和)
//1~98之间的和 = 98 + (1~97之间的和)
//。。。
//1~2之间的和 = 2 + (1~1之间的和)
//1~1之间的和 = 1(递归的出口)
//核心:
//1.找出口
//2.找规律
public static int getSum(int number){//99
if(number == 1){
return 1;
}
//如果numbert不是1呢?
return number + getSum(number -1);
}
递归求阶乘
//需求:利用递归求5的阶乘
//5! = 5 * 4 * 3 * 2 * 1;
//核心:
//1.找出口
//2.找规律
//心得:
//方法内部再次调用方法的时候,参数必须要更加的靠近出口
//第一次调用:5
//第二次调用:4
//5! = 5 * 4!;
//4! = 4 * 3!;
//3! = 3 * 2!;
//2! = 2 * 1!;
//1! = 1;
public static int getFactorialRecursion(int number){//5 !
if(number == 1){
return 1;
}
return number * getFactorialRecursion(number - 1);
}
5.快速排序
/*
快速排序:
第一轮:以0索引的数字为基准数,确定基准数在数组中正确的位置。
比基准数小的全部在左边,比基准数大的全部在右边。
后面以此类推。
*/
public static void quickSort(int[] arr, int i, int j) {
//定义两个变量记录要查找的范围
int start = i;
int end = j;
if(start > end){
//递归的出口
return;
}
//记录基准数
int baseNumber = arr[i];
//利用循环找到要交换的数字
while(start != end){
//利用end,从后往前开始找,找比基准数小的数字
//int[] arr = {1, 6, 2, 7, 9, 3, 4, 5, 10, 8};
while(true){
if(end <= start || arr[end] < baseNumber){
break;
}
end--;
}
System.out.println(end);
//利用start,从前往后找,找比基准数大的数字
while(true){
if(end <= start || arr[start] > baseNumber){
break;
}
start++;
}
//把end和start指向的元素进行交换
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
//当start和end指向了同一个元素的时候,那么上面的循环就会结束
//表示已经找到了基准数在数组中应存入的位置
//基准数归位
//就是拿着这个范围中的第一个数字,跟start指向的元素进行交换
int temp = arr[i];
arr[i] = arr[start];
arr[start] = temp;
//确定6左边的范围,重复刚刚所做的事情
quickSort(arr,i,start - 1);
//确定6右边的范围,重复刚刚所做的事情
quickSort(arr,start + 1,j);
}
6.Arrays
Arrays.sort重写降序排列代码
7.Lambda表达式
lambda表达式对匿名内部类进行简化
函数式编程
Lambda表达式格式
什么是函数式接口?
public class LambdaDemo2 {
public static void main(String[] args) {
//1.匿名内部类的形式调用method方法
//调用一个方法的时候,如果方法的形参是一个接口,那么我们要传递这个接口的实现类对象
//如果实现类对象只要用到一次,就可以用匿名内部类的形式进行书写
method(new Swim() {
@Override
public void swimming() {
System.out.println("正在游泳~~~");
}
});
//2.利用lambda表达式进行改写
/*method(() ->{
System.out.println("正在游泳~~~");
});*/
}
public static void method(Swim s) {
s.swimming();
}
}
interface Swim {
public abstract void swimming();
}
Lambda表达式的省略写法
/*lambda的省略规则
1.参数类型可以省略不写
2.如果只有一个参数,参数类型可以省略,同时()也可以省略
3.如果lambda表达式的方法体只有一行,大括号,分号,return可以省略不写,需要同时省略
*/
// lambda的省略格式
// Arrays.sort(arr, (o1, o2) -> {
// return o1 - o2;
// });
// Arrays.sort(arr, (o1, o2) -> o1 - o2;);
public static void main(String[] args) {
String[] arr = {"a", "aaaa", "aaa", "aa"};
//如果我们要把数组中的数据按照指定的方式进行排列,就需要用到sort方法,而且要制定排序的规则
/* Arrays.sort(arr, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//字符串的长度进行排序
return o1.length() - o2.length();
}
});
//Lambda完整格式
Arrays.sort(arr, (String o1, String o2) -> {
//字符串的长度进行排序
return o1.length() - o2.length();
}
);*/
//Lambda简写格式
//小括号:数据类型可以省略,如果参数只有一个,小括号还可以省略
//大括号:如果方法体只有一行 return ,分号,大括号,都可以省略
Arrays.sort(arr, (o1, o2) -> o1.length() - o2.length());
System.out.println(Arrays.toString(arr));
}
8.五道经典算法题
public class Test1 {
public static void main(String[] args) {
// String s1 = "a";
// String s2 = "b";
// int i = s1.compareTo(s2);
// System.out.println(i);//-1 代表s1小于s2 ASCII码比较
GirlFriend gf1 = new GirlFriend("xiaoshishi", 18, 1.67);
GirlFriend gf2 = new GirlFriend("xiaodandan", 19, 1.72);
GirlFriend gf3 = new GirlFriend("xiaohuihui", 19, 1.78);
GirlFriend gf4 = new GirlFriend("abc", 19, 1.78);
//定义数组存储女朋友的信息
GirlFriend[] arr = {gf1, gf2, gf3, gf4};
//利用Arrays中的sort方法进行排序
// 匿名内部类 Lambda表达式
Arrays.sort(arr, new Comparator<GirlFriend>() {
@Override
public int compare(GirlFriend o1, GirlFriend o2) {
//按年龄大小进行排序,年龄一样,按身高排序,身高一样按姓名的字母进行排序
double temp = o1.getAge() - o2.getAge();
//三元运算符
temp = temp == 0 ? o1.getHeight() - o2.getHeight() : temp;
temp = temp == 0 ? o1.getName().compareTo(o2.getName()) : temp;
if (temp > 0) {
return 1;
} else if (temp < 0) {
return -1;
} else {
return 0;
}
}
});
//lambda表达式书写
Arrays.sort(arr, ( o1, o2) -> {
//按年龄大小进行排序,年龄一样,按身高排序,身高一样按姓名的字母进行排序
double temp = o1.getAge() - o2.getAge();
//三元运算符
temp = temp == 0 ? o1.getHeight() - o2.getHeight() : temp;
temp = temp == 0 ? o1.getName().compareTo(o2.getName()) : temp;
if (temp > 0) {
return 1;
} else if (temp < 0) {
return -1;
} else {
return 0;
}
});
//展示数组中的内容
System.out.println(Arrays.toString(arr));
}
}
public class Test2 {
public static void main(String[] args) {
/*
* 特点:第三个数据开始,是前两个数据和(斐波那切数列)
* */
/* //求解1:
//1.创建一个长度为12的数组
int[] arr = new int[12];
//2.手动给0索引和1索引的数据进行赋值
arr[0] = 1;
arr[1] = 1;
//3.利用循环给剩余的数据进行赋值
for (int i = 2; i < arr.length; i++) {
arr[i] = arr[i - 1] + arr[i - 2];
}
//4.获取最大索引上的数据即可
System.out.println(arr[11]);*/
//求解2:
//递归的方式去求解
//1.递归的出口
//2.找到递归的规律
//Fn(12)=Fn(11)+Fn(10)
//Fn(11)=Fn(10)+Fn(9)
//Fn(10)=Fn(9)+Fn(8)
//Fn(9)=Fn(8)+Fn(7)
//Fn(8)=Fn(7)+Fn(6)
//...
//Fn(3)=Fn(2)+Fn(1)
//Fn(2)=1
//Fn(1)=1;
System.out.println(getSum(12));
}
public static int getSum(int month) {
if (month == 1 || month == 2) {
return 1;
}
return getSum(month - 1) + getSum(month - 2);
}
}
public class Test3 {
public static void main(String[] args) {
/*
day 10: 1
day 9: (day 10 + 1) * 2 = 4
day 8: (day 9 + 1) * 2 = 10
每一天的桃子数量都是后一天数量加1,乘以2
day 7: 一定会依赖后一天桃子的数量
*/
}
public static int getCount(int day) {
if (day <= 0 || day >= 11) {
System.out.println("日期错误");
return -1;
}
if (day == 10) {
return 1;
}
//书写规律
//每一天的桃子树梁都是后一天数量加1,乘2
return (getCount(day + 1) + 1) * 2;
}
}
public class Test4 {
public static void main(String[] args) {
System.out.println(getCount(20));
}
public static int getCount(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
if (n == 3) {
return 4;
}
return getCount(n - 1) + getCount(n - 2)+ getCount(n - 3);
}
}