@数据结构复习笔记(二):
数据结构的有序查找
今天主要学的是排查找,这里我们就简单的讲一下几种常见的有序查找:
1.顺序查找(较通用,适用所有情况)
2.二分查找
3.二分查找非递归
-----------------------------二分查找的优化------------------------
4.插值查找
5.fib查找
6.分块查找(无代码,懒~)
先来看查找的输入输出:
给定一个任意无序定长数组num[10]={1,3,5,7,9,2,4,6,8,10}
因为今天写的是有序查找
所以待会儿会将其先进行排序(有关排序可以看我的第一篇文章)
现在排序完成的num是{1,2,3,4,5,6,7,8,9,10}
现在我们的目标值是7
我们需要从现在的有序数组中去找到这个值7的下标即6(下标从0开始)
需要得到6即找到
若未找到输出-1
看似简单的过程:可以有很多种处理的方法:
先看看第一种查找:
顺序查找:
这种查找方法是最简单的,也是初学c语言的必做题之一。
方法就是对数组进行一次遍历,遍历中通过比较,找到值就把下标返回,并跳出循环,如果遍历一遍未找到值
则输出-1
方法简单粗暴,时间复杂度O(n)
不多做分析,上代码
int findGoalbyOrder(int num[], int len, int goal) {
for (int i = 0; i < len; i++)
{
if (num[i] == goal)
return i;
}
return -1;
};
二分查找(非递归):
上一次讲插入排序的时候有提到优化插入排序的方法,即要找到插入位置是一个查找过程,通过二分查找可以把查找的时间复杂度缩减到O(logn)
这里就讲一下二分查找
二分找到的思路是我们从小到大都接触到的一种常用方法
即从数组中间部分开始查找,先看数组的中间值(这里记作mid)
如果mid=goal //goal为目标值
就将mid的下标返回;
如果mid>goal
将范围缩至mid的前半部分;
如果mid<goal
将范围缩至mid的后半部分;
上代码
int findGoalbyBinarySearch(int num[], int goal, int n)
{
int low, high, mid;
low = 0;
high = n - 1;
while (low <= high)
{
mid = (low + high) / 2;
if (num[mid] == goal)
return mid;
if (num[mid] > goal)
high = mid - 1;
if (num[mid] < goal)
low = mid + 1;
}
return -1;
}
二分查找(递归):
代码
int BinarySearch2(int num[], int goal, int low, int high)
{
int mid = low + (high - low) / 2;
if (num[mid] == goal)
return mid;
if (num[mid] > goal)
return BinarySearch2(num, goal, low, mid - 1);
if (num[mid] < goal)
return BinarySearch2(num, goal, mid + 1, high);
}
-----------------------------二分查找的优化------------------------
插值查找
插值查找优化了二分查找
二分查找选取中间位置,插值查找则通过查找值判定大概位于序列的哪个位置比例。
思路大致相同于二分查找
不同之处在于二分查找是确定中间位置向两边查找,而插值查找则是先根据目标值判定大概的位置比例
即修改二分查找中的mid值
mid = low + (goal - num[low]) / (num[high] - num[low]) * (high - low);
这样看着不太直观
我们看看这个式子到底是什么样子:
上面这个图展示了如何从二分查找的式子变化成插值查找的狮子的,即修改系数1/2,用目标值减去起始下标比上整个数组的长度,得到的比例则是系数
int findGoalbyInsertvalue(int num[], int len, int goal) {
int low, high, mid;
low = 0;
high = len - 1;
while (low <= high)
{
mid = low + (goal - num[low]) / (num[high] - num[low]) * (high - low);
if (num[mid] == goal)
return mid;
if (num[mid] > goal)
high = mid - 1;
if (num[mid] < goal)
low = mid + 1;
}
return -1;
};
非递归类比之前二分查找
fib查找
看起来很高端的一种查找
实际上还是二分查找的一种优化
(这里我os一下:我搜了下fib查找比二分查找好在哪儿,基本上都说的是:获取mid的方式是只通过加减,不需要乘除,这里优化了很多,因为时间复杂度肯定没有优化还是logn级,这里噢,我个人感觉是因为黄金分割率给查找带来的好处,因为查找很多情况,目标数组不一定可读,而黄金分割率在很多地方都有存在,可能统计学上,黄金分割率可能广泛存在吧,欢迎大佬讲解!!!!!)
回归正题,这里我们讲解一下fib查找——斐波那契((Fibonacci)查找(黄金分割查找)
首先不得不提的就是斐波那契数列,这个数列被广泛使用,因为其独特的存在,无论是数列还是计算机的递归,这都是一个不可绕开的话题,即给出前两项1,1,从现在起的下一项都等于前两项的和
1 1 2 3 5 8 13…
数据显示,这个数列的第n项,当n趋于无穷大时,lim fib(n-1)/fib(n)=golden section即约等于0.618
黄金分割率的前32位
0.6180339887 4989484820 458683436565
难道618是这么来的????
好了现在我们已经知道了fib数列
来看看fib查找:
就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为F[n],完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
简单来说
第一步 确定一个新的数组(此数组位原数组+补位0或补位数):根据原数组长度n,在fib数列中招到一个fib[x],使得fib[x]>n,刚好大于就行
第二步,找到比率值,找到了fib[x],那么前面的一个数fib[x-1]/fib[x]就约等于0.618,所以fib[x-1]则位mid的位置,0.618就类似于上面插值查找的那个系数
第三步,同二分查找,若mid大,范围往左,反之往右
上代码
//这里是获取mid 即通过fib数列获取到比例值所在的位置
int getMid(int len) {
int num1,num2,temp,mid;
num1 = num2 = 1;
while (num2 < len) {
temp = num2;
num2 = num1 + num2;
num1 = temp;
}
mid = num1;
return mid-1; //数组下标从0开始,为了省事,我们直接在这里返回的是数组的下标值
};
上面给了插值的非递归,这里给个递归,感兴趣的可以写一写非递归的噢,顺道发我一份,hhhh
int findGoalbyFib(int num[], int goal, int low, int high) {
int mid = low + getMid(high - low + 1);
if (num[mid] == goal)
return mid;
if (num[mid] > goal)
return findGoalbyFib(num, goal, low, mid - 1);
if (num[mid] < goal)
return findGoalbyFib(num, goal, mid + 1, high);
};
分块查找(无代码,懒~)
分块查找又称索引顺序查找,它是顺序查找的一种改进方法。
算法思想:将n个数据元素"按块有序"划分为m块(m ≤ n)。每一块中的结点不必有序,但块与块之间必须"按块有序";即第1块中任一元素的关键字都必须小于第2块中任一元素的关键字;而第2块中任一元素又都必须小于第3块中的任一元素,……
算法流程:
step1 先选取各块中的最大关键字构成一个索引表;
step2 查找分两个部分:先对索引表进行二分查找或顺序查找,以确定待查记录在哪一块中;然后,在已确定的块中用顺序法进行查找。
放个完整的代码:
// search_al.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
/*
查找算法1
线性查找:顺序查找,折半查找,插值查找,fib查找
本实验为线性查找算法
在任意无序数组中查找给定值的数
如:在数组num中查找最大数或给定数
创建人:hu#
创建时间:2020.7.29
*/
//
#include <iostream>
using namespace std;
int getMid(int len);
int findGoalbyOrder(int num[], int len,int goal);
int findGoalbyBinarySearch(int num[], int goal, int n);
int findGoalbyInsertvalue(int num[], int len, int goal);
int findGoalbyFib(int num[], int goal, int low, int high);
int BinarySearch2(int num[], int goal, int low, int high);
int main()
{
int num[10] = {1,2,3,4,5,6,7,8,9,10};
int goal = 7;
int length = sizeof(num)/sizeof(num[0]);
int result = findGoalbyOrder(num,length,goal);
cout << result << endl;
result = findGoalbyBinarySearch(num, goal, length);
cout << result << endl;
result = BinarySearch2(num,goal,0,9);
cout << result << endl;
result = findGoalbyInsertvalue(num, goal, length);
cout << result << endl;
result = findGoalbyFib(num, goal, 0, 9);
cout << result << endl;
}
int findGoalbyOrder(int num[], int len, int goal) {
for (int i = 0; i < len; i++)
{
if (num[i] == goal)
return i;
}
return -1;
};
int findGoalbyBinarySearch(int num[], int goal, int n)
{
int low, high, mid;
low = 0;
high = n - 1;
while (low <= high)
{
mid = (low + high) / 2;
if (num[mid] == goal)
return mid;
if (num[mid] > goal)
high = mid - 1;
if (num[mid] < goal)
low = mid + 1;
}
return -1;
}
int BinarySearch2(int num[], int goal, int low, int high)
{
int mid = low + (high - low) / 2;
if (num[mid] == goal)
return mid;
if (num[mid] > goal)
return BinarySearch2(num, goal, low, mid - 1);
if (num[mid] < goal)
return BinarySearch2(num, goal, mid + 1, high);
}
int findGoalbyInsertvalue(int num[], int len, int goal) {
int low, high, mid;
low = 0;
high = len - 1;
while (low <= high)
{
mid = low + (goal - num[low]) / (num[high] - num[low]) * (high - low);
if (num[mid] == goal)
return mid;
if (num[mid] > goal)
high = mid - 1;
if (num[mid] < goal)
low = mid + 1;
}
return -1;
};
int getMid(int len) {
int num1,num2,temp,mid;
num1 = num2 = 1;
while (num2 < len) {
temp = num2;
num2 = num1 + num2;
num1 = temp;
}
mid = num1;
return mid-1; //数组下标从0开始,为了省事,我们直接在这里返回的是数组的下标值
};
int findGoalbyFib(int num[], int goal, int low, int high) {
int mid = low + getMid(high - low + 1);
if (num[mid] == goal)
return mid;
if (num[mid] > goal)
return findGoalbyFib(num, goal, low, mid - 1);
if (num[mid] < goal)
return findGoalbyFib(num, goal, mid + 1, high);
};
今天的分享到此结束啦,欢迎大家讨论!!!!!!