发生冲突后在哈希表中实现链接时出现分段错误

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了发生冲突后在哈希表中实现链接时出现分段错误相关的知识,希望对你有一定的参考价值。

我正在尝试实现链接(哈希表中的冲突解决技术)。我的程序适用于大多数测试用例。

这是我的程序(它很大,但我知道它失败的地方。所以你可以跳过这部分,如果你想。):

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

struct LinkedListNode
{
    int data;
    struct LinkedListNode *next;
};

struct LinkedListNode* getNewNode()
{
    // I don't need to cast the malloc in c
    return malloc(sizeof(struct LinkedListNode));
}

struct LinkedListNode* insertAtBeginning(struct LinkedListNode** hashTable, int index, int data)
{
    struct LinkedListNode* newNode = getNewNode(); // the new node
    newNode->data = data;
    newNode->next = NULL; // for now I can put the next to be null

    // check if the block is containing null or not
    if (hashTable[index] == NULL)
    {
        // now just insert the new element at beginning
        hashTable[index] = newNode;
        return hashTable[index]; // returning the new address of the block
    }

    // if collisions occur
    struct LinkedListNode* blockListAddress = hashTable[index]; // the address pointing to first node of linked list
    newNode->next = blockListAddress; // storing the address of block in the next of the new linkedlist
    hashTable[index] = newNode; // changing the block address to the address of new node (as we have to insert in beginning)
    return hashTable[index];
}

struct LinkedListNode* searchMe(struct LinkedListNode** hashTable, int index, int key)
{
    struct LinkedListNode* res = NULL;
    struct LinkedListNode* temp = hashTable[index];

    if (temp == NULL)
        return NULL;

    // if we just have one element in the block then the while loop below won't get executed
    // because here condition is temp->next which will be null, thus here I have written if condition
    if (hashTable[index] != NULL && hashTable[index]->data == key)
    {
        return hashTable[index];
    }

    // if not null then traverse through linked list
    while (temp != NULL)
    {
        printf("
TEMP = %d", temp);
        if (key == temp->data)
            res = temp;
        printf("
temp->data=%d
", temp->data);
        temp = temp->next;
    }
    return res;
}

int hashFunction(int num)
{
    return num%10;
}

int main()
{
    int n;
    printf("
Enter elements to be stored
");
    scanf("%d", &n);

    // declaring the hashTable of size n (i.e. size of input elements), its gonna have pointers to LinkedListNode
    struct LinkedListNode** hashTable = malloc(n*sizeof(struct LinkedListNode*)); // I have given memory to the table, now I even need to give memory to the elements in the table
    int i;
    for (i = 0; i < n; ++i)
    {
        hashTable[i] = NULL;
    }

    int d;
    printf("
Enter the elements in array
");
    for (i = 0; i < n; ++i)
    {
        scanf("%d", &d);
        int hashedValue = hashFunction(d);
        hashTable[hashedValue] = insertAtBeginning(hashTable, hashedValue, d);
    }

    int key;
    printf("
Enter the element you want to search for
");
    scanf("%d", &key);
    int ind = hashFunction(key);
    struct LinkedListNode* res = searchMe(hashTable, ind, key);

    if (res == NULL)
    {
        printf("
Not found
");
    }
    else
    {
        printf("
%d is found
", res->data);
    }
}


// time complexity in worst case for searching = O(n),
// average case t.c = O(1+alpha), where alpha = n/m
// n <- number of elements in hashtable
// m <- size of hashtable
// so alpha is 1 in this case
// thus average t.c = theta(1)

该程序为此测试用例提供SIGSEGV

输入要存储的元素

5

输入数组中的元素

21 32 565 784 445

输入要搜索的元素

565

TEMP = 35383520

TEMP->数据= 445

TEMP = 35383456

TEMP->数据= 565

分段故障(核心转储)

经过调试后,我发现它在第56行引发了seg故障,即:

if (key == temp->data)

这一行写在以下代码片段中:

while (temp != NULL)
{
    printf("
TEMP = %d", temp);
    if (key == temp->data)
        res = temp;
    printf("
temp->data=%d
", temp->data);
    temp = temp->next;
}

正如您在上面的失败测试中所看到的那样,while循环执行了3次(它应该只执行两次,因为temp应该第三次指向null)。虽然它正在执行第三次,但它在if (key == temp->data)线上抛出了段错误。

这意味着temp不是NULL,它甚至没有data字段。所以在插入时可能存在问题(即插入newNode的下一个字段可能不会被制作为NULL,但我正在妥善处理那个事情。)如果插入时会出现问题,那么我的代码应该失败其他测试用例。但代码只是失败了上面的指定测试用例。

例如,代码通过了这个测试用例:

[aupadhyay @ localhost c] $ ./a.out

输入要存储的元素

7

输入数组中的元素

21 32 565 784 445 655 84

输入要搜索的元素

565

TEMP = 8063248

TEMP->数据= 655

TEMP = 8063216

TEMP->数据= 445

TEMP = 8063152

TEMP->数据= 565

找到565

我只是无法弄明白,为什么它没有提到上述测试用例。

答案

您的代码在许多地方存在的问题是,在索引到hashTable时,您不能确保保持在最初分配的范围内。

在你的例子中,数字565将生成一个5的hashedValue。你只在hashTable中分配了5个元素,它们覆盖了0到4的范围。插入hashTable[5]进入未定义行为的领域,您的代码崩溃。当您输入7个数字时,您不会遇到同样的问题,因为所有7个数字都会生成0到6范围内的hashedValues。

由于你的hashFunction只返回0到9之间的数字,你可以声明一个跟踪hashTable大小的新变量,并在输入数字时将其展开,或者预先分配它以获得最大大小。

struct LinkedListNode** hashTable = malloc(10*sizeof(struct LinkedListNode*)); // I
int i;
for (i = 0; i < 10; ++i)
{
    hashTable[i] = NULL;
}

从长远来看,另一种选择会更有意义,因为如果你改变hashFunction它会适应。

另一答案

您遇到的问题是:您没有正确初始化哈希表。你写了:

int i;
for (i = 0; i < n; ++i)
{
    hashTable[i] = NULL;
}

由于您的哈希表有10个桶,因此它应该是<10。

当n == 5时,hashTable [5]没有初始化并且有垃圾。当545被哈希处理时,它会获得垃圾,因为它是下一个指针,而不是NULL。

以上是关于发生冲突后在哈希表中实现链接时出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章

为啥在访问二级指针时出现分段错误错误? C语言

创建链表时出现神秘的分段错误(添加功能)

返回指针时出现分段错误

在 C++ 中使用链表时出现空指针异常

尝试从方法返回指向对象的指针时出现分段错误

从 C 调用汇编函数时出现分段错误错误