一、顺序查找java
二分查找mysql
算法思想:又叫折半查找,要求待查找的序列有序。每次取中间位置的值与待查关键字比较,若是中间位置的值比待查关键字大,则在前半部分循环这个查找的过程,若是中间位置的值比待查关键字小,则在后半部分循环这个查找的过程。直到查找到了为止,不然序列中没有待查的关键字。算法
实现:sql
1.非递归代码数据库
public static int biSearch(int []array,int a){ int lo=0; int hi=array.length-1; int mid; while(lo<=hi){ mid=(lo+hi)/2; if(array[mid]==a){ return mid+1; }else if(array[mid]<a){ lo=mid+1; }else{ hi=mid-1; } } return -1; }
2.递归实现数组
public static int sort(int []array,int a,int lo,int hi){ if(lo<=hi){ int mid=(lo+hi)/2; if(a==array[mid]){ return mid+1; } else if(a>array[mid]){ return sort(array,a,mid+1,hi); }else{ return sort(array,a,lo,mid-1); } } return -1; }
时间复杂度为 O(logN) app
查找第一个元素出现的位置(元素容许重复)函数
public static int biSearch(int []array,int a){ int n=array.length; int low=0; int hi=n-1; int mid=0; while(low<hi){ mid=(low+hi)/2; if(array[mid]<a){ low=mid+1; }else{ hi=mid; } } if(array[low]!=a){ return -1; }else{ return low; } }
查询元素最后一次出现的位置性能
public static int biSearch(int []array,int a){ int n=array.length; int low=0; int hi=n-1; int mid=0; while(low<hi){ mid=(low+hi+1)/2; if(array[mid]<=a){ low=mid; }else{ hi=mid-1; } } if(array[low]!=a){ return -1; }else{ return hi; } }
1测试 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
平均性能:斐波那契>折半>插值,由于折半查找是加法与除法的运算,插值为四则运算,斐波那契加减运算。
分块查找
分块查找是将顺序查找与折半查找相结合的一种查找方法。
基本思想:
1. 首先将查找表分红若干块,在每一块中数据元素的存放是任意的,但块与块之间必须是有序的(假设这种排序是按关键字值递增的,也就是说在第一块中任意一个数 据元素的关键字都小于第二块中全部数据元素的关键字,第二块中任意一个数据元素的关键字都小于第三块中全部数据元素的关键字,依次类推);
2. 创建一个索引表,把每块中最大的关键字值按块的顺序存放在一个辅助数组中,这个索引表也按升序排列;
3. 查找时先用给定的关键字值在索引表中查找,肯定知足条件的数据元素存放在哪一个块中,查找方法既能够是折半方法,也能够是顺序查找。
4. 再到相应的块中顺序查找,即可以获得查找的结果。
案例分析:
一个查找表共有15个数据元素,现将它分红三块,每块5个数据元素,各块采用顺序方式独立存放在数组B一、B二、B3之中,辅助数组A的每一个元素 包含两个域,关键字域中存放该块中关键字的上确界(本块中最大的关键字值),指针域存放该块的数组始址,存放状态如图6-5所示。
若是要查找关键字为66的数据元素,首先用66与A中各个元素的key比较,因为66<74,肯定66在第三块中(若是存在),而后按A[2].link 到数组B3中采用顺序查找找到B3[2],查找成功。
/**
* 分块查找
*
* @param index 索引表,其中放的是各块的最大值
* @param st 顺序表,
* @param key 要查找的值
* @param m 顺序表中各块的长度相等,为m
* @return
*/
private int BlockSearch(int[ ] index, int[ ] st, int key, int m)
{
// 在序列st数组中,用分块查找方法查找关键字为key的记录
// 1.在index[ ] 中折半查找,肯定要查找的key属于哪一个块中
int i = partSearch(index, key);
if(i >= 0)
{
int j = i > 0 ? i * m : i;
int len = (i + 1) * m;
// 在肯定的块中用顺序查找方法查找key
for(int k = j; k < len; k++)
{
if(key == st[k])
{
System.out.println("查询成功");
return k;
}
}
}
System.out.println("查找失败");
return -1;
}
public int partSearchs(int[] data, int tmpData)
{
int mid;
int low = 0;
int high = data.length - 1;
while(low <= high)
{
mid = (low + high) / 2; // 中间位置
if(tmpData == data[mid])
{
return mid;
}
else if(tmpData < data[mid])
{
high = mid - 1;
}
else
{
low = mid + 1;
return low;
}
}
return -1; // 没有查找到
}
优势:
①在表中插入或删除一个记录时,只要找到该记录所属的块,就在该块内进行插入和删除运算。
②因块内记录的存放是任意的,因此插入或删除比较容易,无须移动大量记录。
分块查找的主要代价是增长一个辅助数组的存储空间和将初始表分块排序的运算。
分块查找算法的效率介于顺序查找和二分查找之间。
若表中有10000个结点,则应把它分红100个块,每块中含100个结点。用顺序查找肯定块,分块查找平均须要作100次比较,而顺序查找平均需作5000次比较,二分查找最多需14次比较。
分块查找(索引顺序查找)
它是顺序查的的一种改进方法。在此查找法中,除自己外,尚需创建一个"索引表"。索引表里有m个记录,每一个索引n个元素,m*n等于数组的长度。其中包括两项内容:关键字(其值为该子表最大关键字)和指针(指示表第一个记录在表中的位置)
过程分两步进行:1.先用二分法查找索引表,肯定要找的记录在哪一块; 2.而后再在相应块用顺序查找找到目标记录。分块查找又称为索引顺序查找。
使用了二分查找法和顺序查找法,因此其时间复杂度应为两者之合。即:O(log(2m))+O(n)=O(log(2m)+n)=O(log(2m)+length/m)
哈希查找
哈希查找是经过计算数据元素的存储地址进行查找的一种方法。O(1)的查找,即所谓的秒杀。哈希查找的本质是先将数据映射成它的哈希值。哈希查找的核心是构造一个哈希函数,它将原来直观、整洁的数据映射为看上去彷佛是随机的一些整数。
哈希查找的操做步骤:
1) 用给定的哈希函数构造哈希表;
2) 根据选择的冲突处理方法解决地址冲突;
3) 在哈希表的基础上执行哈希查找。
创建哈希表操做步骤:
1) step1 取数据元素的关键字key,计算其哈希函数值(地址)。若该地址对应的存储空间尚未被占用,则将该元素存入;不然执行step2解决冲突。
2) step2 根据选择的冲突处理方法,计算关键字key的下一个存储地址。若下一个存储地址仍被占用,则继续执行step2,直到找到能用的存储地址为止。
哈希查找步骤为:
1) Step1 对给定k值,计算哈希地址 Di=H(k);若HST为空,则查找失败;若HST=k,则查找成功;不然,执行step2(处理冲突)。
2) Step2 重复计算处理冲突的下一个存储地址 Dk=R(Dk-1),直到HST[Dk]为空,或HST[Dk]=k为止。若HST[Dk]=K,则查找成功,不然查找失败。
好比说:”5“是一个要保存的数,而后我丢给哈希函数,哈希函数给我返回一个”2",那么此时的”5“和“2”就创建一种对应关系,这种关系就是所谓的“哈希关系”,在实际应用中也就造成了”2“是key,”5“是value。
那么有的朋友就会问如何作哈希,首先作哈希必需要遵照两点原则:
①: key尽量的分散,也就是我丢一个“6”和“5”给你,你都返回一个“2”,那么这样的哈希函数不尽完美。
②:哈希函数尽量的简单,也就是说丢一个“6”给你,你哈希函数要搞1小时才能给我,这样也是很差的。
其实经常使用的作哈希的手法有“五种”:
第一种:”直接定址法“。
很容易理解,key=Value+C;这个“C"是常量。Value+C其实就是一个简单的哈希函数。
第二种:“除法取余法”。
很容易理解, key=value%C;解释同上。
第三种:“数字分析法”。
这种蛮有意思,好比有一组value1=112233,value2=112633,value3=119033,
针对这样的数咱们分析数中间两个数比较波动,其余数不变。那么咱们取key的值就能够是
key1=22,key2=26,key3=90。
第四种:“平方取中法”。此处忽略,见名识意。
第五种:“折叠法”。
这种蛮有意思,好比value=135790,要求key是2位数的散列值。那么咱们将value变为13+57+90=160,而后去掉高位“1”,此时key=60,哈哈,这就是他们的哈希关系,这样作的目的就是key与每一位value都相关,来作到“散列地址”尽量分散的目地。
影响哈希查找效率的一个重要因素是哈希函数自己。当两个不一样的数据元素的哈希值相同时,就会发生冲突。为减小发生冲突的可能性,哈希函数应该将数据尽量分散地映射到哈希表的每个表项中。
解决冲突的方法有如下两种:
(1) 开放地址法
若是两个数据元素的哈希值相同,则在哈希表中为后插入的数据元素另外选择一个表项。当程序查找哈希表时,若是没有在第一个对应的哈希表项中找到符合查找要求的数据元素,程序就会继续日后查找,直到找到一个符合查找要求的数据元素,或者遇到一个空的表项。
(2) 链地址法
将哈希值相同的数据元素存放在一个链表中,在查找哈希表的过程当中,当查找到这个链表时,必须采用线性查找方法。
实现哈希函数为“除法取余法”,解决冲突为“开放地址线性探测法”,代码以下:
[java] view plain copy
索引查找是在索引表和主表(即线性表的索引存储结构)上进行的查找。
索引查找的过程是:
1) 首先根据给定的索引值K1,在索引表上查找出索引值等于KI的索引项,以肯定对应予表在主表中的开始位置和长度,
2) 而后再根据给定的关键字K2,茬对应的子表中查找出关键字等于K2的元素(结点)。对索引表或子表进行查找时,若表是顺序存储的有序表,则既可进行顺序查找,也可进行二分查找,不然只能进行顺序查找。
一提到“索引”,估计你们第一反应就是“数据库索引”,对的,其实主键创建“索引”,就是方便咱们在海量数据中查找。
实现索引查找时常使用的三个术语:
1) 主表:这个很简单,要查找的对象。
2) 索引项:通常咱们会用函数将一个主表划分红几个子表,每一个子表创建一个索引,这个索引叫作索引项。
3) 索引表:索引项的集合也就是索引表。
通常“索引项”包含三种内容:index,start,length
第一: index,也就是索引指向主表的关键字。
第二:start,也就是index在主表中的位置。
第三:length, 也就是子表的区间长度。
代码实现:
[java] view plain copy
其时间复杂度为O(1);