Java的查找算法和排序算法

诗林  金牌会员 | 2024-10-28 12:57:38 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 355|帖子 355|积分 1065

一、查找算法

1. 基本查找



  • 基本查找也叫顺序查找。
  • 核心:从0索引开始挨个往后查找。
a. 示例



  • 需求:界说一个方法,查询元素在数组中的索引值。
  1. import java.util.ArrayList;
  2. public class Demo2 {
  3.     public static void main(String[] args) {
  4.         int[] arr = {131, 127, 147, 81, 103, 23, 7, 79, 81};
  5.         System.out.println(searchNumber(arr, 81));
  6.     }
  7.     public static ArrayList<Integer> searchNumber(int[] arr, int number){
  8.         ArrayList<Integer> list = new ArrayList<>();
  9.         for (int i = 0; i < arr.length; i++) {
  10.             if (arr[i] == number) {
  11.                 list.add(i);
  12.             }
  13.         }
  14.         return list;
  15.     }
  16. }
复制代码

2. 二分查找



  • 二分查找又称折半查找。
  • 前提条件:数组中的数据必须是有序的。

    • 如果数据是乱的,必须先排序。
    • 只能确定当前key在数组中是否存在,不能确定其索引值。

  • 核心:每次清除一半的查找范围。
  • 过程:

    • 界说min和max表示当前要查找的范围
    • 界说中心索引mid(min和max中心的索引)
    • 如果key在mid的左边,缩小范围时,min稳定,max等于mid减1
    • 如果key在mid的右边,缩小范围时,max稳定,min等于mid加1

a. 示例

  1. public class Demo3 {
  2.     public static void main(String[] args) {
  3.         int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};
  4.         System.out.println(BinarySearch(arr, 127));
  5.     }
  6.     public static int BinarySearch(int[] arr, int number){
  7.         // 定义范围
  8.         int min = 0;
  9.         int max = arr.length;
  10.         while (true) {
  11.             if (min > max) {
  12.                 return -1;
  13.             }
  14.             // 定义中间索引
  15.             int mid = (min + max) / 2;
  16.             // 核心代码
  17.             if (arr[mid] > number) {
  18.                 max = mid - 1;
  19.             } else if (arr[mid] < number) {
  20.                 min = mid + 1;
  21.             } else if (arr[mid] == number) {
  22.                 return mid;
  23.             }
  24.         }
  25.     }
  26. }
复制代码

3. 插值查找



  • 插值查找在二分查找的底子上改进。
  • 前提条件:数据尽可能的分布匀称。
  • 核心:                                             m                               i                               d                               =                               m                               i                               n                               +                                                                      k                                        e                                        y                                        −                                        a                                        r                                        r                                        [                                        m                                        i                                        n                                        ]                                                                a                                        r                                        r                                        [                                        m                                        a                                        x                                        ]                                        −                                        a                                        r                                        r                                        [                                        m                                        i                                        n                                        ]                                                                   ×                               (                               m                               a                               x                               −                               m                               i                               n                               )                                      mid = min + \dfrac{key-arr[min]}{arr[max]-arr[min]}\times(max-min)                        mid=min+arr[max]−arr[min]key−arr[min]​×(max−min)

    • mid值是key在数组中的百分比位置。
    • mid = 偏移量 + 左隔断 ÷ 总隔断 × (最大值-最小值)

4. 斐波那契查找



  • 斐波那契查找在二分查找的底子上改进。
  • 根据黄金分割点来盘算mid索引。
  • mid = min + 黄金分割点左半边长度 - 1。
5. 分块查找



  • 原则

    • 前一块中的最大数据,小于后一块中所有的数据(块内无序,块间有序)
    • 块数数量一般等于元素个数开根号。比如:16个元素一般分为4块左右。

  • 核心:先确定要查找的元素在哪一块,然后再块内挨个查找。

a. 示例



  • 界说一个数组 {16, 5, 9, 12, 21, 18, 32, 23, 37, 26, 45, 34, 50, 48, 61, 52, 73, 66},查询数字是否在数组中。
  1. package day18.search;
  2. public class Demo4 {
  3.     public static void main(String[] args) {
  4.         int[] arr = {16, 5, 9, 12, 21, 18, 32, 23, 37, 26, 45, 34, 50, 48, 61, 52, 73, 66};
  5.         // 块对象
  6.         Block b1 = new Block(21, 0, 5);
  7.         Block b2 = new Block(45, 6, 11);
  8.         Block b3 = new Block(73, 12, 17);
  9.         Block[] blockArr = {b1, b2, b3};
  10.         int number = 66;
  11.         // 现确定在哪一块
  12.         int index = getIndex(blockArr, arr, number);
  13.         // 在块中查找
  14.         System.out.println(index);
  15.     }
  16.     private static int getIndex(Block[] blockArr, int[] arr, int number) {
  17.         int indexBlock = findIndexBlock(blockArr, number);
  18.         if (indexBlock == -1) {
  19.             return -1;
  20.         }
  21.         int startIndex = blockArr[indexBlock].getStartIndex();
  22.         int endIndex = blockArr[indexBlock].getEndIndex();
  23.         for (int i = startIndex; i <= endIndex; i++) {
  24.             if (arr[i] == number) {
  25.                 return i;
  26.             }
  27.         }
  28.         return -1;
  29.     }
  30.     public static int findIndexBlock(Block[] blockArr, int number){
  31.         for (int i = 0; i < blockArr.length; i++) {
  32.             if (number <= blockArr[i].getMax()) {
  33.                 return i;
  34.             }
  35.         }
  36.         return -1;
  37.     }
  38. }
  39. class Block{
  40.     private int max;  // 块中最大值
  41.     private int startIndex;  // 起始索引
  42.     private int endIndex;  // 结束索引
  43.     public Block() {
  44.     }
  45.     public Block(int max, int startIndex, int endIndex) {
  46.         this.max = max;
  47.         this.startIndex = startIndex;
  48.         this.endIndex = endIndex;
  49.     }
  50.     public int getMax() {
  51.         return max;
  52.     }
  53.     public void setMax(int max) {
  54.         this.max = max;
  55.     }
  56.     public int getStartIndex() {
  57.         return startIndex;
  58.     }
  59.     public void setStartIndex(int startIndex) {
  60.         this.startIndex = startIndex;
  61.     }
  62.     public int getEndIndex() {
  63.         return endIndex;
  64.     }
  65.     public void setEndIndex(int endIndex) {
  66.         this.endIndex = endIndex;
  67.     }
  68. }
复制代码

二、排序算法

1. 冒泡排序



  • 步骤:

    • 相邻的元素两两比较,大的放反面,小的放前面;
    • 第一轮比较完毕之后,最大值就已经确定,第二轮可以少循环一次,反面以此类推;
    • 如果数组中有n个数据,总共要实行n-1轮。

a. 示例



  • 界说一个数组{2, 1, 4, 5, 3},并排序。
  1. import java.util.Arrays;
  2. public class Demo1 {
  3.     public static void main(String[] args) {
  4.         int[] arr = {2, 1, 4, 5, 3};
  5.         // 循环多少轮
  6.         for (int i = 0; i < arr.length-1; i++) {
  7.             // 每一轮排序
  8.             for (int j = 0; j < arr.length - 1 - i; j++) {
  9.                 if (arr[j] > arr[j + 1]) {
  10.                     int temp = arr[j];
  11.                     arr[j] = arr[j + 1];
  12.                     arr[j + 1] = temp;
  13.                 }
  14.             }
  15.         }
  16.         System.out.println(Arrays.toString(arr));
  17.     }
  18. }
复制代码

2. 选择排序



  • 步骤:

    • 从0索引开始,与每一个索引上的元素依次比较。
    • 小的放前面,大的放反面。

a. 示例



  • 界说一个数组{2, 1, 6, 8, 3},并排序。
  1. import java.util.Arrays;
  2. public class Demo2 {
  3.     public static void main(String[] args) {
  4.         int[] arr = {2, 1, 6, 8, 3};
  5.         // 进行比较的索引值
  6.         for (int i = 0; i < arr.length; i++) {
  7.             // 拿每个索引值对应的元素与后面的每个元素进行比较
  8.             // 每完成一轮,索引值加1
  9.             for (int j = i + 1; j < arr.length; j++) {
  10.                 if (arr[i] > arr[j]) {
  11.                     int temp = arr[i];
  12.                     arr[i] = arr[j];
  13.                     arr[j] = temp;
  14.                 }
  15.             }
  16.         }
  17.         System.out.println(Arrays.toString(arr));
  18.     }
  19. }
复制代码

3、插入排序



  • 步骤:

    • 将索引在[0, N]的元素看作有序的,把[N+1, arr.length-1]的元素当成无序的。
    • 遍历无序的数据,将遍历到的元素插入到有序序列中适当的位置,如遇到相同数据,插在反面。

  • N的范围:0~arr.length-1
a. 示例



  • 界说数组:{3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48}
  1. import java.util.Arrays;
  2. public class Demo3 {
  3.     public static void main(String[] args) {
  4.         int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
  5.         // 找到无序的那一组数据从哪个索引开始
  6.         int startIndex = -1;
  7.         for (int i = 0; i < arr.length; i++) {
  8.             if (arr[i] > arr[i + 1]) {
  9.                 startIndex = i + 1;
  10.                 break;
  11.             }
  12.         }
  13.         // 遍历从startIndex开始到最后一个元素
  14.         for (int i = startIndex; i < arr.length; i++) {
  15.             // 记录索引,以防被修改
  16.             int j = i;
  17.             // 遍历交换位置
  18.             while (j > 0 && arr[j] < arr[j - 1]) {
  19.                 int temp = arr[j];
  20.                 arr[j] = arr[j - 1];
  21.                 arr[j - 1] = temp;
  22.                 j--;
  23.             }
  24.         }
  25.         System.out.println(Arrays.toString(arr));
  26.     }
  27. }
复制代码

4. 快速排序(效率最高)



  • 步骤:

    • 将排序范围内的第一个数字作为基准数,在界说两个索引变量start、end
    • 索引start从前往后找比基准数大的,索引end从后往前找比基准数小的。
    • start、end都找到一个数后,替换两个数。
    • 循环上面三步,直到start和end指向同一个索引。让基准数与这个索引的元素替换(基准数归位)。

      • 归位后的效果:基准数左边的,比基准数小;基准数右边的,比基准数大。

    • 对基准数两边的数据重复上面四步,直到要求范围的开始索引大于竣事索引。

a. 示例



  • 界说一个长度为100万的数组,为数组随机添补数字,给数组举行排序。
  1. import java.util.Random;
  2. public class Demo6 {
  3.     public static void main(String[] args) {
  4.         Random random = new Random();
  5.         int[] arr = new int[1000000];
  6.         for (int i = 0; i < arr.length; i++) {
  7.             arr[i] = random.nextInt();
  8.         }
  9.         
  10.         long start = System.currentTimeMillis();
  11.         quickSort(arr, 0, arr.length - 1);
  12.         long end = System.currentTimeMillis();
  13.         System.out.println("共用时: " + (end-start));
  14.     }
  15.     public static void quickSort(int[] arr, int startIndex, int endIndex) {
  16.         if (startIndex > endIndex) return;
  17.         // 记录索引值,防止被修改
  18.         int start = startIndex;
  19.         int end = endIndex;
  20.         // 记录基准数
  21.         int baseNumber = arr[startIndex];
  22.         // 利用循环找到要交换的数
  23.         while (start != end) {
  24.             // 从end往前找
  25.             while (end > start && arr[end] >= baseNumber) end--;
  26.             // 从start往后找
  27.             while (end > start && arr[start] <= baseNumber) start++;
  28.             // 交换start和end
  29.             int temp = arr[end];
  30.             arr[end] = arr[start];
  31.             arr[start] = temp;
  32.         }
  33.         // 基准数归位
  34.         int temp = arr[startIndex];
  35.         arr[startIndex] = arr[end];
  36.         arr[end] = temp;
  37.         // 确定6左边的范围
  38.         quickSort(arr, startIndex, start - 1);
  39.         // 确定6右边的范围
  40.         quickSort(arr, end + 1, endIndex);
  41.     }
  42. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

诗林

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表