一、顺序查找
按索引顺序查找,可用于查找无序序列
int SequenceSearch(vector<int> seq, int key)
{
const int c_len = seq.size();
for(int i=0; i<c_len; ++i)
if(seq[i] == key)
return i; // 找到key = seq[i]
return -1; // key不在表中,查找失败
}
时间复杂度:T(n) = θ(n)
二、二分查找
待查找序列必须有序
过程:
通过将待查找的值key与序列中位数比较,判断key在左半序列还是右半序列;然后在新的序列(左半序列或右半序列)中继续做二分查找,直到找到或序列查找完毕
int BinarySearch(vector<int> seq, int key)
{
const int c_len = seq.size();
int left = 0, right = c_len, middle;
while(left < right)
{
middle = (left + right) / 2;
if(seq[middle] == key)
return middle; // 找到key = seq[middle]
else if(seq[middle] > key)
right = middle; // key 不会等于 seq[right]
else if(seq[middle] < key)
left = middle + 1; //key 可能等于 seq[left]
}
return -1; // key不在表中,查找失败
}
时间复杂度:while循环次数最大为lgn(向上取整)(以2为底)
T(n) <= lgn x 常数 = O(lgn)
三、分块查找
性能位于顺序查找和二分查找中间
除了存储待排序序列之外,还需要存储一个索引表(键为序列中的元素,对应的值为元素所在的块)
假设待排序序列有n个元素,将待排序序列分成k个块,每块中的元素为n/k+1(最后一块的元素小于等于n/k+1);
这k个块总体是有序的,即第i块中的任意元素一定小于第i+1块中的任意元素;
每个块中的元素是无序的。
步骤:先找到待查找元素key的块索引,再在相应的块中查找key
由于k个块总体有序,所以可以使用顺序查找或者二分查找来查找块索引;
由于块中元素是无序的,所以只能通过顺序查找在相应块中查找key。
c++代码:
//在seq[p~q]中顺序查找key
int SequenceSearch1(vector<int> seq, int key, int p, int q); // IndexSearch中使用
int BinarySearch1(vector<int> seq, int key); // IndexSearch中使用
int IndexSearch(vector<int> seq, int key, const int k)
{
const int c_len = seq.size();
const int max_n = c_len / k + 1;
map<int, int> block_table; // black_min[i], block_index
vector<int> block_min;
for(int i=0; i<k; ++i)
{
block_table[seq[max_n*i]] = i; // 为了方便,比第i块最小值大,比第i+1块最小值小的元素块索引为i
block_min.push_back(seq[max_n*i]); //为了方便,这里的seq排过序了,所以每块的最小值就是每个块的第一个元素
}
int min_index = BinarySearch1(block_min, key);
if(min_index == -1) // key<min(seq)
return -1;
else
{
int block_index = block_table[block_min[min_index]];
int index_left = block_index*max_n;
int index_right = index_left + max_n;
if (index_right > c_len)
index_right = c_len;
return SequenceSearch1(seq, key, index_left, index_right);
}
}
int SequenceSearch1(vector<int> seq, int key, int p, int q)
{
for(int i=p; i<q; ++i)
if(seq[i] == key)
return i;
return -1;
}
int BinarySearch1(vector<int> seq, int key)
{
const int c_len = seq.size();
int left = 0, right = c_len, middle;
while(left < right)
{
middle = (left + right) / 2;
if(seq[middle] <= key)
if((seq[middle+1] > key) || (middle + 1 >= c_len))
return middle;
else
left = middle + 1;
else
right = middle;
}
return -1;
}
时间复杂度:
若查找块索引时使用二分查找,则块索引的时间复杂度为θ(lgk) (假设分成k块);若采用顺序查找,则块索引时间复杂度为θ(k)
在块中使用顺序查找的时间复杂度为θ(n/k)
所以T(n) = θ(n/k+lgk) 或θ(n/k+k)