简体   繁体   English

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

[英]Segmentation fault while implementing chaining in hash table after collisions occur

I am trying to implement chaining (collision resolution technique in hash table). 我正在尝试实现链接(哈希表中的冲突解决技术)。 My program works fine for most of the test cases. 我的程序对于大多数测试用例都可以正常工作。

Here is my program (it's quite big, but I know where it is failing. So you can skip this part if you want.): 这是我的程序(它很大,但是我知道它在哪里失败。因此,如果需要,您可以跳过此部分。):

#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("\nTEMP = %d", temp);
        if (key == temp->data)
            res = temp;
        printf("\ntemp->data=%d\n", temp->data);
        temp = temp->next;
    }
    return res;
}

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

int main()
{
    int n;
    printf("\nEnter elements to be stored\n");
    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("\nEnter the elements in array\n");
    for (i = 0; i < n; ++i)
    {
        scanf("%d", &d);
        int hashedValue = hashFunction(d);
        hashTable[hashedValue] = insertAtBeginning(hashTable, hashedValue, d);
    }

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

    if (res == NULL)
    {
        printf("\nNot found\n");
    }
    else
    {
        printf("\n%d is found\n", 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)

The program gives SIGSEGV for this test case: 该程序为该测试用例提供了SIGSEGV

Enter elements to be stored 输入要存储的元素

5

Enter the elements in array 输入数组中的元素

21 32 565 784 445 21 32 565 784 445

Enter the element you want to search for 输入您要搜索的元素

565 565

TEMP = 35383520 温度= 35383520

temp->data=445 TEMP->数据= 445

TEMP = 35383456 温度= 35383456

temp->data=565 TEMP->数据= 565

Segmentation fault (core dumped) 分段故障(核心已转储)

After debugging I found that it's throwing seg fault at line number 56, ie: 调试后,我发现它在第56行抛出了段错误,即:

if (key == temp->data)

This line is written in this code snippet: 此行在以下代码段中编写:

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

As you can see in the failing test above that, the while loop is executing 3 times (it was supposed to be executed only twice, because the temp should point to null for the third time). 正如您在上面的失败测试中所看到的那样,while循环执行了3次(它应该只执行两次,因为temp第三次指向null)。 And while it is executing 3rd time, it's throwing segfault at the line if (key == temp->data) . 而且,当它第三次执行时,它会在if (key == temp->data)的行上抛出段错误。

It means that temp is not NULL , and it even doesn't has data field. 这意味着temp不是NULL ,甚至没有data字段。 So there might be the problem in the insertion (ie while inserting the next field of the newNode might not be made NULL , but I am properly taking care of that thing.) If there would be the problem in insertion then my code should fail of other test cases too. 因此,插入时可能会出现问题(即,在插入newNode的下一个字段时可能不会设为NULL ,但我已妥善处理了该事情。)如果在插入时出现问题,则我的代码应该失败其他测试用例。 But the code is just failing for the specified test case above. 但是对于上面指定的测试用例,代码只是失败了。

For example, the code passes this test case: 例如,代码通过了此测试用例:

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

Enter elements to be stored 输入要存储的元素

7 7

Enter the elements in array 输入数组中的元素

21 32 565 784 445 655 84 21 32 565 784 445 655 84

Enter the element you want to search for 输入您要搜索的元素

565 565

TEMP = 8063248 温度= 8063248

temp->data=655 TEMP->数据= 655

TEMP = 8063216 温度= 8063216

temp->data=445 TEMP->数据= 445

TEMP = 8063152 温度= 8063152

temp->data=565 TEMP->数据= 565

565 is found 找到565

I am just unable to figure it out, why does it fail the mentioned test case. 我只是无法弄清楚,为什么它不能通过提到的测试用例。

The problem with your code in many places, is that you don't ensure that when indexing into hashTable that you remain within the bounds that you allocate initially. 代码在许多地方存在的问题是,您无法确保在索引hashTable时仍保持在最初分配的范围内。

In your example, the number 565 would generate a hashedValue of 5. You've only allocated 5 elements in hashTable which covers you for the range of 0 to 4 though. 在您的示例中,数字565会生成5的hashedValue 。您仅在hashTable分配了5个元素, hashTable该元素覆盖了0到4的范围。 Inserting into hashTable[5] enters the realm of undefined behaviour and your code crashes. 插入hashTable[5]将进入未定义行为的领域,并且您的代码将崩溃。 You don't get the same problem when you enter in 7 numbers because all 7 numbers generate hashedValue s that are within the range 0 to 6. 当您输入7个数字时,您不会遇到相同的问题,因为所有7个数字都会生成在0到6范围内的hashedValue

Since your hashFunction will only return numbers between 0 and 9, you could either declare a new variable that tracks the size of hashTable and expands it as numbers are entered or alternatively pre-allocate it for the maximum size. 由于您的hashFunction将仅返回0到9之间的数字,因此您可以声明一个新变量以跟踪hashTable的大小,并在输入数字时对其进行扩展,或者预分配其最大大小。

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

In the long term the other option would make more sense as it will adapt if you ever change hashFunction . 从长远来看,另一个选项会更有意义,因为如果您更改hashFunction ,它将可以适应。

You problem is here: you do not correctly initialize the hash table. 您的问题在这里:您没有正确初始化哈希表。 You wrote: 你写了:

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

Since your hashtable has 10 buckets, it should be i < 10. 由于您的哈希表有10个存储桶,因此它应为i <10。

When n == 5, hashTable[5] is not initialzed and has garbage. 当n == 5时,hashTable [5]未初始化并且具有垃圾。 When 545 gets hashed, it gets that garbage as it's next pointer, not NULL. 当对545进行哈希处理时,它将作为下一个指针(而不是NULL)得到该垃圾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM