【算法与数据结构】Java实现查找与排序

文章目录

  • 第一部分:查找算法
    • 二分查找
    • 插值查找
    • 分块查找
    • 哈希查找
    • 树表查找
  • 第二部分:排序算法
    • 冒泡排序
    • 选择排序
    • 插入排序
    • 快速排序
  • 总结


第一部分:查找算法

二分查找

也叫做折半查找,属于有序查找算法。

前提条件:数组数据必须有序,从小到大,或者从大到小都是可以的。

如果是无序的,也可以先进行排序。
但是排序之后,会改变原有数据的顺序,查找出来元素位置跟原来的元素可能是不一样的,所以排序之后再查找只能判断当前数据是否在容器当中,返回的索引无实际的意义。

二分
基本思想:用给定值先与中间结点比较。

比较完之后有三种情况:

  • 相等 :说明找到了
  • 要查找的数据比中间节点 : 说明要查找的数字在中间节点左边
  • 要查找的数据比中间节点: 说明要查找的数字在中间节点右边
public static void main(String[] args) {//二分查找/折半查找//核心://每次排除一半的查找范围//需求:定义一个方法利用二分查找,查询某个元素在数组中的索引//数据如下:{7, 23, 79, 81, 103, 127, 131, 147}int[] arr = {7, 23, 79, 81, 103, 127, 131, 147};System.out.println(binarySearch(arr, 150));}public static int binarySearch(int[] arr, int number){//1.定义两个变量记录要查找的范围int min = 0;int max = arr.length - 1;//2.利用循环不断的去找要查找的数据while(true){if(min > max){return -1;}//3.找到min和max的中间位置int mid = (min + max) / 2;//4.拿着mid指向的元素跟要查找的元素进行比较if(arr[mid] > number){//4.1 number在mid的左边//min不变,max = mid - 1;max = mid - 1;}else if(arr[mid] < number){//4.2 number在mid的右边//max不变,min = mid + 1;min = mid + 1;}else{//4.3 number跟mid指向的元素一样//找到了return mid;}}}

插值查找

插值:是在二分查找的基础上,让中间的mid点,尽可能靠近想要查找的元素。
1
修改mid公式即可!

private static int binarySearch2(int[] arr, int num) {int min = 0;int max = arr.length - 1;while (true) {if (min > max) {return -1;}int mid = min + (num - arr[min]) / (arr[max] - arr[min]) * (max - min);//这里改公式if (num > arr[mid]) {min = mid + 1;} else if (num < arr[mid]) {max = mid - 1;} else {return mid;}}
}

细节:
对于表长较大,而关键字分布又比较均匀的查找表来说,插值查找算法的平均性能比折半查找要好的多。
反之,数组中如果分布非常不均匀,那可以选折半二分

分块查找

当数据表中的数据元素很多时,可以采用分块查找。

汲取了顺序查找和折半查找各自的优点,既有动态结构,又适于快速查找

分块查找适用于数据较多,但是数据不会发生变化的情况,如果需要一边添加一边查找,建议使用哈希查找

分块查找的过程:

  1. 需要把数据分成N多小块,块与块之间不能有数据重复的交集。
  2. 给每一块创建对象单独存储到数组当中
  3. 查找数据的时候,先在数组查,当前数据属于哪一块
  4. 再到这一块中顺序查找
public class BlockSearchDemo {public static void main(String[] args) {/*分块查找核心思想:块内无序,块间有序实现步骤:1.创建数组blockArr存放每一个块对象的信息2.先查找blockArr确定要查找的数据属于哪一块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 = 37;//调用方法,传递索引表,数组,要查找的元素int index = getIndex(blockArr,arr,number);//打印一下System.out.println(index);}//利用分块查找的原理,查询number的索引private static int getIndex(Block[] blockArr, int[] arr, int number) {//1.确定number是在那一块当中int indexBlock = findIndexBlock(blockArr, number);if(indexBlock == -1){//表示number不在数组当中return -1;}//2.获取这一块的起始索引和结束索引   --- 30// Block b1 = new Block(21,0,5);   ----  0// Block b2 = new Block(45,6,11);  ----  1// Block b3 = new Block(73,12,17); ----  2int 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 findIndexBlock(Block[] blockArr,int number){ //100//从0索引开始遍历blockArr,如果number小于max,那么就表示number是在这一块当中的for (int i = 0; i < blockArr.length; i++) {if(number <= blockArr[i].getMax()){return i;}}return -1;}
}class Block{private int max;//最大值private int startIndex;//起始索引private int endIndex;//结束索引//省略 构造 属性 等 JavaBean
}

哈希查找

树表查找

第二部分:排序算法

冒泡排序

Bubble Sort:

数值之间 两两比较 找到最大的数 放到最后
第二轮开始以此类推 :从0-倒数第二 再开始比较 (即不再管最后一个数[依次找得到最大数])

    private static void bubbleSort() {Random random = new Random();int[] arr = new int[10000];for (int i = 0; i < arr.length; i++) {arr[i] = random.nextInt(1000);}long start = System.currentTimeMillis();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;}}}long end = System.currentTimeMillis();System.out.println(end - start);for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}}

重复的遍历过要排序的数列,一次比较相邻的两个元素,如果他们的顺序错误就把他们交换过来。

总结步骤:

  1. 相邻的元素两两比较,大的放右边,小的放左边
  2. 第一轮比较完毕之后,最大值就已经确定,第二轮可以少循环一次,后面以此类推
  3. 如果数组中有n个数据,总共我们只要执行n-1轮的代码就可以
public class BubbleDemo {public static void main(String[] args) {/*冒泡排序:核心思想:1,相邻的元素两两比较,大的放右边,小的放左边。2,第一轮比较完毕之后,最大值就已经确定,第二轮可以少循环一次,后面以此类推。3,如果数组中有n个数据,总共我们只要执行n-1轮的代码就可以。*///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 4if(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();}
}

选择排序

找到最小的数 排在最前面
第一轮: 0索引位置的数 与后面的数依次比较 找到最小的互换位置
第二轮: 1索引位置的数 与… 以此循环
注意内循环 是从1 开始 所以 arr.length不减1

//for (int i = 0; i < arr.length - 1; i++) {
//    if (arr[0] > arr[i + 1]) {
//        int temp = arr[0];
//        arr[0] = arr[i + 1];
//        arr[i + 1] = temp;
//    }
//}
//
//for (int i = 1; i < arr.length - 1; i++) {
//    if (arr[1] > arr[i + 1]) {
//        int temp = arr[1];
//        arr[1] = arr[i + 1];
//        arr[i + 1] = temp;
//    }
//}// 关于为什么 (j = 1 +i) :
//① i = 0 -> j=  1 ~ 5
//② i = 1 -> j = 2 ~ 5
//...
for (int i = 0; i < arr.length - 1; i++) {for (int j = 1 + i; j < arr.length; j++) {if (arr[i] > arr[j]) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}
}
    private static void selectionSort() {int[] arr = {2, 4, 5, 3, 1};for (int i = 0; i < arr.length - 1; i++) {for (int j = 1 + i; j < arr.length; j++) {if (arr[i] > arr[j]) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}}for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}}

总结步骤:

  1. 从0索引开始,跟后面的元素一一比较
  2. 小的放前面,大的放后面
  3. 第一次循环结束后,最小的数据已经确定
  4. 第二次循环从1索引开始以此类推
  5. 第三轮循环从2索引开始以此类推
  6. 第四轮循环从3索引开始以此类推。
public class SelectionDemo {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);}private static void printArr(int[] arr) {//3.遍历数组for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}System.out.println();}
}

插入排序

  1. 首先分为 有序的部分 无序的部分 数据

  2. 无序的部分第一个数 依次 与有序的数据 倒序进行对比 , 然后将无序的部分插入到有序的适当位置

  3. 依次循环 每个无序的第一个数 与有序的倒序 对比 加入到有序的部分 中

  4. 其实就是 跟它的前一个数对比 交换位置

int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};//1.找到无序的部分
int startIndex = -1;
for (int i = 0; i < arr.length; i++) {if (arr[i] > arr[i + 1]) {startIndex = i + 1;break;}
}//2.遍历无序 (可以用while 或者 for) 用while 比较清晰
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;//    j--;//}for (int j = i; j > 0 && arr[j] < arr[j - 1]; j--) {int temp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = temp;}
}

插入排序在插入的时候,有优化算法,在遍历有序序列找正确位置时,可以采取二分查找

   private static void insertionSorting() {int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};//1.找到无序的部分的索引头int index = findOrderPart(arr);for (int i = index; i < arr.length; i++) {for (int j = i; j > 0 && arr[j] < arr[j - 1]; j--) {int temp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = temp;}}for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}}private static int findOrderPart(int[] arr) {for (int i = 0; i < arr.length; i++) {if (arr[i] > arr[i + 1]) {return i + 1;}}return -1;}
public class InsertDemo {public static void main(String[] args) {/*插入排序:将0索引的元素到N索引的元素看做是有序的,把N+1索引的元素到最后一个当成是无序的。遍历无序的数据,将遍历到的元素插入有序序列中适当的位置,如遇到相同数据,插在后面。N的范围:0~最大索引*/int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};//1.找到无序的哪一组数组是从哪个索引开始的。  2int 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;j--;}}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. 定义两个索引:从前往后 寻找 比基准数大的 // 从后往前 寻找 比基准数小的 --> 找到两个索引交换位置
  2. 直到 两个索引交汇在同一个数值索引位置上 为止
  3. 之后 这个交汇位置的值 与 基准数 进行交换
  4. 以上为一轮交换逻辑。
  5. 循环使用递归方法进行排序, 以基准数为分界线,分为两部分,两次递归 重复排序
    213
    private static void quickSort(int[] arr, int i, int j) {int start = i;int end = j;if (start > end) {return;}int baseNum = arr[i];while (start != end) {while (true) {if (start >= end || arr[end] < baseNum) {break;}end--;}while (true) {if (start >= end || arr[start] > baseNum) {break;}start++;}int temp = arr[start];arr[start] = arr[end];arr[end] = temp;}int temp = arr[i];arr[i] = arr[start];arr[start] = temp;quickSort(arr, i, start - 1);quickSort(arr, start + 1, j);}

总结步骤:

  1. 从数列中挑出一个元素,一般都是左边第一个数字,称为 “基准数”;
  2. 创建两个指针,一个从前往后走,一个从后往前走。
  3. 先执行后面的指针,找出第一个比基准数小的数字
  4. 再执行前面的指针,找出第一个比基准数大的数字
  5. 交换两个指针指向的数字
  6. 直到两个指针相遇
  7. 将基准数跟指针指向位置的数字交换位置,称之为:基准数归位。
  8. 第一轮结束之后,基准数左边的数字都是比基准数小的,基准数右边的数字都是比基准数大的。
  9. 把基准数左边看做一个序列,把基准数右边看做一个序列,按照刚刚的规则递归排序
public class QuickSortDemo {public static void main(String[] args) {System.out.println(Integer.MAX_VALUE);System.out.println(Integer.MIN_VALUE);/*快速排序:第一轮:以0索引的数字为基准数,确定基准数在数组中正确的位置。比基准数小的全部在左边,比基准数大的全部在右边。后面以此类推。*/int[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};//int[] arr = new int[1000000];/* Random r = new Random();for (int i = 0; i < arr.length; i++) {arr[i] = r.nextInt();}*/long start = System.currentTimeMillis();quickSort(arr, 0, arr.length - 1);long end = System.currentTimeMillis();System.out.println(end - start);//149System.out.println(Arrays.toString(arr));//课堂练习://我们可以利用相同的办法去测试一下,选择排序,冒泡排序以及插入排序运行的效率//得到一个结论:快速排序真的非常快。/* for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + " ");}*/}/**   参数一:我们要排序的数组*   参数二:要排序数组的起始索引*   参数三:要排序数组的结束索引* */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);}
}

总结

2.1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/415460.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nginx的应用场景之一http服务器

Nginx本身也是一个静态资源的服务器&#xff0c;当只有访问静态资源的时候&#xff0c;就可以使用Nginx来做服务器&#xff0c;如果一个网站只是静态页面的话&#xff0c;那么就可以通过这种方式来实现部署。 1、 首先在usr/local/test/下创建pic目录, 然后在pic中放一个test.…

Vue中v-if与v-show区别详解

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…

【jQuery入门】基础使用-入口函数、顶级对象$

文章目录 前言一、基础使用1.1 jQuery的下载1.2 简单的使用 二、顶级对象$总结 前言 jQuery是一款广泛应用于前端开发的JavaScript库&#xff0c;它简化了许多常见任务的操作&#xff0c;使得代码编写更加便捷。本文将介绍jQuery的基础使用&#xff0c;包括入口函数和顶级对象…

Docker-nacos集群部署

nacos单机模式 先拉取一个mysql docker pull mysql:5.7 定义一个挂载目录 mkdir -p /mysql/{conf,data,script} 配置一个my.cnf放到conf目录下 开启mysql容器 privilegedtrue:使用该参数&#xff0c;container内的root拥有真正的root权限&#xff0c;否则&#xff0c;cont…

鹧鸪云如何实现光伏测绘?

随着科技的飞速发展&#xff0c;新能源行业日新月异。作为可再生能源的一种&#xff0c;光伏能源日益受到重视。在此背景下&#xff0c;利用先进的技术&#xff0c;提高光伏测绘的效率&#xff0c;如卫星地图实景测绘、自动生成可研报告以及生成工程报价清单等&#xff0c;为光…

【Maven教程】(十四):生成项目站点—— 丰富项目信息、项目报告插件、自定义站点外观、国际化及部署站点 ~

Maven 生成项目站点 1️⃣ 最简单的站点2️⃣ 丰富项目信息3️⃣ 项目报告插件3.1 JavaDocs3.2 Source Xref3.3 CheckStyle3.4 PMD3.5 ChangeLog3.6 Cobertura 4️⃣ 自定义站点外观4.1 站点描述符4.2 头部内容及外观4.3 皮肤4.4 导航边栏 5️⃣ 创建自定义页面6️⃣ 国际化7️…

ConcurrentHashMap 原理

ConcurrentHashMap ConcurrentHashMap的整体架构ConcurrentHashMap的基本功能ConcurrentHashMap在性能方面的优化 concurrentHashMap&#xff1a; ConcurrentHashMap的整体架构 concurrentHashMap是由数组链表红黑树组成 当我们初始化一个ConcurrentHashMap实例时&#xff0c…

工厂企业消防安全AI可视化视频智能监管解决方案

一、方案背景 2023年11月20日下午6时30分许&#xff0c;位于江苏省无锡市惠山区前洲街道的某公司突发严重火灾&#xff0c;共造成7人死亡。这次火灾提醒我们工业安全至关重要&#xff0c;企业都应该时刻保持警惕&#xff0c;加强安全意识和培训&#xff0c;提高应对突发事件的…

前端框架前置课Node.js学习(1) fs,path,模块化,CommonJS标准,ECMAScript标准,包

目录 什么是Node.js 定义 作用: 什么是前端工程化 Node.js为何能执行Js fs模块-读写文件 模块 语法: 1.加载fs模块对象 2.写入文件内容 3.读取文件内容 Path模块-路径处理 为什么要使用path模块 语法 URL中的端口号 http模块-创建Web服务 需求 步骤: 案例:浏…

KubeSphere平台使用

KubeSphere官网地址&#xff1a;https://kubesphere.io/zh/ KubeKey一键部署K8S集群&#xff1a;https://kubesphere.io/zh/docs/v3.4/installing-on-linux/introduction/multioverview/ 一台master node&#xff08;初始化主节点&#xff09;、两台 work node&#xff08; joi…

图片太模糊我们怎么提高清晰度呢

在数字时代&#xff0c;图片是我们日常生活中不可或缺的一部分。然而&#xff0c;有时候由于各种原因&#xff0c;我们得到的图片清晰度可能并不理想。这篇文章将介绍三款软件&#xff0c;帮助你提高图片的清晰度&#xff0c;让你的图片更加生动、清晰。 一、水印云 水印云是…

VUE--插槽slot(将父级的模块片段插入到子级中)

组件可以接收任意类型的JS值作为props&#xff0c;但我们想要为子组件传递一些模板片段&#xff0c;并在子组件中进行渲染时&#xff0c;此时可以采用插槽slot来实现 简单来说&#xff0c;插槽时组件内留一个或多个插槽的位置&#xff0c;供组件传递对应的模板代码&#xff08;…