C中的通用二进制搜索

时间:2017-06-11 13:26:57

标签: c generic-programming

我在为通用二进制搜索编写的代码时遇到问题。 当我尝试在字符串数组上执行搜索时,我注意到传递给binSearch函数的字符串数组不包含字符串。

有人可以暗示提示吗?

非常欣赏

#define SIZE 100
typedef unsigned char BYTE

请考虑这个主要内容:

void main()
{


char ** stringArr, stringToFind[SIZE];
int stringSize;
int res;

    stringArr = getStringArr(&stringSize);

    // string to find
    gets(stringToFind);


    res = stringBinSearch(stringArr, stringSize, stringToFind);

    if (res == 1)
        printf("The string %s was found\n", stringToFind);
    else
        printf("The string %s was not found\n", stringToFind);
}

char** getStringArr(int* stringSize)
{
    int i, size, len;
    char** arr;
    char temp[SIZE];


    scanf("%d", &size);
    getchar();

    arr = (char**)malloc(size * sizeof(char*));
    checkAllocation(arr);


    for (i = 0; i < size; i++)
    {
        gets(temp);
        len = strlen(temp);
        temp[len] = '\0';
        arr[i] = (char*)malloc((len+1) * sizeof(char));
        checkAllocation(arr[i]);
        strcpy(arr[i], temp);
    }

    *stringSize = size;
    return arr;
}

int stringBinSearch(char** stringArr, int stringSize, char* stringToFind)
{
    return binSearch(stringArr, stringSize, sizeof(char*), stringToFind,compare2Strings);
}

int binSearch(void* Arr, int size, int ElemSize, void* Item, int(*compare)(void*, void*))
{
    int left = 0, right = size - 1, place;
    BOOL found = FALSE;

    while (found == FALSE && left <= right)
    {
        place = (left + right) / 2;

        if (compare(Item, (BYTE*)Arr + place*ElemSize) == 0)
            found = TRUE;

        else if (compare(Item, (BYTE*)Arr + place*ElemSize) < 0)
            right = place - 1;

        else
            left = place + 1;
    }
    return found;
}

int compare2Strings(void* str1, void* str2)
{
    char* elemA, *elemB;

    elemA = (char*)str1;
    elemB = (char*)str2;

    return strcmp(elemA, elemB);
}

3 个答案:

答案 0 :(得分:0)

您好问题是您将字符串数组发送到二进制搜索功能的方式。因为你需要传递一个字符串数组,你的Arr参数必须是void**而不是void*

int binSearch(void** Arr, int size, int ElemSize, void* Item, int(*compare)(void*, void*))

在您的函数中,只要您想从数组中访问字符串,就可以像以下一样访问它:(char*) *(Arr+place*ElemSize)

答案 1 :(得分:0)

int数组进行排序时,传递的值是指向int,拼写为int *的指针。对字符串数组(拼写为char *)进行排序时,传递的值是指向字符串的拼写,拼写为char **。比较器没有用于比较字符串。作为无法模仿的BLUEPIXY said非常简洁的样式 - 您需要修改代码以将传递的void *参数视为char **而不是char *

通过通用排序,这通常是问题的结束。使用二进制搜索,还有另一个问题,你犯了错误。也就是说,被搜索项目的类型需要与数组中的一个条目相同,因此您需要将指针传递给项目,而不仅仅是项目。

因此,添加材料以允许代码以最小的更改进行编译,从gets()更改为fgets()的封面(因为gets() is too dangerous to be used — ever!和使用它的程序会在其中生成警告用于macOS Sierra 10.12.5 - warning: this program uses gets(), which is unsafe.),并打印出输入数据,以便您可以看到它是什么,我最终得到:

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BOOL int
#define TRUE 1
#define FALSE 0

static inline char *sgets(size_t buflen, char *buffer)
{
    char *result = fgets(buffer, buflen, stdin);
    if (result)
        buffer[strcspn(buffer, "\n")] = '\0';
    return result;
}

#define checkAllocation(x) assert((x) != 0)

#define SIZE 100
typedef unsigned char BYTE;

char **getStringArr(int *stringSize);
int stringBinSearch(char **stringArr, int stringSize, char *stringToFind);
int binSearch(void *Arr, int size, int ElemSize, void *Item, int (*compare)(void *, void *));
int compare2Strings(void *str1, void *str2);

int main(void)
{
    char **stringArr, stringToFind[SIZE];
    int stringSize;
    int res;

    stringArr = getStringArr(&stringSize);

    sgets(sizeof(stringToFind), stringToFind);

    printf("Strings: %d\n", stringSize);
    for (int i = 0; i < stringSize; i++)
        printf("[%d] = [%s]\n", i, stringArr[i]);
    printf("Search: [%s]\n", stringToFind);

    res = stringBinSearch(stringArr, stringSize, stringToFind);

    if (res == 1)
        printf("The string %s was found\n", stringToFind);
    else
        printf("The string %s was not found\n", stringToFind);
    return 0;
}

char **getStringArr(int *stringSize)
{
    int i, size, len;
    char **arr;
    char temp[SIZE];

    scanf("%d", &size);
    getchar();

    arr = (char **)malloc(size * sizeof(char *));
    checkAllocation(arr);

    for (i = 0; i < size; i++)
    {
        sgets(sizeof(temp), temp);
        len = strlen(temp);
        temp[len] = '\0';
        arr[i] = (char *)malloc((len + 1) * sizeof(char));
        checkAllocation(arr[i]);
        strcpy(arr[i], temp);
    }

    *stringSize = size;
    return arr;
}

int stringBinSearch(char **stringArr, int stringSize, char *stringToFind)
{
    return binSearch(stringArr, stringSize, sizeof(char *), &stringToFind, compare2Strings);
}

int binSearch(void *Arr, int size, int ElemSize, void *Item, int (*compare)(void *, void *))
{
    int left = 0, right = size - 1, place;
    BOOL found = FALSE;

    while (found == FALSE && left <= right)
    {
        place = (left + right) / 2;

        if (compare(Item, (BYTE *)Arr + place * ElemSize) == 0)
            found = TRUE;

        else if (compare(Item, (BYTE *)Arr + place * ElemSize) < 0)
            right = place - 1;

        else
            left = place + 1;
    }
    return found;
}

int compare2Strings(void *str1, void *str2)
{
    char *elemA = *(char **)str1;
    char *elemB = *(char **)str2;

    return strcmp(elemA, elemB);
}

关键变化是:

  • compare2Strings() - 比较char **值中的数据。
  • stringBinSearch() - 传递stringToFind
  • 的地址

AFAICR,任何其他变化都是化妆品或“基础设施”。

请注意the return type of main() should be int - 您只能在允许使用的Windows上使用void

示例运行1:

数据:

5
Antikythera
albatross
armadillo
pusillanimous
pygmalion
pygmalion

输出:

Strings: 5
[0] = [Antikythera]
[1] = [albatross]
[2] = [armadillo]
[3] = [pusillanimous]
[4] = [pygmalion]
Search: [pygmalion]
The string pygmalion was found

示例运行2:

数据文件:

5
armadillo
pygmalion
Antikythera
pusillanimous
albatross
pygmalion

输出:

Strings: 5
[0] = [armadillo]
[1] = [pygmalion]
[2] = [Antikythera]
[3] = [pusillanimous]
[4] = [albatross]
Search: [pygmalion]
The string pygmalion was not found

两组数据之间的区别在于,在第一种情况下,字符串处于正确的排序顺序 - 成功(可靠)二进制搜索的先决条件 - 在第二种情况下,数据的排序顺序不正确。 (也就是说,我有一个未排序的订单,仍然发现'pygmalion' - 我使用了不同的shuffle来显示结果。但'可靠'的评论适用。)

答案 2 :(得分:-1)

您编写通用二进制搜索的方法是正确的。但是,尝试提前返回会减慢二进制搜索速度。这也意味着你不能使用&#34;小于&#34;的C ++约定。是比较运算符定义。等到左右相等,然后返回。