java后端开发day29--常见算法(一)----查找与排序
(以下内容全部来自上述课程)
1.查找算法
1.基本查找
数据无 顺序要求。
package search;
public class BasicSearchDemo1 {
public static void main(String[] args) {
//基本查找/顺序查找
//核心:
//从0索引开始挨个往后查找
//需求:定义一个方法利用基本查找,查询某个元素是否存在
//数据如下:{131, 127, 147, 81, 103, 23, 7, 79}
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){
//利用基本查找,查询某个元素是否存在
//数据如下:{131, 127, 147, 81, 103, 23, 7, 79}
for(int i = 0; i < arr.length; i++){
if(arr[i] == number){
return true;
}
}
return false;
}
}
2.二分查找/折半查找
- 前提条件:数组中的数据必须是有序的。
如果数据是乱的,先排序再用二分查找得到的索引没有实际意义,只能确定当前数字在数组中是否存在,因为排序之后数字的位置就可能发生变化了。 - 核心逻辑:每次排除一半的查找范围。
- 提高查找效率
package search;
public class BinarySearchDemo1 {
public static void main(String[] args) {
// 二分查找/折半查找
// 核心:
// 每次排除一半的查找范围
// 前提:数组元素有序
// 需求:定义一个方法利用二分查找,查询某个元素是否存在
// 数据如下:{1,2,3,4,5,6,7,8,9}
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int index = binarySearch(arr, 8);
System.out.println(index);
}
public static int binarySearch(int[] arr, int value) {
// 定义三个变量记录要查找的范围
int min = 0;
int max = arr.length - 1;
// 循环查找,min大于max时结束查找
// 检查中间值是否是要找的
// 中间值比要找的值大,说明要找的值在左边
// 中间值比要找的值小,说明要找的值在右边
// 重新计算min和max
while (true) {
if (min > max) {
return -1;
}
int mid = (min + max) / 2;
if (arr[mid] > value) {
max = mid - 1;
} else if (arr[mid] < value) {
min = mid + 1;
} else {
return mid;
}
}
}
}
3.插值查找(二分查找优化1----了解)
只能数据分布均匀才能用。
4.斐波那契(二分查找优化2----了解)
5.分块查找
- 分块原则1:前一块中的最大数据,小于后一块中所有的数据。(块内无序,块间有序)
- 分块原则2:块数数量一般等于数字的个数开根号。比如:16个数字一般分为4块左右。
- 核心思路:先确定要查找的元素在哪一块,然后在块内挨个查找。
package search;
public class BlockSearchDemo {
public static void main(String[] args) {
//分块查找
//核心:
//1、必须要知道索引表的内容
//2、先去索引表中找,确定要找的数据在哪一个块中
//3、再去这个块中找对应的元素
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 = 66;
//调用方法,传递索引表、数组、要查找的值
int index = blockSearch(blockArr, arr, number);
System.out.println(index);
}
//利用分块原理,查询number在哪个块中
public static int blockSearch(Block[] blockArr, int[] arr, int number){
//1、确认number是在哪一块中
int indexBlock = getIndex(blockArr, number);
if(indexBlock == -1){
//索引表中没有要查找的值
return -1;
}
//2、获取这一块的起始索引和结束索引
//Block b1 = new Block(21, 0, 5);
//Block b2 = new Block(45, 6, 11);
//Block b3 = new Block(73, 12, 17);
int startIndex = blockArr[indexBlock].getStartIndex();
int endIndex = blockArr[indexBlock].getEndIndex();
//3、遍历这一块,获取这一块中的每一个元素
for(int i = startIndex; i <= endIndex; i++){
if(arr[i] == number){
return i;
}
}
return -1;
}
//定义一个方法。用来确定number在哪一个块中
public static int getIndex(Block[] blockArr,int number){
//从0索引开始遍历blockArr,如果number小于max,那么就表示number在这个块中
for(int i = 0; i < blockArr.length; i++){
//判断number是否小于索引表中的最大值
//如果在,记录这个值的索引,并结束循环
if(number <= blockArr[i].getMax()){
return i;
}
}
return -1;
}
}
//JavaBean
class Block {
private int max;
private int startIndex;
private int endIndex;
public Block() {
}
public Block(int max, int startIndex, int endIndex) {
this.max = max;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
/**
* 获取
*
* @return max
*/
public int getMax() {
return max;
}
/**
* 设置
*
* @param max
*/
public void setMax(int max) {
this.max = max;
}
/**
* 获取
*
* @return startIndex
*/
public int getStartIndex() {
return startIndex;
}
/**
* 设置
*
* @param startIndex
*/
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
/**
* 获取
*
* @return endIndex
*/
public int getEndIndex() {
return endIndex;
}
/**
* 设置
*
* @param endIndex
*/
public void setEndIndex(int endIndex) {
this.endIndex = endIndex;
}
public String toString() {
return "Block{max = " + max + ", startIndex = " + startIndex + ", endIndex = " + endIndex + "}";
}
}
1.拓展1
6.哈希查找 ---->>拓展2
2.排序算法
1.冒泡排序(相邻-----先最大)
相邻的数据两两比较,小的放前面,大的放后面。
package mysort;
public class BubbleDemo1 {
public static void main(String[] args) {
// 冒泡排序
// 核心:
// 每次比较相邻的两个元素,如果前一个比后一个大,就交换
// 每次比较完毕后,下一次的比较就会少一个元素
// 需求:定义一个方法利用冒泡排序,对数组进行排序
// 数组如下:{24, 69, 80, 57, 13}
int[] arr = {24, 69, 80, 57, 13};
bubbleSort(arr);
printArr(arr);
}
public static void bubbleSort(int[] arr) {
// 利用冒泡排序,对数组进行排序
// 数组如下:{24, 69, 80, 57, 13}
// 外层循环控制的是次数:arr.length - 1
for (int i = 0; i < arr.length - 1; i++) {
// 内存循环控制的是索引:arr.length - 1 - i
for (int j = 0; j < arr.length - 1 - i; j++) {
// 比较相邻的两个元素,如果前一个比后一个大,就交换
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
public static void printArr(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
2.选择排序(0与后-----先最小)
从0索引开始,拿着每一个0索引上的元素跟后面的元素依次比较,小的放前面,大的放后面,以此类推。(数字pk)
package mysort;
public class SelectionDemo {
public static void main(String[] args) {
// 选择排序
// 核心:
// 每次循环找到最小的元素,放到前面
// 需求:定义一个方法利用选择排序,将一个int数组中的数据从小到大排序
// 数据如下:{24, 69, 80, 57, 13}
int[] arr = {24, 69, 80, 57, 13};
selectionSort(arr);
printArr(arr);
}
public static void selectionSort(int[] arr) {
// 利用选择排序,将一个int数组中的数据从小到大排序
// 数据如下:{24, 69, 80, 57, 13}
// 外层循环控制的是次数:arr.length - 1
for (int i = 0; i < arr.length - 1; i++) {
// 内存循环控制的是索引:i + 1
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;
}
}
}
}
public static void printArr(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
3.插入排序(分两派------无插有)
将0索引的元素到N索引的元素看作是有序的,把N+1索引的元素到最后一个当成是无序的。
遍历无序的数据,将遍历到的元素插入有序序列中适当的位置,如遇到相同数据,插在后面。
N的范围:0~最大索引
package mysort;
public class InsertDemo {
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++) {
//问题:如何把arr[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;
j--;
}
}
printArr(arr);
}
public static void printArr(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
4.递归算法(套娃)
指的是方法中调用方法本身的现象。
注意:递归一定要有出口(结束条件),否则就会出现内存溢出。
作用:大事化小,小事化了。
核心:
- 找出口:什么时候不再调用方法。
- 找规则:如何把大问题变成规模较小的问题。
一阶一阶的弹窗,往里加载方法,最后到结束条件把返回值返回给方法的调用者,然后方法一个一个出栈。
5.快速排序(0当原点,左右互换)
先移动end,再移动start。
package mysort;
public class QuickSortDemo {
public static void main(String[] args) {
int[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};
quickSort(arr, 0, arr.length - 1);
printArr(arr);
}
public static void quickSort(int[] arr, int left, int right) {
if (left > right) {
return;
}
int i = left;
int j = right;
int temp = arr[left];
while (i != j) {
while (arr[j] >= temp && i < j) {
j--;
}
while (arr[i] <= temp && i < j) {
i++;
}
if (i < j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
}
arr[left] = arr[i];
arr[i] = temp;
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
public static void printArr(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}