在本文中我将介绍Java中的常见算法,查找算法包括基本查找、二分查找、插值查找和分块查找。排序算法包括冒泡排序、选择排序、插入排序和快速排序
查找算法:
1.基本查找:
代码:
public class BasicSearchDemo {
public static void main(String[] args) {
int[] arr = {1,21,31,41,51,61,71,81};
Scanner sc = new Scanner(System.in);
String numStr = sc.nextLine();
int num = Integer.parseInt(numStr);
boolean result = basicSearch(arr, num);
System.out.println(result);
}
//基本查找方法
public static boolean basicSearch(int[] arr, int number) {
for (int i = 0; i < arr.length; i++) {
if(arr[i] == number) {
return true;
}
}
return false;
}
}
这是简单的基本查找,通过遍历数组来查看元素是否存在
运行结果:
基本查找小练习:
代码(含题目要求):
public class BasicSearchTest {
public static void main(String[] args) {
/*
练习1:
需求:定义一个方法利用基本查找,查询某个元素在数组中的索引
要求:不需要考虑数组中元素是否重复
*/
/*
练习2:
需求:定义一个方法利用基本查找,查询某个元素在数组中的索引
要求:需要考虑数组中元素有重复的可能性
例如:{1,1,1,2,3,4,5,6,1}
若查找1,则需要返回所有元素1的索引,即0,1,2,8
*/
//生成一个数组
int[] arr = {1,11,21,31,41,51,51,61,51,61};
//键盘录入一个元素
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要查找的元素:");
String numStr = sc.nextLine();
int num = Integer.parseInt(numStr);
System.out.println(getIndex(arr, num));
System.out.println(getAllIndex(arr, num));
}
//练习1
public static int getIndex(int[] arr, int number) {
for (int i = 0; i < arr.length; i++) {
if(arr[i] == number) {
return i;
}
}
return -1;
}
//练习2
public static ArrayList<Integer> getAllIndex(int[] arr, int number) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
if(arr[i] == number) {
list.add(i);
}
}
return list;
}
}
运行结果:
2.二分查找:
特点:
二分查找的数据必须是按大小顺序排好的 二分查找可以很大的提高查找效率
代码:
public class BinarySearchDemo1 {
public static void main(String[] args) {
//二分查找的数据必须是按大小顺序排好的
//二分查找可以很大的提高查找效率
//定义数组
int[] arr = {1,21,31,41,51,61,71,81};
//键盘录入一个要查找的元素
System.out.println("输入要查找的元素:");
Scanner sc = new Scanner(System.in);
String numStr = sc.nextLine();
int num = Integer.parseInt(numStr);
System.out.println(binarySearch(arr, num));
}
//定义二分查找方法
public static int binarySearch(int[] arr, int num) {
//用min和max表示当前查找范围
int min = 0;
int max = arr.length - 1;
while (true) {
//这种情况说明元素不存在
if(min > max) {
return -1;
}
//定义中间指针
int mid = (min + max) / 2;
//进行判断
if(arr[mid] < num) {
//元素在右边
min = mid + 1;
} else if(arr[mid] > num) {
//元素在左边
max = mid - 1;
} else {
//找到了
return mid;
}
}
}
}
3.插值查找:
改变mid位置时使用数学公式使其更靠近要查找的元素
特点:
适用于数据分布较均匀的情况下
代码:
public class InterpolationSearch {
public static void main(String[] args) {
//适用于数据分布较均匀的情况下
int[] arr = {1,2,3,5,6,8,9,10};
System.out.println("请输入要查找的元素值:");
Scanner sc = new Scanner(System.in);
String numStr = sc.nextLine();
int num = Integer.parseInt(numStr);
int index = interpolationSearch(arr, num);
System.out.println(index);
}
public static int interpolationSearch(int[] arr, int num) {
//定义查找范围
int min = 0;
int max = arr.length - 1;
while(true) {
if(min > max) {
return -1;
}
//mid = min + (key - arr[min]) / (arr[max] - arr[min]) * (max - min)
int mid = min + (num - arr[min]) / (arr[max] - arr[min]) * (max - min);
if(arr[mid] > num) {
max = mid - 1;
} else if(arr[mid] < num) {
min = mid + 1;
} else {
return mid;
}
}
}
}
4.分块查找:
对数据先进行分块,通过先确定要查找的元素属于哪个块,再只需对那个块进行遍历
代码:
public class BlockSearch {
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};
//输入要查找的元素
Scanner sc = new Scanner(System.in);
System.out.println("请输入要查找的元素");
String numStr = sc.nextLine();
int num = Integer.parseInt(numStr);
int index = getIndex(arr, blockArr, num);
System.out.println(index);
}
private static int getIndex(int[] arr, Block[] blockArr, int num) {
int blockIndex = getBlock(blockArr, num);
if(blockIndex == -1) {
return -1;
}
//将范围缩小到这块的开始和结束索引
int startIndex = blockArr[blockIndex].getStartIndex();
int endIndex = blockArr[blockIndex].getEndIndex();
//遍历
for (int i = startIndex; i <= endIndex; i++) {
if(arr[i] == num) {
return i;
}
}
return -1;
}
private static int getBlock(Block[] blockArr, int num) {
for (int i = 0; i < blockArr.length; i++) {
if(num < blockArr[i].getMax()) {
return i;
}
}
return -1;
}
}
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.冒泡排序:
特点:
相邻的元素两两比较,大的放右边,小的放左边(从小到大情况) 第一轮比较完毕之后,最大值就已经确定,第二轮可以少循环一次,后面以此类推 如果数组中有n个数据,那总共执行n-1轮代码就可以
代码:
public class BubbleSort {
public static void main(String[] args) {
//相邻的元素两两比较,大的放右边,小的放左边(从小到大情况)
//第一轮比较完毕之后,最大值就已经确定,第二轮可以少循环一次,后面以此类推
//如果数组中有n个数据,那总共执行n-1轮代码就可以
//创建一个数组
int[] arr = {1,4,5,2,3,9,5,6};
int[] resultArr = bubbleSort(arr);
for (int i = 0; i < resultArr.length; i++) {
System.out.println(resultArr[i]);
}
}
private static int[] bubbleSort(int[] arr) {
//外循环:要进行几轮
for (int i = 0; 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;
}
}
}
return arr;
}
}
2.选择排序:
特点:
从0索引开始,拿着每一个索引上的元素跟后面的元素依次比较 小的放前面,大的放后面(从小到大情况),以此类推 第一轮循环结束后,最小的数据已经确定 第二轮循环从1索引开始,以此类推
代码:
public class SelectionSort {
public static void main(String[] args) {
//从0索引开始,拿着每一个索引上的元素跟后面的元素依次比较
//小的放前面,大的放后面(从小到大情况),以此类推
//第一轮循环结束后,最小的数据已经确定
//第二轮循环从1索引开始,以此类推
//创建数组
int[] arr = {4,3,9,5,6,8,2,1};
int[] resultArr = bubbleSort(arr);
for (int i = 0; i < resultArr.length; i++) {
System.out.println(resultArr[i]);
}
}
public static int[] bubbleSort(int[] arr) {
//外循环:表示几轮
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;
}
}
}
return arr;
}
}
3.插入排序:
特点:
将0索引的元素到N索引的元素看做是有序的,把N+1索引的元素到最后一个元素当成是无序的。 遍历无序的数据,将遍历到的元素插入有序序列中适当的位置,如遇到相同数据,插在后面。
代码:
public class InsertionSort {
public static void main(String[] args) {
//将0索引的元素到N索引的元素看做是有序的,把N+1索引的元素到最后一个元素当成是无序的。
//遍历无序的数据,将遍历到的元素插入有序序列中适当的位置,如遇到相同数据,插在后面。
//创建数组
int[] arr = {1,6,5,3,9,7,16,1,22,3};
int[] resultArr = insertionSort(arr);
for (int i = 0; i < resultArr.length; i++) {
System.out.println(resultArr[i]);
}
}
public static int[] insertionSort(int[] arr) {
//判断有序元素个数
int index = 0;
for (int i = 1; i < arr.length; i++) {
if(arr[index] < arr[index + 1]) {
index++;
} else {
break;
}
}
//index为最后一个有序元素的索引
//有序元素后面的每个元素要插入有序元素中 插入后有序元素加1 索引也++
//我的其他思路 复杂了。。
/*
for (; index < arr.length - 1; index++) {
int i = index + 1;
for(int j = index; j >= 0; j--) {
if(arr[i] >= arr[j]) {
break;
} else {
//有序元素后面的无序元素只要比前面的小就交换位置
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i--;
continue;
}
}
}
*/
//从有序数组后的第一个元素到最后一个元素
for (int i = index + 1; 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;
j--;
}
}
return arr;
}
}
4.快速排序
这里展示快速排序之前要先学会递归思想,我先来放两个递归思想的小练习
递归练习一 题目及代码:
public class RecursionAlgorithmTest1 {
public static void main(String[] args) {
//核心:找出口 找规律
//方法中再次调用方法时,参数应更接近出口
//求1~100所有整数的和
int sum = getSum(100);
System.out.println(sum);
}
//1~100所有整数的和 = 100 + 1~99的和
//1~99的和 = 99 + 1~98的和
//…………
public static int getSum(int num) {
//出口
if(num == 1) {
return 1;
}
return num + getSum(num - 1);
}
}
递归练习二 题目及代码:
public class RecursionAlgorithmTest2 {
public static void main(String[] args) {
//需求:用递归求5的阶乘,并把结果在控制台输出
int factorail = getFactorail(5);
System.out.println(factorail);
}
//5的阶乘 = 5 * 4的阶乘
//4的阶乘 = 4 * 3的阶乘
//…………
public static int getFactorail(int num) {
//出口
if(num == 1) {
return 1;
}
return num * getFactorail(num - 1);
}
}
接下来开始讲解快速排序:
过程:
//将排序范围中的第一个数字作为基准数,在定义两个变量start,end //start从前往后找比基准数大的,end从后往前找比基准数小的。 /*找到之后交换start和end指向的元素,并循环这一过程,直到start和end处于同一个位置, 该位置是基准数在数组中应存入的位置,再让基准数归位*/ //归为后的效果:基准数左边的都比基准数小,右边的都比基准数大
代码演示:
public class QuickSort {
public static void main(String[] args) {
//创建数组
int[] arr = {6,2,3,1,7,5,8};
int start = 0;
int end = arr.length - 1;
quickSort(arr, start, end);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
private static void quickSort(int[] arr, int i, int j) {
//出口
if(i >= j) {
return;
}
int start = i;
int end = j;
//基准数
int baseNumber = arr[i];
while(start != end) {
//end从右往左开始找比基准数小的数
while(true) {
if(end <= start || arr[end] < baseNumber) {
break;
}
end--;
}
//start从左往右开始找比基准数大的数
while(true) {
if(end <= start || arr[start] > baseNumber) {
break;
}
start++;
}
//交换位置
int temp = arr[end];
arr[end] = arr[start];
arr[start] = temp;
}
//将基准数与当前start和end索引所在位置交换
int temp = arr[i];
arr[i] = arr[start];
arr[start] = temp;
//基准数左边继续重复刚才所做的事
quickSort(arr, i, start - 1);
//基准数右边继续重复刚才所做的事
quickSort(arr, start + 1, j);
}
}