C语言:查找算法

来源:互联网 发布:淘宝不能申请售后 编辑:程序博客网 时间:2024/04/28 16:55

查找是指从一组记录集合中找出满足给定条件的记录。今天给大家介绍三种基本的查找算法: 顺序查找、折半查找和索引查找。

一、顺序查找

基本思想:

从查找表的一端开始,逐个将记录的关键字和给定的值进行比较,如果某个记录的关键字和给定值相等,则称查找成功;否则说明查找表中不存在关键值为给定值的记录,则称查找失败。

代码清单:

int sequenceSearch(int *a, int length, int k) {    for (int i = 0; i < length; i++) {        if (k == a[i]) {            return i;        }    }    return -1;}

参数说明:

a: 表示给定的记录集合。

length: 表示给定记录集合的个数。

k: 表示给定值。

结论分析:

顺序查找的优点是算法简单,且对表的结构没有任何要求。它的缺点就是查询效率低,因此,当表中元素个数比较多时,不宜采用顺序查找。

二、折半查找(二分查找)

前提条件:

1. 要求查找表中的记录按关键字有序排列。

2. 只能适用于顺序存储结构。

基本思想:

先取查找表的中间位置的关键字与给定值作比较,若他们的值相等,则查找成功;如果给定值比该记录的关键字值大,说明要查找的记录一定在查找表的后半部分,则在查找表的后半分继续使用遮半查找;反之,在查找表的前半部分使用折半查找....... 直到查找成功,或者直到确定查找表中没有待查找的记录为止,即查找失败。

流程图演示:


代码清单:

int binSearch(int *a, int length, int k) {    int low = 0, high = length - 1, mid = 0, find = 0;    while ((low <= high) && (!find)) {        mid = (low + high) / 2;        if (k == a[mid]) {            find = 1;            break;        } else {            if (k > a[mid]) {                low = mid + 1;            } else {                high = mid - 1;            }        }    }        if (find) {        return mid;    } else {        return -1;    }}

参数说明:

a: 表示给定的记录集合。

length: 表示给定记录集合的个数。

k: 表示给定值。

结论分析:

折半查找要求查找表按关键字有序,而排序是一种很费事的运算;另外,折半查找要求表是顺序存储的,为保持表的有序性,在进行插入和删除操作时,都必须移动大量记录。因此,折半查找的高查找效率是以牺牲排序为代价的,它特别适合于一经建立就很少移动、而又经常需要查找的线性表。

三、索引查找

基本思想:

索引查找又称为分块查找,即把线性表分成若干块,在每一块中记录的关键字不一定有序,但是块与块之间必须有序。假设这种排序是按关键字值递增排序的,抽取各块中的最大关键字及该块的起始位置构成索引表,按块的顺序存放在一个数组中,显然这个数组是有序的,一般按升序排列。文字描述有点晦涩,示意图如下:



其中,索引表很明显是一个结构体,它的定义如下:

struct idtable {    int key;    int address;    int length;};

key: 索引表中的关键字。

address: 索引表对应块的首地址。

length: 索引表对应块的长度。

从上面的示意图我们可以看出,索引查找,我们可以先对索引表进行折半查找,找出对应的块,然后再在对应的快中利用顺序查找找出需要查找的关键字。

代码清单:

struct idtable {    int key;    int address;    int length;};int indexSearch(int *a, int a_length, struct idtable idtables[], int idtables_length, int keyword) {    // 先用二分查找法找出对应的块号    int low1 = 0, high1 = idtables_length - 1, mid = 0;    while (low1 <= high1) {        mid = (low1 + high1) / 2;        if (keyword <= idtables[mid].key) {            high1 = mid - 1;        } else {            low1 = mid + 1;  // 查找完毕,low1存放块号        }    }        if (low1 < idtables_length) {        int index = -1;        // low2为块在表中的起始地址        int low2 = idtables[low1].address, high2 = 0;        if (low1 == idtables_length - 1) {            high2 = a_length - 1;        } else {            high2 = idtables[low1 + 1].address - 1;        }                // 用顺序查找法在对应的块中找出符合条件的值        for (int i = low2; i <= high2; i++) {            if (a[i] == keyword) {                index = i;                break;            }        }                return index;    } else {        return -1;    }}int main(int argc, const char * argv[]) {        // 主表    int a[] = {22, 12, 13, 8, 9, 20, 33, 42, 44, 38, 24, 46, 60, 58, 74, 47, 86, 53};    // 索引表    struct idtable idtables[3] = {        {22, 0, 6},        {46, 6, 6},        {86, 12, 6}    };        int result = indexSearch(a, 18, idtables, 3, 74);        printf("index:%d", result);        return 0;}

结论分析:

索引查找的效率介于顺序查找和折半查找之间,对于数据量巨大的线性表,它是一种较好的方法。在表中插入或者删除一个记录时,只要找到该记录所属的块,就可以在该块内进行插入和删除运算,插入和删除无需移动大量记录。分块查找的主要代价:需要增加一个辅助数组的存储空间和将初始表分块排序的运算。

0 0
原创粉丝点击