数据排序与搜索在任何语言编程中都非常常见且常用,并且经常需要实现不同数据类型的搜索。对于数据规模比较小,且未排序的数据(如从传感器采集来的数据)要查到某个数据的话,一般使用的是线性搜索。对于整数类型数据的搜索,可以使用类似下面的方法来实现:
int lsearch( int key, int array[], int size)
{
for(int i=0; i
{
if(array[i] == key)
{
return i;
}
}
return -1;
}
这段程序中,值得注意有两点。一个是由于sizeof(int) ==
4,所以指针每一跳为四个字节,即&array[i+1]
-&array[i]的结果为4。另外一个是array[i] ==
key,每次比较的字节数为sizeof(int)。
现在知道了一个线性搜索函数要知道每次指针跳向下次跳的字节数和如何比较两个数据是否相等。因此,进行范式编程时,除了前面这个函数的几个参数外,必须传入这两个参数,及每个元素的大小,以及如何比较这两个元素。
实现
对于一个要查找的元素key,我们并不知道其大小,因此我们需要将这个元素的地址和大小传入到lserach中。此外,还需要知道要查找数组的大小以便能够知道最多查找的次数,还需要知道每个元素大小以便进行迭代。
方法一:
void *lsearch(void *key, void base, int n, int elemSize)
{
for(int i=0; i
{
void *elemAddr = (char *)base + i*elemSize;
if(memcmp(key,elemAddr,elemSize) == 0)
return e.emAddr;
}
return 0;
}
方法二:
void *lsearch(void *key, void *base ,int n, int elemSize,
int (*cmpfn)(void *,void *))
{
for(int i=0; i
{
void *elemAddr = (char *)base + i*elemSize;
if(cmpfn(key,elemAddr) == 0)
return elemAddr;
}
return NULL;
}
这里,需要注意的是int (*cmpfn)(void *,void
*)中,并没有传入元素的大小,这是因为我们在调用lsearch之前就知道了如何比较两个元素是否相等。当然,这个元素需要调用者自己写。
一个简单的例子
int cmpfn(void *elem1, void *elem2)
{
int *ip1 = elem1;
int *ip2 = elem2;
return *ip1 - *ip2;
}
void *lsearch(void *key, void *base ,int n, int elemSize,\
int (*cmpfn)(void *,void *))
{
int i=0;
for( i=0; i
{
void *elemAddr = (char *)base + i*elemSize;
if(cmpfn(key,elemAddr) == 0)
return elemAddr;
}
return NULL;
}
int main()
{
int array[] = {1,3,5,7,9,11,13,15,17,19};
int key1 = 13;
int key2 = 33;
int *find1 = NULL;
int *find2 = NULL;
find1 = lsearch(&key1,array,sizeof(array)/sizeof(int),\
sizeof(int),cmpfn);
find2 = lsearch(&key2,array,sizeof(array)/sizeof(int),\
sizeof(int),cmpfn);
printf("address of array is:%p\n",array);
printf("address of find1 is:%p\n",find1);
printf("address of find2 is:%p\n",find2);
}
结果:
可以看到,这个函数实现了我们需要的功能。
以上两种方法都可以实现范类型的的线性搜索。对比方法二和方法一可以看到:两个方法实现的效果都一样,方法二的效率可能会高一些,因为知道了数据类型写cmpfn的,而方法一只能一个字节一个字节的去比较。效率较低。