【问题标题】:C++ Linked List Sorting, Splitting, and Printing issueC++ 链表排序、拆分和打印问题
【发布时间】:2025-04-20 18:45:02
【问题描述】:

大家好,本周我的实验室任务是让我学习链表。实验提示如下:

  1. 编写一个程序,创建一个至少包含 20 个元素的正向链表,其中每个元素包含一个 0 到 99 之间的随机整数。打印该列表。

  2. 编写函数“returnMiddleList”,一次性找到链表的中间元素。打印该元素的整数值以及该元素相对于头部的位置(从零开始)(其中头部=0,头部指向的元素=1,前一个指向的元素=2等)。

  3. 在中间元素处将列表分成两半,以创建两个完全独立的、大小几乎相等 (+/- 1) 的链表并打印这两个列表。修改“returnMiddleList”函数来完成此操作,返回第二个链表的头部并将指向该头部的元素的链接设置为空。然后打印两个列表元素中存储的整数的两个和。

  4. 将两个列表从最小到最大排序并打印出来(在此步骤打印是可选的,具体取决于所采用的排序方法)。然后结合这两个列表,同时再次从最小到最大排序并打印出新列表。 (提示:在对前两个未排序的列表进行排序和组合之前,您可以进一步细分列表并按一到两个元素列表的比例对它们进行排序。这种排序叫什么?)

我有 #1 和 #2 工作,但 #3 和 #4 是问题开始的地方。当我将链接列表分成两个列表并打印出单个列表时,我的第一个链接列表打印出 9 个数字,而它应该打印出 10(第 10 个数字不知何故消失了?),但是当我对第一个列表求和时在那之后,消失的数字被添加到总和中!我不知道它为什么会消失,这是一个问题。另一个问题是在第二个列表中,随机“0”被添加到列表中,其中一个数字丢失了。我的最后一个问题是关于#4,因为我使用的合并算法似乎不起作用(我在对它们进行排序时将列表合并在一起,但我没有使用递归排序,因为我们还没有学会这一点)。任何输入和帮助将不胜感激!谢谢!

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;

struct nodeType {
    int data;
    nodeType *link;
};

void populateList(nodeType *head) {
//  srand(time(NULL));
    nodeType *temp;
    nodeType *current = head;

    for (int i = 0; i < 20; i++) {
        temp = new nodeType;

        current->data = rand() % 100;

        current->link = temp;

        current = temp;
    }

    temp->link = NULL;
}

void print(nodeType *head) {
    int i = 1;

    while (head->link != NULL) {
        cout << "#" << i++ << ": " << head->data << endl;

        head = head->link;
    }
}

nodeType* returnMiddleList(nodeType *head) {
    nodeType *p1 = head, *p2 = head;
    int count = 0;
    int middle = 1;

    while (p1->link->link != NULL) {
        p1 = p1->link;

        count++;

        if (count % 2 == 0) {
            p2 = p2->link;
            middle++;
        }

    }

    cout << "Middle #" << middle << ": " << p2->data << endl;

    p1 = p2->link;
    p2->link = NULL;

    return p1;
}

void add(nodeType *head) {
    int sum = 0;

    while (head != NULL) {
        sum = sum + head->data;
        head = head->link;
    }

    cout << sum << endl;
}

void sort(nodeType *head) {
    nodeType *temp = head;

    while (temp != NULL) {
        nodeType *temp2 = temp;

        while (temp2 != NULL) {
            if (temp->data > temp2->data) {
                int temp3;

                temp3 = temp->data;
                temp->data = temp2->data;
                temp2->data = temp3;
            }

            temp2 = temp2->link;
        }

        temp = temp->link;
    }
}

nodeType* merge(nodeType* head1, nodeType* head2) {
    nodeType *head3 = new nodeType, *current1 = head1, *current2 = head2;

    while (current1 != NULL || current2 != NULL) {
        if (current1 == NULL) {
            while (current2 != NULL) {
                //logic
                current2 = current2->link; //dumps list 2
                head3->data = current2->data;
            }
            break;
        }
        if (current2 == NULL) {
            while (current1 != NULL) {
                //Logic
                current1 = current1->link; //dumps list 1
                head3->data = current1->data;
            }
            break;
        }

        if (current1->data < current2->data) {
            //logic
            current1 = current1->link; //increments list 1
            head3->data = current1->data;

        } else {
            //logic
            current2 = current2->link; //increments list 2
            head3->data = current2->data;

        }

    }

    return head3;
}

int main() {
    nodeType *head = new nodeType, *head2, *head3;

    populateList(head);

    print(head);
    cout << endl;

    head2 = returnMiddleList(head);

    cout << endl << "List #1 Sum: ";
    add(head);

    cout << endl << "List #2 Sum: ";
    add(head2);

    sort(head);
    cout << endl << "List #1 Sorted" << endl;
    print(head);

    sort(head2);
    cout << endl << "List #2 Sorted" << endl;
    print(head2);

    head3 = merge(head, head2);
    print(head3);
}

【问题讨论】:

  • 我认为是时候学习使用调试器了。
  • 在论坛求助之前,我一直使用它直到感到困惑。
  • 除了调试之外,命名是个好主意。名称操作。命名数据。
  • @Twigler 调试器有什么令人困惑的地方?你单步执行你的代码,观察变量,当程序偏离你写在纸上的计划时,你就发现了问题。至少,打印程序中战略点的变量值。
  • @PaulMcKenzie 我已经尝试过所有这些,但我无法解决我的问题...... :(

标签: c++ sorting split linked-list printf


【解决方案1】:

对于#3,您不需要计数。代码还应该在尝试检查 p1->link 之前检查 head == NULL,p1 == NULL,并且应该在尝试检查 p1->link->link 之前检查 p1->link == NULL。添加这些检查后,为了消除计数,只需将 p1 一次推进两个:p1 = p1->link->link,同时将 p2 一次推进一个:p2 = p2->link。一旦使用 p1->link 或 p1->link->link 到达列表的末尾,然后将 p2 视为指向列表前半部分的最后一个节点的指针,并按照给定的说明进行拆分列表。

对于#4,递归地将列表拆分为子列表的方法通常称为divide and conquer algorithm(wiki 链接)。这种方法用于自上而下的合并排序,虽然还有其他方法更适合(更快)使用链表实现合并排序,但我觉得讲师可能希望您遵循给定的提示。

【讨论】: