查找:順序查找、二分查找、分塊查找

1、順序查找c++

按索引順序查找,可用於查找無序序列性能

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)code


2、二分查找排序

待查找序列必須有序索引

過程:table

經過將待查找的值key與序列中位數比較,判斷key在左半序列仍是右半序列;而後在新的序列(左半序列或右半序列)中繼續作二分查找,直到找到或序列查找完畢class

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)
map

3、分塊查找tab

性能位於順序查找和二分查找中間

除了存儲待排序序列以外,還須要存儲一個索引表(鍵爲序列中的元素,對應的值爲元素所在的塊)

假設待排序序列有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)