主要参考七大查找算法
- 无序查找:被查找数列有序无序均可;
- 有序查找:被查找数列必须为有序数列。
顺序查找
- 就是平时常用的暴力搜索,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没有找到关键字等于k的结点,表示查找失败。
- 时间复杂度: O(n) O ( n )
int SequenceSearch(int array[], int value, int len){
for(int i = 0; i < len; i++){
if(array[i] == value)
return i;
}
return -1;
}
二分查找
- 也称为折半查找,属于有序查找算法。用给定值k先与中间结点的关键字比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。
- 时间复杂度: O(log(n)) O ( l o g ( n ) )
/*第一种方法*/
int BinarySearch1(int array[], int value, int len){
int low = 0, high = len - 1;
int mid = 0;
while(low < high){
mid = (low + high) >> 1;
if(array[mid] == value)
return mid;
if(array[mid] > value)
high = mid -1;
if(array[mid] < value)
low = mid + 1;
}
return -1;
}
/*第二种方法,基于递归的思想*/
int BinarySearch2(int array[], int value, int low, int high){
int mid = low + (high - low) / 2;
if(array[mid] == value)
return mid;
if(array[mid] > value)
BinarySearch2(array, value, low, mid - 1);
if(array[mid] > value)
BinarySearch2(array, value, mid + 1, high);
}
插值查找
在介绍插值查找之前,首先考虑一个新问题,如果要在取值范围1 ~ 10000 之间 100 个元素从小到大均匀分布的数组中查找5, 我们自然会考虑从数组下标较小的开始查找。
经过以上分析,折半查找这种查找方式,不是自适应的(也就是说是傻瓜式的)。二分查找中查找点计算如下:
mid=(low+high)/2
m
i
d
=
(
l
o
w
+
h
i
g
h
)
/
2
, 即
mid=low+1/2∗(high−low)
m
i
d
=
l
o
w
+
1
/
2
∗
(
h
i
g
h
−
l
o
w
)
;
通过类比,我们可以将查找的点改进为如下:
mid=low+(key−a[low])/(a[high]−a[low])∗(high−low)
m
i
d
=
l
o
w
+
(
k
e
y
−
a
[
l
o
w
]
)
/
(
a
[
h
i
g
h
]
−
a
[
l
o
w
]
)
∗
(
h
i
g
h
−
l
o
w
)
,
也就是将上述的比例参数1/2改进为自适应的,根据关键字在整个有序表中所处的位置,让mid值的变化更靠近关键字key,这样也就间接地减少了比较次数。
时间复杂度:
O(log(log(n)))
O
(
l
o
g
(
l
o
g
(
n
)
)
)
斐波那契查找
树查找
分块查找
分块查找又称索引顺序查找,它是顺序查找的一种改进方法。
算法思想:将n个数据元素”按块有序”划分为m块(m ≤ n)。每一块中的结点不必有序,但块与块之间必须”按块有序”;即第1块中任一元素的关键字都必须小于第2块中任一元素的关键字;而第2块中任一元素又都必须小于第3块中的任一元素,……
算法流程:
step1. 先选取各块中的最大关键字构成一个索引表;
step2. 查找分两个部分:先对索引表进行二分查找或顺序查找,以确定待查记录在哪一块中;然后,在已确定的块中用顺序法进行查找。
哈希查找
先简单整理一下哈希表相应的知识。
哈希表也成为散列表,是使用哈希函数将关键字映射到对应值的数据结构。对关键字的不同类型,可以设计不同的散列函数。
解决哈希冲突的两种方法:
1. 开散列法(Open Hashing)也称为链接法。
散列表中的每个元素为一个链表,被映射到相同下标的关键字放在对应的链表中。如图,Hash函数为
f(x)=x%7
f
(
x
)
=
x
%
7
,那么关键字8,22呗映射到下标1,为了解决冲突,将8和22以链表的形式存储在下标1对应的元素中。
2. 开放寻址法(Open Addressing)。
所有元素都被储存在散列表里。 当有冲突时,通过叹茶函数g(x)来计算下一个待检查的下标,直到碰到一个空的下标为止。
复杂度分析:单纯论查找复杂度:对于无冲突的Hash表而言,查找复杂度为O(1)(注意,在查找之前我们需要构建相应的Hash表)