C++ 创建链接列表,使每个节点指向另一个链接列表

C++ 创建链接列表,使每个节点指向另一个链接列表,c++,linked-list,C++,Linked List,嘿,伙计们,我的代码应该创建一个学生的链接列表,对于每个学生,它必须为该学生创建一个分数的链接列表。我真的不知道我的两个链表是否设置正确,因为当我试图遍历链表时,不会打印分数 struct Grade{ float score; }; struct GradeNode{ Grade grade; GradeNode *next_gnode; }; struct StudentNode { string name; GradeNode *ghead;

嘿,伙计们,我的代码应该创建一个学生的链接列表,对于每个学生,它必须为该学生创建一个分数的链接列表。我真的不知道我的两个链表是否设置正确,因为当我试图遍历链表时,不会打印分数

 struct Grade{
     float score;
 };

struct GradeNode{
    Grade grade;
    GradeNode *next_gnode;
};

struct StudentNode {
   string name;
   GradeNode *ghead;
   StudentNode *next_snode;
};

StudentNode* head; //head of student linked list
下面的函数从一个文件中获取输入,并创建一个节点,该节点的值与指向等级链接列表的指针一起,首先设置为null

void buildStudentList(string n){

StudentNode *newNode{ new StudentNode}; //initialize new Student node
StudentNode *curr; //to traverse thru Student lIst

//initialize student node
newNode->name = n;
newNode->next_snode = nullptr;

//have HEAD of THIS student's grades set to null, since there are no grades present for this student at this moment
newNode->ghead = nullptr;

//if student list is empty
if(!head){

    //make this student node the head of the list
    head = newNode;
}
else{

    //else add it to the end of the list

    curr = head;

    //traverse to the end of the list
    while(curr->next_snode){
        curr= curr->next_snode;
    }

    //make grades for this student
    buildGradeList(newNode->ghead, newNode->name);

    //assign new node to the end of the list
    curr->next_snode = newNode;

}
};
建立成绩表功能

//parameter is Grade Head, where we will attach a grade link list to it
void buildGradeList(GradeNode *head, string n){

//NOTE: head is HEAD OF GRADE LIST

bool quit = false;
int x;

while (!quit) {

    cout<<"ENTER GRADE FOR "<<n<< ": (0 to quit)"<<endl;
    cin>>x;
    cout<<endl;

    if(x==0){
        //exit while loop and return      //when one presses 0, they go to the next student on the list!!!
        quit=true;
    }
    else{
        //append this value to head
        appendGrades(head, x);
    }
}

//return to prev function
return;
}

希望各位能提供意见

最容易实现的解决方案是将buildGradeList和appendGrades函数的签名中的GradeNode*head更改为GradeNode*&head。这会起作用,但我不建议你使用它,因为它没有抓住你锻炼的重点

你的代码在我看来基本上是正确的,我还没有运行它,所以我不能确定,除了一个问题:当你把等级列表的头传递给这两个函数时,你是按值传递的。这意味着一个副本是由头部制作的,你所有的更改都将被复制到副本上,这意味着它们不会生效,你学生的成绩节点*Ghead实际上不会指向任何东西

根据您在这里掌握的最正确的代码,以及我的经验,大多数程序员都在努力处理指针和链表,我认为您理解按值传递某个对象与传递某个对象的指针/引用的概念。然而,为了能够使用指针,您必须理解指针本身只是一个地址,即一个值。因此,当您将指针传递到函数中时,您可以修改它所指向的对象的值,并且调用者将看到该更改,但是您对指针本身所做的任何更改都将在函数结束时丢失,因为这些更改是对地址副本进行的,这意味着您无权访问原始地址,因此无法更改原始地址

这都意味着,当向函数传递指针时,不能更改它指向的位置。但解决办法很简单

当您想更改函数中int变量的值并让调用者看到更改时,可以将该整数的地址以int*的形式传递给函数。因此,如果您想更改函数中“int*”变量的值,而不是它所指向的值,而是指针本身的值,您可以将该指针的地址以int**的形式传递给函数

在您的情况下,这意味着您必须将我提到的两个函数的签名更改为:

void buildGradeList(GradeNode **head, string n);
void appendGrades(GradeNode **head, int s);
当然,您还必须对appendGrade的主体进行轻微修改:

这将是正确的,这将是有效的,它将是正确的,在最初的问题和您的解决方案的精神

<>我在顶部建议的解决方案也可以工作,除了添加AND和引用之外没有其他更改,或者更确切地说,函数签名的LValk引用,因为这正是C++中引用的含义。引用是一个指针,它不需要特殊的语法来使用no*来取消引用或获取某物的地址。这意味着使用引用更方便,但它们无法完成使用指针所做的许多事情,例如,必须找到链表末尾的循环不可能使用引用以这种形式写入

但我想提出更好的建议。这两个占据成绩列表首位的函数也可能会更改该列表。因此,我建议他们不要接受指向列表头的指针或指向列表头的指针的引用,而是始终可以返回指向列表头的指针。这意味着它们有时返回一个新的头指针,有时返回传递给它们的同一个指针,但它们自己不会更改实际的头指针;他们返回他们认为应该是头的指针,并让呼叫他们的人来决定

您需要进行的更改如下所示:

// First, change how we call buildGradeList inside buildStudentList:
newNode->ghead = buildGradeList(newNode->ghead, newNode->name);

// then, change the signature for buildGradeList:
GradeNode * buildGradeList (GradeNode * head, string n) {

// then, when you are calling appendGrades, store the value it returns in "head":
head = appendGrades(head, x);

// appendGrades will return the "head" (sometimes new, sometimes the same old one)
GradeNode * appendGrades (GradeNode *head, int s){

// just add this to the end of the appendGrades function:
return head;

就这样。您还可以更改buildStudentList函数以遵循此设计,并始终返回学生链接列表的标题,有时是新的,有时是旧的。我相信这会更好、更有用,特别是在您稍后将遇到的更复杂的问题/任务中。

实现的最简单解决方案是在buildGradeList和appendGrades函数的签名中将GradeNode*head更改为GradeNode*&head。这会起作用,但我不建议你使用它,因为它没有抓住你锻炼的重点

你的代码在我看来基本上是正确的,我还没有运行它,所以我不能确定,除了一个问题:当你把等级列表的头传递给这两个函数时,你是按值传递的。这意味着一个副本是由头部制作的,您的所有更改都将被复制到副本中,这意味着它们不会生效,并且您的st 学生的GradeNode*gheads永远不会指向任何东西

根据您在这里掌握的最正确的代码,以及我的经验,大多数程序员都在努力处理指针和链表,我认为您理解按值传递某个对象与传递某个对象的指针/引用的概念。然而,为了能够使用指针,您必须理解指针本身只是一个地址,即一个值。因此,当您将指针传递到函数中时,您可以修改它所指向的对象的值,并且调用者将看到该更改,但是您对指针本身所做的任何更改都将在函数结束时丢失,因为这些更改是对地址副本进行的,这意味着您无权访问原始地址,因此无法更改原始地址

这都意味着,当向函数传递指针时,不能更改它指向的位置。但解决办法很简单

当您想更改函数中int变量的值并让调用者看到更改时,可以将该整数的地址以int*的形式传递给函数。因此,如果您想更改函数中“int*”变量的值,而不是它所指向的值,而是指针本身的值,您可以将该指针的地址以int**的形式传递给函数

在您的情况下,这意味着您必须将我提到的两个函数的签名更改为:

void buildGradeList(GradeNode **head, string n);
void appendGrades(GradeNode **head, int s);
当然,您还必须对appendGrade的主体进行轻微修改:

这将是正确的,这将是有效的,它将是正确的,在最初的问题和您的解决方案的精神

<>我在顶部建议的解决方案也可以工作,除了添加AND和引用之外没有其他更改,或者更确切地说,函数签名的LValk引用,因为这正是C++中引用的含义。引用是一个指针,它不需要特殊的语法来使用no*来取消引用或获取某物的地址。这意味着使用引用更方便,但它们无法完成使用指针所做的许多事情,例如,必须找到链表末尾的循环不可能使用引用以这种形式写入

但我想提出更好的建议。这两个占据成绩列表首位的函数也可能会更改该列表。因此,我建议他们不要接受指向列表头的指针或指向列表头的指针的引用,而是始终可以返回指向列表头的指针。这意味着它们有时返回一个新的头指针,有时返回传递给它们的同一个指针,但它们自己不会更改实际的头指针;他们返回他们认为应该是头的指针,并让呼叫他们的人来决定

您需要进行的更改如下所示:

// First, change how we call buildGradeList inside buildStudentList:
newNode->ghead = buildGradeList(newNode->ghead, newNode->name);

// then, change the signature for buildGradeList:
GradeNode * buildGradeList (GradeNode * head, string n) {

// then, when you are calling appendGrades, store the value it returns in "head":
head = appendGrades(head, x);

// appendGrades will return the "head" (sometimes new, sometimes the same old one)
GradeNode * appendGrades (GradeNode *head, int s){

// just add this to the end of the appendGrades function:
return head;

就这样。您还可以更改buildStudentList函数以遵循此设计,并始终返回学生链接列表的标题,有时是新的,有时是旧的。我相信这会更好、更有用,特别是在以后遇到更复杂的问题/任务时。

StudentNode有名称,为什么grade Node没有等级?似乎有一个单独的等级类使它变得比需要的更复杂,或者至少在同一代码中有两种不同的方法。建议:概括链表及其节点。模板在这里可能会有所帮助。这A将列表逻辑与包含结构的逻辑分离,学生不知道包含它的LinkedList甚至存在,可以集中精力表示学生的单一职责,B允许学生包含LinkedList成员,从而消除GradeNode类和大量几乎重复的代码。遗漏了一点:你可以用一些简单的东西来测试链表的实现,比如int,确保它在添加学生和成绩的复杂因素之前工作。@Kingsley我最终会为每个学生添加更多的值,并将它们存储在成绩中struct@user4581301谢谢你的建议!将研究使用模板StudentNode有名称,为什么grade Node没有等级?似乎有一个单独的等级类使它变得比需要的更复杂,或者至少在同一代码中有两种不同的方法。建议:概括链表及其节点。模板在这里可能会有所帮助。这A将列表逻辑与包含结构的逻辑分离,学生不知道包含它的LinkedList甚至存在,可以集中精力表示学生的单一职责,B允许学生包含LinkedList成员,从而消除GradeNode类和大量几乎重复的代码。遗漏了一点:您可以使用诸如int之类的简单方法测试链表实现,确保
在增加学生和成绩的复杂性之前,它是有效的。@Kingsley我最终将为每个学生增加更多的价值,并将其存储在年级中struct@user4581301谢谢你的建议!将研究使用templatesWow,我希望OP能够理解这一点。传递指针和期望指针的更改在函数外部可见是一个非常常见的问题。我想知道你是否应该写一些版本作为一个样本答案。我同意这是一个非常普遍的问题,而且有很好的理由。但我不知道什么是样本答案。你能提供一个指针吗@哇,谢谢你的解释!这很有道理。我会按照你的建议,试着让grade函数返回指向头部的指针。再次感谢,这是一个巨大的帮助@MiltonPauta,这里有两个教训:首先是指针指向指针类型和值的机制,每个程序员都应该学习并熟悉它。第二个想法是更新值的函数可以返回新值,而不是就地进行更新。这两种方法都适用范围很广,但它们彼此完全独立。哇,我希望OP能理解这一点。传递指针和期望指针的更改在函数外部可见是一个非常常见的问题。我想知道你是否应该写一些版本作为一个样本答案。我同意这是一个非常普遍的问题,而且有很好的理由。但我不知道什么是样本答案。你能提供一个指针吗@哇,谢谢你的解释!这很有道理。我会按照你的建议,试着让grade函数返回指向头部的指针。再次感谢,这是一个巨大的帮助@MiltonPauta,这里有两个教训:首先是指针指向指针类型和值的机制,每个程序员都应该学习并熟悉它。第二个想法是更新值的函数可以返回新值,而不是就地进行更新。两者都适用范围很广,但它们彼此完全独立。