活动地址:CSDN21天学习挑战赛
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。
基础算法训练(四)折半查找
❤❤❤❤❤❤❤❤❤❤❤❤
写在前面的一些话:本人是本科在校软件工程在读准大三大学生,在跟上学校安排课程的同时,通过自学学习了Java后端开发的内容,学习了Spring,SpringMVC,SpringBoot等框架,在不断的学习中不断进步的同时,也感觉到一些迷茫,有时也会看不到前面的路该怎么走,本着一颗求知与记录的心情开始了写博客的生活,把自己的学习历程记录下来的同时,也希望认识到更多的人一起互勉学习✨✨
🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈
今天是基础算法训练的第四篇内容,学习的是折半查找,这个周末去看医生去了,整个人高烧加咳嗽缓了好久,休息了两天,今天来更新第四篇算法学习的内容,今天学习的是折半查找,今天的这个算法不算特别的难,但是这种思想真的,我第一次接触到这种查找方法的时候觉得能想到这种算法去优化查找效率的一定是个天才,这种方法真的太神奇了和之前的顺序查找完全不一样的思路!!开始今天的学习,加油加油!
第一章 🎀了解算法🎃
一、什么是算法?
算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间,空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。
二、算法的特征
一个算法应该具有以下五个重要的特征:
🧡有穷性(Finiteness):
算法的有穷性是指算法必须能在执行有限个步骤之后终止;
💛确切性 (Definiteness):
算法的每一步骤必须有确切的定义;
💚输入项(Input):
一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0个输入是指算法本身定出了初始条件;
💙输出项(Output):
一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的;
🤎可行性(Effectiveness):
算法中执行的任何计算步骤都是可以被分解为基本的可执行的操作步骤,即每个计算步骤都可以在有限时间内完成(也称之为有效性)。
三、为什么要学习算法
算法对计算机科学的所有分支都非常重要。在绝大多数的计算机科学分支领域中,要想完成任何实质性的工作,理解算法的基础知识并掌握与算法密切相关的数据结构知识是必不可少的。通过我们学习算法,可以更好的提高代码的执行效率,最关键的是可以从思维上的一个提升,通过学习算法可以更加多个角度的去看待以及处理问题,并找出一个问题的最优解
第二章 ✨查找算法🎢
在数据结构与算法中,我们一般查找的算法只要有: 顺序查找 (线性查找)、二分查找/折半查找、插值查找以及斐波那契查找 。 插值查找即就是给定一组数字,我们直接将给定的值找到,若找到则返回该值,没找到则返回-1。
而今天所学习的算法是查找算法中的折半查找
一、折半查找概念
在计算机科学中,折半搜索(英语:half-interval search),也称二分搜索(英语:binary search)、对数搜索(英语:logarithmic search),是一种在有序数组中查找某一特定元素的搜索算法。
搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半
假设有已经按照从小到大的顺序排列好的五个整数a[0]~a[4]存放到大小为5的数组a[n]中,要查找的数是X,其基本思想是: 设查找数据的范围下限为L=0,上限为R=4,求中点mid=(L+R)/2,用X与中点元素a[mid]比较,若X等于a[mid],即找到,停止查找;否则,若X大于a[mid],替换下限L=mid+1,到下半段继续查找;若X小于a[mid],换上限R=mid-1,到上半段继续查找;如此重复前面的过程直到找到或者L>R为止。如果L>R,说明没有此数,打印找不到信息,程序结束。
二、折半查找执行流程
实现顺序查找:
-
设置输入项,给定一个所需要查找的数组,以及所需查找的元素
-
设置输出项:若查找元素成功返回所处数组对应的下标index,若查询失败则返回-1
-
算法执行流程:
算法的执行流程比较的灵巧,搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半,假设有已经按照从小到大的顺序排列好的五个整数a[0]~a[4]存放到大小为5的数组a[n]中,要查找的数是X,其基本思想是: 设查找数据的范围下限为L=0,上限为R=4,求中点mid=(L+R)/2,用X与中点元素a[mid]比较,若X等于a[mid],即找到,停止查找;否则,若X大于a[mid],替换下限L=mid+1,到下半段继续查找;若X小于a[mid],换上限R=mid-1,到上半段继续查找;如此重复前面的过程直到找到或者L>R为止。如果L>R,说明没有此数,打印找不到信息,程序结束。
这是折半查找的执行图解:
三、执行代码
程序设计思路:
- 设定数组,以及所需要查询的值
- 编写算法
- 处理返回的值
输入数组a{5,6,13,13,18,18,21,24,25,32,33,34,40,42,47};
输入需要查询的值:key=21;
编写算法binarySearch();
处理返回结果
package com.Yurrize.BinarySearchSort;
public class Search {
public static void main(String[] args) {
// 给定有序数组a[]
int[] arr = {5,6,13,13,18,18,21,24,25,32,33,34,40,42,47};
//设定查找的key值为21
int key = 21;
// 调用算法,并输出结果
int result = binarySearch(arr, key);
//判断返回的值,输出对应的结果
if(result==-1){
System.out.println("没有找到key值,"+key+"在数组中不存在");
}else {
//输出最终的结果
System.out.println("成功找到key,key位于arr数组中的下标为"+result+"的位置");
}
}
public static int binarySearch(int[]arr,int key){
// 定义变量left,right,标记数组头和尾部元素
int left = 0;
int right = arr.length - 1;
// 循环终止条件为:当左超过右,代表已经遍历完一遍
while (left <= right){
// 取中间元素mid,+left防止循环出不来
int mid = (right - left) / 2 + left;
if (arr[mid] == key){
// 当a[mid]的值等于key时表示搜索到需要的数值,并返回对应的下标
return mid ;
}else if(arr[mid] > key){
// 当比key大时代表key在数组的左半边,不在右边,移动right到中间-1
right = mid - 1;
}else {
// 当比key小时代表在数组的右半边,不在左边,移动left到中间+1
left = mid + 1;
}
}
// 循环结束,没有找到对应的值,返回-1
return -1;
}
}
程序执行成功:
查询到对应的结果:返回数组下标
查询失败,输出提示
四、算法分析
时间复杂度
二分查找的平均查找长度 ASL 为 ((n+1)log2(n+1))/n-1,有的书上写的是 log2(n+1)-1,或者是 log2n,具体计算比较麻烦,这里就不讨论了。
二分查找有个很重要的特点,就是不会查找数列的全部元素,而查找的数据量其实正好符合元素的对数,正常情况下每次查找的元素都在一半一半地减少。所以二分查找时间复杂度为 O(log2n)
是毫无疑问的。当然,最好的情况是只查找一次就能找到,但是在最坏和一般情况下的确要比顺序查找好了很多。
空间复杂度
由于算法不会改变原有的元素集合,只需要一个额外的变量控制索引变化,所以空间复杂度为常数级:O(1)。
🥽总结🎪
今天是第一次接触到非暴力的查找算法,折半查找是一种效率高的查找算法,同时需要深刻的理解他的原理一半一半的查找,编写代码的时候才会写的非常的顺畅,是一种非常锻炼思维的灵活的算法