【问题标题】:How do I sort a doubly-linked list in ascending order?如何按升序对双向链表进行排序?
【发布时间】:2021-02-02 05:39:19
【问题描述】:

我正在尝试在 C 编程语言中对双向链表执行插入排序功能。当我在一个双向链表上运行这个函数的代码时 13749 我得到一个排序的输出。但是,当我在 53749 的双向链表上运行此代码时,我得到一个空白输出(是的仍然编译和运行)。

我无法弄清楚为什么当第一个节点的值大于第二个节点时它返回空白输出。我猜这与我的 if 语句有关?

void insertion_sort_increasing(struct List *list)
{
    struct Node *current_node = list->head; //initialize current_node
    struct Node *tempA;
    struct Node *tempB;
    struct Node *tempC;
    struct Node *tempD;

    if (current_node == NULL) {
        printf("Empty List.");
    } else {
        current_node = current_node->next;
        while (current_node != NULL) { //iterates doubly linked list
            if (current_node->prev->StudentID > current_node->StudentID) {
                tempA = current_node; //(3 in this case)
                tempB = current_node->prev->prev; //(NULL in this case)
                tempC = tempA->next->prev;
                tempD = tempB->next;

                tempA->next->prev = tempA->prev; // 5<--7
                tempB->next->prev = tempC;       // 3<--5
                tempB->next = tempA->prev->next; // NULL-->3
                tempA->prev->next = tempA->next; // 5-->7
                tempA->next = tempD;             // 3-->5
                tempA->prev = tempD->prev;       // NULL<--3
                if (tempB == NULL) {
                    list->head = tempB->next;    // 3 = head
                }
            }
            current_node = current_node->next;
        }
    }
}

【问题讨论】:

  • 请发帖minimal reproducible example 并选择一种语言。适合 C++ 的东西不适合 C,反之亦然。
  • 请详细说明并解释返回空白是什么意思?你是如何测试代码的?请同时添加该代码。
  • 顺便说一句:我认为这不是插入排序。那里有大量节点指针,但我认为我没有看到输出列表。
  • 我会注意到,不可能只用一个循环对一个非平凡的未排序列表进行排序。您需要做的是从输入列表中弹出项目,并将它们插入到输出列表中的适当位置。因此,您有一个用于弹出每个节点的外循环,以及一个遍历输出循环的内循环(最好将其放在 SortedInsert() 函数中)以找到它刚刚从输入列表中弹出的节点的正确位置。
  • 这是学习如何使用调试器的好时机。或者在你的代码中插入一些printf()s。此外,jwdonahue 的回答是很好的建议。

标签: c doubly-linked-list


【解决方案1】:

您的代码中存在多个问题:

  • 您对列表执行单次扫描,交换无序的相邻节点。此循环不处理节点应向左移动多个位置的情况。
  • 如果tempB 为空,即:如果应该交换列表的两个初始节点,则代码会崩溃。
  • 如果第一个节点发生变化,list-&gt;head 应该更新。
  • 临时变量名称混淆,尤其是tempC等于tempA,初始顺序不是tempA -> tempB -> tempC -> tempD
  • 对于插入排序,您应该将当前节点移动到目前已排序的节点中的位置,然后跳到下一个节点,直到到达列表的末尾。

这是修改后的版本:

void insertion_sort_increasing(struct List *list)
{
    struct Node *current_node = list->head;

    while (current_node != NULL) {
        struct Node *next = current_node->next;
        while (current_node->prev && current_node->prev->StudentID > current_node->StudentID) {
            // swap current_node and its predecessor (tempC and tempB)
            struct Node *tempA = current_node->prev->prev;
            struct Node *tempB = current_node->prev;
            struct Node *tempC = current_node;
            struct Node *tempD = current_node->next;

            if (tempA) {
                tempA->next = tempC;
            } else {
                list->head = tempC;
            }
            tempC->prev = tempA;
            tempC->next = tempB;
            tempB->prev = tempC;
            tempB->next = tempD;
            if (tempD) {
                tempD->prev = tempB;
            } else {
                list->tail = tempB;
            }
        }
        current_node = next;
    }
}

【讨论】:

    【解决方案2】:

    您需要学会在代码中分离关注点。插入排序接受输入列表或数组并返回输出列表或数组。因此,首先,您需要一个接受List** 并返回void 的函数,或者接受List* 并返回List* 的函数。从逻辑上讲,您需要正确地做三件事,1)遍历输入列表,2)从输入列表中删除一个节点而不破坏 1、3)在排序顺序的正确位置插入输出列表。这相当于三个功能。

    List *InsertionSort(List * pList) {...}
    List *SortedInsert(List *pList, List *pNode) {...}
    List *Remove(List *pNode) {...}
    

    InsertionSort 只是循环它的输入,调用Remove,不会丢失头或尾指针的轨迹,这取决于你在列表中移动的方式,然后用它的节点调用SortedInsert刚刚从 pList 的头部或尾部删除。 SortedInsert 然后遍历pList 寻找插入pNode 的正确位置,然后返回列表的新头部,可能只是pNode

    一次只考虑一项操作更容易,您编写的代码将更简单,更易于理解和调试。事实上,您可以先测试SortedInsert,以确保它正常工作,然后测试Remove,然后再转到InsertionSort。您需要学习如何使用调试器并使自己熟悉单步执行代码和检查变量的状态。第四个函数PrintList 可能也在这里订购。

    我不会写一大堆代码,也不会真正明确地说明算法细节,因为你可以通过 SO 或 Google 搜索得到,这似乎是一项显而易见的家庭作业。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-03
      • 1970-01-01
      • 2011-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多