【问题标题】:Structure Linked List in C not connected wellC中的结构链表连接不好
【发布时间】:2021-05-26 08:44:25
【问题描述】:

我正在尝试在 C 中创建一个链表,其中每个节点都连接到右侧和左侧。使用 insert_node 函数,我输入了 4 个节点的值:2、3、5、2

如果我写的逻辑正确,插入节点应该已经自动对列表进行排序,使其对齐为:2,2,3,5

如果我检查 print_list 中的中间值,该值会显示为 3,这正是我的预期。但是,一旦我使用临时节点 temp 移动到左侧节点,temp 就会变为 nullptr。

我不明白为什么会这样,因为 print_list 中的临时节点是用列表的中间节点初始化的,而中间节点被分配了一个左节点。

typedef struct ListNode{
    struct ListNode* right;
    struct ListNode* left;
    int value;
} ListNode;
//a linked list that saves the middle node of the list
typedef struct LinkedList{
    ListNode* middle;
    int left_size;
    int right_size;
}LinkedList;

//a function to reduce repeating malloc
ListNode* init_node() {
    return (ListNode*)malloc(sizeof(ListNode*) * 2 + 4);
}
LinkedList* init_list() {
    return (LinkedList*)malloc(sizeof(ListNode*) + sizeof(int) * 2);
}


//function to assign NULL to unassigned pointers in structs 
void nullify_node(ListNode* node) {
    node->left = NULL;
    node->right = NULL;
}
void nullify_list(LinkedList* list) {
    list->middle = NULL;
}

//sorts the list so that the leftmost node has smallest value
void insert_node(LinkedList* list, int value) {

    ListNode* new_node = init_node();
    new_node->value = value;
    nullify_node(new_node);
    printf("initialized new node\n");
    
    //if no node was ever inserted in the list, make the new node be the middle one
    if (list->left_size+list->right_size==0) { 
        list->middle = new_node;
        list->right_size += 1;
    }
    else {
        //make a temporary node to traverse the list
        ListNode* temp =list->middle;
        nullify_node(temp);
        printf("initialized temp\n");
        
        //if given value is smaller or equal to that of the middle node, traverse to the left
        if (value <= list->middle->value) {
            int left_size = list->left_size;
            
            //if no node was ever inserted to the left, make the new node the first left node
            if (left_size == 0) {
                printf("initialized first left");
                list->middle->left=new_node;
                list->left_size += 1;
                
            }
            else {
                //temp->left should be the left node to new node
                //traverse temp until temp->left->value is smaller than value while temp->value is bigger than value
                for (; left_size > 0; left_size--) {
                    if (temp->left) {//only if temp->left exist check temp->left->value
                        //if temp->left->value is bigger than value, hop once more
                        if (value < temp->left->value) {
                            temp = temp->left;
                        }//if it is the same or bigger, stop there.
                        else {
                            break;
                        }
                    }
                }
                //put new node between temp->left and temp
                if (temp->left) {
                    new_node->right = temp;
                    new_node->left = temp->left;
                    temp->left->right = new_node;
                    temp->left = new_node;
                }
                else {//if temp was the leftmost node, make new node be the leftmost node.
                    new_node->right = temp;
                    temp->left = new_node;
                }
                    

                //balance list
                list->left_size += 1;
                if (list->left_size > list->right_size + 1) {
                    list->middle = list->middle->left;
                    list->left_size -= 1;
                    list->right_size += 1;
                }
                        
                
            }
        }//traverse to the right side of the list if given value is bigger than the middle node's value
        else if (value > list->middle->value) {
            int right_size = list->right_size;
            //since middle value is considered as one of the right side's nodes, hop minus 1 time than the right_size
            for (; right_size > 1; right_size--) {
                if (temp->right) {// if temp has a right node, compare temp->right->value with given value
                    //if given value is bigger, move temp to the right
                    if (value > temp->right->value) {
                        temp = temp->right;
                    }
                    else {
                        break;
                    }
                }               
            }
            //if temp wasn't the rightmost node,
            if (temp->right) {
                //insert new node between temp and temp->right
                new_node->left = temp;
                new_node->right = temp->right;
                temp->right->left = new_node;
                temp->right = new_node;
            }
            else {//if temp was the rightmost node, make the new node be the rightmost node
                temp->right = new_node;
                new_node->left = temp;
            }
            //balance list
            list->right_size += 1;
            if (list->right_size > list->left_size + 1) {
                list->middle = list->middle->right;
                list->left_size += 1;
                list->right_size -= 1;
            }
        }
            
    }
}
void print_list(LinkedList*list) {
    //move to leftmost node
    ListNode*temp = list->middle;
    printf("middlevalue:%d", temp->value);
    for (int i = 0; i < list->left_size ; i++) {
        //when input 2, 3, 5, 2, from the second interation temp is nullptr for some reason
        temp = temp->left;
        printf("%dth value:%d",i, temp->value);
    }
    for (int j = 0; j < list->left_size + list->right_size; j++) {
        printf("\t%d", temp->value);
        temp = temp->right;
    }
}

【问题讨论】:

    标签: c algorithm


    【解决方案1】:

    init_node 和 init_list 都假设硬结构包装,而且完全是错误的。这些应该看起来像这样(尽管缺乏错误检查):

    ListNode *init_node(int value) // note argument
    {
        ListNode * p = malloc(sizeof *p);
        p->left = p->right = NULL;
        p->value = value;
        return p;
    }
    
    LinkedList *init_list()
    {
        LinkedList *p = malloc(sizeof *p);
        p->left_size = p->right_size = 0;
        p->middle = NULL;
        return p;
    }
    

    注意添加到init_node 的参数。这允许这样做:

    ListNode* new_node = init_node();
    new_node->value = value;
    nullify_node(new_node);
    

    变成这样:

    ListNode *new_node = init_node(value);
    

    接下来,您显然很难理解指针的工作原理。当你这样做时:

    //make a temporary node to traverse the list
    ListNode *temp = list->middle;
    nullify_node(temp);
    printf("initialized temp\n");
    

    您实际上是在将temp 指向您的list-&gt;middle 指向的相同节点,然后将该节点的左右指针置空。 IE。您只是将左侧或右侧的任何东西泄漏到以太中。更糟糕的是,大小参数(您在整个代码中非常依赖)保持原样,这意味着它们现在正在考虑不再存在的列表微粒(因为您使用该 nullify_node 孤立/泄漏了它们)。

    删除这一行:

    nullify_node(temp);
    

    理想情况下,随着我们新的init_node 实现的出现,只需删除该函数即可。无论如何,它实际上毫无价值。

    最后,print_list。参数应该是 const,并且不应该依赖于 LinkedList 结构 whatsoever 的 size 成员。即

    void print_list(const LinkedList *list)
    {
        //move to leftmost node
        const ListNode *temp = list->middle;
        if (temp)
        {
            while (temp->left)
                temp = temp->left;
        }
    
        while (temp)
        {
            printf("%d ", temp->value);
            temp = temp->right;
        }
    }
    

    【讨论】:

    • 天哪,非常感谢!这对我来说已经足够了。感谢您花时间进行如此明确的解释!我希望你有一个伟大的一年:DD
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-01
    • 2012-11-21
    • 2014-11-29
    • 1970-01-01
    • 2023-04-03
    相关资源
    最近更新 更多