如何在不更改数据的情况下更改以前创建的双向循环链表中 node 的位置?

(First of all, I'm sorry for my bad English, English is not my native language.)

我们在大学参加了"数据 struct "课程的考试.最后一个问题是这样给出的.

查看下面给出的代码.补齐缺失的功能.

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

struct Node
{
    int data;
    struct Node* next;
    struct Node* pre;
};

struct Node* node_create(int data)
{
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
    new_node->data = data;
    new_node->next = NULL;
    new_node->pre = NULL;

    return new_node;
}

void node_add(struct Node** head, struct Node* new_node)
{
    struct Node* list = *head;

    if(*head == NULL)
    {
        new_node->next = new_node;
        new_node->pre = new_node;
        *head = new_node;
    }
    else
    {
        while(list->next != *head)
        {
            list = list->next;
        }

        list->next = new_node;
        (*head)->pre = new_node;

        new_node->next = *head;
        new_node->pre = list;
    }
}

void node_list(struct Node** head)
{
    struct Node* list = *head;

    if(*head == NULL)
    {
        printf("\nEmpty Linked List!\n");
        return;
    }

    do{

        //printf("(%p) %p - %d-> (%p)", list->pre,list,list->data,list->next);
        printf("%d-> ", list->data);
        list = list->next;
    }while(list != *head);
}

void node_delete(struct Node** head, int data)
{
    if(*head == NULL)
    {
        printf("\nEmpty Linked List!\n");
        return;
    }

    struct Node* list = *head;
    struct Node* end = *head;

    if( list->data == data )
    {
        if(list->next == list)
        {
            free(list);
            *head = NULL;
        }
        else
        {
            while(end->next != *head)
            {
                end = end->next;
            }

            *head = list->next;
            end->next = *head;
            (*head)->pre = end;
            free(list);
        }
    }
    else
    {
        while(list->data != data && list->next != *head)
        {
            list = list->next;
        }

        if(list->data != data && list->next == *head)
        {
            printf("No value for delete!\n");
            return;
        }

        (list->pre)->next = list->next;
        (list->next)->pre = list->pre;
        free(list);
    }

    printf("\nDelete of complited!\n");


}

void node_sorting(struct Node** head)
{
    
}




int main()
{
    struct Node* head = NULL;
    struct Node* new_node = NULL;
    int select = 0, data = 0, one = 1;

    while(one == 1)
    {
        printf("\n\nNode Add (1)\n");
        printf("Node List (2)\n");
        printf("Node Delete (3)\n");
        printf("Node Sorting (4)\n");

        printf("\nSelect: ");
        scanf("%d", &select);

        if(select == 1)
        {
            printf("\nData: ");
            scanf("%d", &data);

            new_node = node_create(data);
            node_add(&head, new_node);
        }
        else if(select == 2)
        {
            node_list(&head);
        }
        else if(select == 3)
        {
            printf("\nData to delete: ");
            scanf("%d", &data);

            node_delete(&head, data);
        }
        else if(select == 4)
        {
            node_sorting(&head);
        }

    }

    return 0;
}

考虑到问题很简单,可以用气泡算法解决,我编写了以下代码作为答案.

void node_sorting(struct Node** head)
{
    struct Node* list = *head;
    struct Node* tolist = *head;

    if(*head == NULL)
    {
        printf("\nEmpty Linked List!\n");
        return;
    }

    if((*head)->next == *head)
    {
        printf("A single-element linked list cannot be sorted.");
        return;
    }

    do{

        tolist = list->next;
        list = list->next;

        while(tolist != *head)
        {
            if(list->data > tolist->data)
            {
                int temp = 0;
                temp = tolist->data;
                tolist->data = list->data;
                list->data = temp;
            }
    
            tolist = tolist->next;
        }


    }while(list != *head);

}

然而,当结果公布时,我得知我考试不及格,上面的问题得了0分.

当我与教授这门课的教授交谈时,我得到了以下答案.你写的答案只是一个骗局.如果我在现实生活中使用这个,可能会造成严重的 destruct .永远不要改变数据.改变 node 的位置.

我不明白这是怎么回事.我花了一周的时间研究这个问题,发现了以下资源.

Inserting data in a sorted Circular Linked List

Inserting a element in a singly circular linked list in sorted manner

Insert element into a sorted Circular Double Linked List

这些都不适合对现有的双循环链表进行排序.任何文件或文本,你可以与我分享,适合我的要求将对我很有帮助.非常感谢提前.

推荐答案

其 idea 是更新prenext成员,以便以不同的顺序放置 node .

以下是使用该原则合并排序的实现.它由以下步骤组成:

  1. 判断给定的列表是否只有零个或一个 node :在这种情况下,列表被排序,我们可以返回.如果没有:
  2. 在给定列表中找到中间 node .
  3. 将列表拆分为两个循环列表,以便此 node 成为第二个列表的头部.这意味着大约有pre,next个指针需要更新.
  4. 对两个较小的列表中的每一个执行此算法
  5. 现在,这两个列表已排序:将它们合并为一个已排序的循环列表.

以下是要添加到代码中以使其像那样工作的函数:

struct Node* extract_head(struct Node** head) {
    struct Node *node = *head;
    // Detach node from the list it is in
    node->pre->next = node->next;
    node->next->pre = node->pre;
    // Make next node the new head
    *head = node == node->next ? NULL : node->next;
    // Return the node we have extracted
    return node;
}

struct Node* get_middle_node(struct Node* head) {
    if (!head) return head;
    struct Node *last = head->pre;
    // Walk forward and backwards until the two pointers meet:
    while (head != last) {
        head = head->next; // Forward
        if (head == last) break;
        last = last->pre;  // Backward
    }
    return head;
}

struct Node* merge(struct Node* left, struct Node* right) {
    struct Node *newHead = NULL;
    while (left || right) { // While there are nodes to merge...
        // Move the node with the least value into a new circular list
        node_add(&newHead, extract_head(
            !right || left && left->data < right->data ? &left : &right
        ));
    }
    return newHead;
}

struct Node* split_at(struct Node *head, struct Node *at) {
    struct Node *tail = at->pre;
    at->pre = head->pre;
    head->pre->next = at;
    head->pre = tail;
    tail->next = head;
    // Return the pointer to the second half that was separated
    return at;
}

struct Node* merge_sort(struct Node* head) {
    return !head || head->next == head ? head // One node only? => is sorted
         // Split in two, sort each, and merge:
         : merge(merge_sort(split_at(head, get_middle_node(head))), 
                 merge_sort(head));
}

void node_sorting(struct Node** head)
{
    *head = merge_sort(*head);
}

这不是您的问题,但是您提供的代码有一些奇怪的特殊性.例如,在node_addnode_delete中,有大约while个循环遍历整个列表,只在列表中的最后一个 node 停止.但这最后一个 node 是头 node 的前身,所以您只需查看(*head)->pre就可以找到它!

C++相关问答推荐

如何用C(使用两个s补数算术的32位程序)计算

为什么PLT表中没有push指令?

Malloc(sizeof(char[Length]))是否不正确?

为什么GCC可以调用未定义的函数?

ZED for SDL上的C语言服务器

当execvp在C函数中失败时杀死子进程

将 struct 变量赋给自身(通过指针取消引用)是否定义了行为?

如何在C客户端应用程序的ClientHello消息中添加自定义扩展?

在Linux上使用vscode和lldb调试用Makefile编译的c代码

如何在C中只对字符串(包含数字、单词等)中的数字进行重复操作?

如何在c中使用具有不同变量类型的内存分配?

C程序向服务器发送TCPRST

有没有一种方法可以用C创建保留限定符的函数?

try 查找带有指针的数组的最小值和最大值

当我在34mb的.mp4文件中使用FREAD时,我得到了一个分段错误,我如何解决它?

如何打印循环调度问题的时间表

在我的第一个C语言中观察到的错误';你好世界';程序

如何不断地用C读取文件?

当 n 是我们从用户那里获得的整数时,创建 n 个 struct 参数

与 C 相比,C++ 中无副作用的无限循环的好处是 UB?