【问题标题】:Linked list inserting with two constraints带有两个约束的链表插入
【发布时间】:2018-08-19 04:35:57
【问题描述】:

尝试按字母顺序将学生插入链接列表。学生有名字和年龄。它们按名称排序,如果名称相同,则按年龄排序。

我可以正确地获得名称部分,但年龄有点棘手。分解的部分是第一个 if 语句。当一个新学生与列表中的第一个人同名时,他们必须按年龄排序,但是当我尝试使用该代码时,它会给我一个分段错误。其余代码可以工作。
这是code

Student* insert(Student* student, Student* list)
{
Student* current;

if (list == NULL || (precedes(student->name, list->name) > 0) || strcmp(student->name, list->name) == 0){    
    if (strcmp(list->name, student->name) == 0) {  // goes wrong here i think
        if (student->age < list->age) {
            student->next = list;
            list = student;
        } else {
            student->next = list->next;
            list->next = student;
        }
    } else {
        student->next = list;
        list = student;
    }
} else {
    current = list;
    while(current->next != NULL && (precedes(current->next->name, student->name) > 0)) {
        current= current->next;
    }
    if (current->next != NULL && strcmp(current->next->name, student->name) == 0) {
        if (current->next->age > student->age){
            student->next = current->next;
            current->next = student;
        } else {
            student->next = current->next->next;
            current->next->next = student;
        }
    } else {
        student->next = current->next;
        current->next = student;
    }

}
return list;
}

【问题讨论】:

    标签: c linked-list insert


    【解决方案1】:

    你做的比它需要的要困难得多。

    您有一个明显的情况,即取消引用空指针是确定的,因此确保未定义的行为也是如此。在您的代码中:

    if (list == NULL || (precedes(student->name, list->name) > 0) || strcmp(student->name, list->name) == 0){    
        if (strcmp(list->name, student->name) == 0) {  // goes wrong here i think
    

    如果由于 list == NULL 为真而进入该 if 块,您将立即取消引用该空指针以访问其 nameage 成员。随之而来的是未定义的行为,而您实际上是幸运,您的程序崩溃了(可能会更糟;它可能会成功并让您相信您没有错误)。


    实用比较功能

    这项任务只是因为两个Student 对象的比较可能是两阶段而不是一个阶段而变得复杂。所以做两件事:

    • 编写一个比较函数,该函数可以得出较小-相等-较大条件的特定标准。
    • 在需要比较两个 Student 结构的任何地方使用该函数。

    这样的比较函数如下所示:

    int cmp_Student(const Student *lhs, const Student *rhs)
    {
        int cmp = strcmp(lhs->name, rhs->name);
        if (cmp == 0)
            cmp = (lhs->age < rhs->age) ? -1 : rhs->age < lhs->age;
        return cmp;
    }
    

    lhs 引用“小于”rhsStudent 时,这将返回&lt; 0,当lhs 等于rhs 时返回零,当lhs 是“时返回&gt; 0”大于“大于rhs

    使用它,您可以编写一个简单的指针到指针遍历算法,遍历列表中的指针以寻找适当的插入点,然后使用指针到指针来实现这一点。这也消除了list 为 NULL 时对特殊大小写的需要,因为您真的不在乎。

    Student *insert(Student *student, Student *list)
    {
        Student **pp = &list;
        while (*pp && cmp_Student(student, *pp) < 0)
            pp = &(*pp)->next;
    
        student->next = *pp;
        *pp = student;
    
        return list;
    }
    

    即使您不使用insert 方法,您仍然可以将cmp_Student 用于您自己的算法。无论如何,值得仔细阅读以上内容以了解它是如何工作的,而调试器是一种很好的方法。

    如果您坚持现有的实现,显然您需要修复该空指针取消引用代码路径,因为这显然是错误的。

    【讨论】:

    • 感谢您提供如此详尽的答复。我刚刚开始使用 C 进行编码,本周才开始使用指针和结构,因此这些信息非常有用。我使用了您在先验函数中同时具有两个约束的想法,这很有帮助。最终没有使用指针指针,因为还没有被介绍给那些。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多