简体   繁体   English

基数排序链表 - 链接桶

[英]Radix sort a linked list - linking the buckets

I'm trying to implement radix sort on a linked list based on an integer with the code below.我正在尝试使用下面的代码在基于整数的链表上实现基数排序。

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

#define MAX_DIGITS 10  // maximum number of digits in a key

// Structure for a node in the linked list
typedef struct node
{
    int key;  // the key to be sorted
    char value[20];  // the value associated with the key
    struct node *next;  // pointer to the next node in the list
} Node;

// Function prototypes
void radixSort(Node **head);
Node *createNode(int key, const char *value);
Node *append(Node *head, int key, const char *value);
void printList(Node *head);

int main(void)
{
    Node *head = NULL;  // head of the linked list

    // Create a linked list with some random keys and values
    head = append(head, 456, "apple");
    head = append(head, 345, "banana");
    head = append(head, 123, "cherry");
    head = append(head, 789, "date");
    head = append(head, 231, "elderberry");
    head = append(head, 567, "fig");
    head = append(head, 876, "grape");

    // Print the original list
    printf("Original list:\n");
    printList(head);

    // Sort the list using radix sort
    radixSort(&head);

    // Print the sorted list
    printf("Sorted list:\n");
    printList(head);

    return 0;
}

// Function to sort the linked list using radix sort
void radixSort(Node **head)
{
    Node *bucket[10];  // array of buckets
    Node *curr;  // pointer to the current node
    Node *tail[10];  // array of tails for each bucket
    int i, j, k;
    int factor;  // factor to sort on
    int digits[MAX_DIGITS];  // array to store the digits of the keys

    // Initialize the buckets and tails
    for (i = 0; i < 10; i++)
    {
        bucket[i] = NULL;
        tail[i] = NULL;
    }

    // Find the maximum number of digits in the keys
    int maxDigits = 0;
    curr = *head;
    while (curr != NULL)
    {
        int key = curr->key;
        int numDigits = 0;
        while (key > 0)
        {
            numDigits++;
            key /= 10;
        }
        if (numDigits > maxDigits)
        {
            maxDigits = numDigits;
        }
        curr = curr->next;
    }

    // Loop through each digit, starting with the least significant digit
    for (factor = 1; maxDigits > 0; factor *= 10, maxDigits--)
    {
        // Extract the digits of the keys
        curr = *head;
        while (curr != NULL)
        {
            digits[curr->key / factor % 10]++;
            curr = curr->next;
        }

        // Cumulative sum of the digits
        for (i = 1; i < 10; i++)
        {
            digits[i] += digits[i - 1];
        }

        // Sort the nodes into the appropriate buckets
        curr = *head;
        while (curr != NULL)
        {
            int digit = curr->key / factor % 10;
            if (bucket[digit] == NULL)
            {
                bucket[digit] = curr;
                tail[digit] = curr;
            }
            else
            {
                tail[digit]->next = curr;
                tail[digit] = curr;
            }
            curr = curr->next;
        }

        // Rebuild the list in sorted order
        *head = NULL;
        for (i = 9; i >= 0; i--)
        {
            //printf("%dA\n",i);
            if (bucket[i] != NULL)
            {
                //printf("%dB\n",i);
                if (*head == NULL)
                {
                    *head = bucket[i];
                   // printf("%dC\n",i);
                }
                else
                {
                    //printf("%dD\n",i);
                    tail[9 - i]->next = bucket[i];
                    //printf("%dF\n",i);
                }

               // tail[9 - i] = tail[i];
            }
            else{
               // printf("%dE\n",i);
            }
    //printf("here\n");
        }
    }
}

// Function to create a new node with the given key and value
Node *createNode(int key, const char *value)
{
    Node *node = (Node*) malloc(sizeof(Node));
    node->key = key;
    strcpy(node->value, value);
    node->next = NULL;
    return node;
}

// Function to append a new node with the given key and value to the end of the list
Node *append(Node *head, int key, const char *value)
{
    Node *newNode = createNode(key, value);
    Node *curr = head;
    if (head == NULL)
    {
        return newNode;
    }
    while (curr->next != NULL)
    {
        curr = curr->next;
    }
    curr->next = newNode;
    return head;
}

// Function to print the linked list
void printList(Node *head)
{
    Node *curr = head;
    while (curr != NULL)
    {
        printf("(%d, %s) ", curr->key, curr->value);
        curr = curr->next;
    }
    printf("\n");
}

The segmentation fault occurs when tail[9 - i]->next = bucket[i];tail[9 - i]->next = bucket[i];时发生段错误is executed.被执行。

I added printf statements (turned them into comment blocks) to trace where the error is.我添加了printf语句(将它们变成注释块)来跟踪错误所在。 Can someone please help me figure out a way to get this to work?有人可以帮我想办法让它工作吗?

There are a few issues:有几个问题:

  • tail[9 - i]->next = bucket[i]; sets the wrong pointer.设置错误的指针。 There is no reason why it should be 9 - i .没有理由应该是9 - i It could even be that tail[9 - i] is NULL. tail[9 - i]甚至可能是 NULL。 So this leads to indefined behaviour.所以这会导致不确定的行为。 Instead you should keep track of what the current tail node is in the list that is being built.相反,您应该跟踪正在构建的列表中的当前节点。 You could use curr for that purpose.您可以为此目的使用curr Let it start (before the loop) with curr = NULL and then when you find a non-null bucket, end that process by setting curr = tail[i] .让它从curr = NULL开始(在循环之前),然后当您找到一个非空桶时,通过设置curr = tail[i]结束该过程。 When a bucket is found when the *head is no longer NULL , make the link with curr->next = bucket[i] .*head不再为NULL时找到桶时,使用curr->next = bucket[i]建立链接。

  • The new list is not terminated with a NULL pointer.新列表未以NULL指针终止。 When the above point is implemented, continue after the loop with curr->next = NULL .实现上述点后,在curr->next = NULL循环后继续。

  • In the next iteration of the factor loop, both digits and buckets need to be reset.factor循环的下一次迭代中, digitsbuckets都需要重置。 You could do this with a loop or with memset .您可以使用循环或使用memset来执行此操作。

Here is the corrected factor loop code -- comments indicate where corrections were made:这是更正后的factor循环代码——注释指出了更正的地方:

    for (factor = 1; maxDigits > 0; factor *= 10, maxDigits--)
    {
        memset(digits, 0, sizeof(digits)); // reset!
        memset(bucket, 0, sizeof(bucket)); // reset!
        
        curr = *head;
        while (curr != NULL)
        {
            digits[curr->key / factor % 10]++;
            curr = curr->next;
        }
        
        for (i = 1; i < 10; i++)
        {
            digits[i] += digits[i - 1];
        }

        curr = *head;
        while (curr != NULL)
        {
            int digit = curr->key / factor % 10;
            if (bucket[digit] == NULL)
            {
                bucket[digit] = curr;
                tail[digit] = curr;
            }
            else
            {
                tail[digit]->next = curr;
                tail[digit] = curr;
            }
            curr = curr->next;
        }

        *head = NULL;
        curr = NULL; // <-- track the current tail of the newly built list
        for (i = 9; i >= 0; i--)
        {
            if (bucket[i] != NULL)
            {
                if (*head == NULL)
                {
                    *head = bucket[i];
                }
                else
                {
                    curr->next = bucket[i]; // Append bucket after the current tail
                }
                curr = tail[i]; // The tail is now at the end of this bucket
            }
        }
        curr->next = NULL; // Terminate the list properly
    }

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

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