【问题标题】:How can I implement a linked list and allow users to choose a specific node to remove with C++?如何实现链表并允许用户选择要使用 C++ 删除的特定节点?
【发布时间】:2018-05-14 20:33:03
【问题描述】:

我花了几乎一整天的时间来尝试这样做,我了解指针和链表的作用,但我不知道如何实际编码它,我发现的只是 Java 和 C 示例无济于事,因为我使用的是 C++。 提前感谢您查看我的代码并帮助我,考虑到我花了多少天的时间为此感到压力和困惑,我真的很感激。到目前为止,我不会撒谎,我的大部分 deleteNode 函数可能都是垃圾。但就像我说过的,我只是迷路了,我什至不知道从哪里开始或如何进步,因为我只了解概念。

这是我的数据文件。

John Doe    80
Jane Smith  70
Bill Jones  50
Pat  Hughes 90
Sam  Sosa   40

这是我的头文件

#include<string>
using namespace std;
class student {
public:
    student();   // constructor method
    void st_fn(string fn);
    string st_fn();
    void st_ln(string ln);
    string st_ln();
    void st_score(float s);
    float st_score();
    string st_pass_or_fail();
    // need a pointer to the next object
    student *nxt_ptr;
protected:   // protected can be inherited
    float m_score;
    string m_ln;
    string m_fn;
    string m_pf_msg;
};
student::student()  //constructor
{
    nxt_ptr = NULL;
    m_score = 0;
}
void student::st_fn(string fn)
{
    m_fn = fn;
}
string student::st_fn()
{
    return m_fn;
}
void student::st_ln(string ln)
{
    m_ln = ln;
}
string student::st_ln()
{
    return m_ln;
}
void student::st_score(float s)
{
    m_score = s;
}
float student::st_score()
{
    return m_score;
}
string student::st_pass_or_fail()
{
    if (m_score >= 60)
        m_pf_msg = "PASSED";
    else
        m_pf_msg = "FAILED";

    return m_pf_msg;
}

这是我的 .cpp 文件。

#include<iostream>
#include<string>
#include<fstream>
#include "Header.h"
using namespace std;
int display_menu()
{
    int option;

    cout << endl << endl;
    cout << "1. Display List" << endl;
    cout << "2. Add a student" << endl;
    cout << "3. Delete first student" << endl;
    cout << "4. Search by Last Name" << endl;
    cout << "5. Exit" << endl;
    cin >> option;

    return option;
}
student * search_last_name(student *h)
{
    student *f = NULL;
    student *t = NULL;
    string s_ln;

    // prompt for last name to search for
    cout << "Enter Last Name of the Student";
    cin >> s_ln;

    if (h != NULL)
    {
        t = h;
        while (t != NULL)
        {
            if (t->st_ln() == s_ln)
                f = t;   // found the last name so save t

            t = t->nxt_ptr;
        }
    }
    else
        cout << "List is empty" << endl;

    return f;

}
void add_student(student *&head)  // h is the head of the list
{
    student *new_st, *r;
    string fn, ln;
    float s;

    cout << "Enter new students first name, last name and score";
    cin >> fn >> ln >> s;

    // instantiate a new node, use new_st
    new_st = new student;
    new_st->st_fn(fn);
    new_st->st_ln(ln);
    new_st->st_score(s);

    if (head == NULL)
        head = new_st;
    else
    {
        // find the last node, use r for this
        // write code
        r = head;
        while (r->nxt_ptr != nullptr)
            r = r->nxt_ptr;

        // add to the back of the list
        // write code
        r->nxt_ptr = new_st;
    } // end of else
} // end of add student
student * delete_front(student * head)
{
    student *t;
    // delete front node
    // check for empty list

    if (head != NULL)
    {
        // delete first node
        t = head;
        head = head->nxt_ptr;
        delete(t);
    }
    else
        cout << "List is empty - nothing to delete" << endl;

    return head;
}
void deleteNode(struct Node *head, struct Node *n)
{
    // When node to be deleted is head node
    if (head == n)
    {
        n = head->next;

        //Remove the link of next node
        head->next = head->next->next;



        return;
    }

    //When not first node, folow the  normal deletion process

    //Find the previous node
    struct Node *prev = head;
    while (prev->next != NULL && prev->next != n)
        prev = prev->next;

    // Check if node really exists in Linked List
    if (prev->next == NULL)
    {
        cout << endl << "Given node is not present in Linked List";
        return;
    }

    //Remove node from linked list should it exist
    prev->next = prev->next->next;


    return;
}

void display_list(student *t)
{
    if (t == NULL)
        cout << "List is Empty!";
    else
    {

        while (t != NULL)
        {
            cout << "******Student******" << endl;
            cout << t->st_ln() << endl;
            cout << t->st_fn() << endl;
            cout << t->st_score() << endl << endl;
            t = t->nxt_ptr;
        }
    }
}
int main()
{
    string ln, fn;
    float s;
    int n;
    ifstream infile;
    student *head = NULL;   //pointer to a student object
    student *cp = NULL;     // pointer to end of the list
    student *new_st = NULL;  // pointer to a new student object
    student *f = NULL;      // pointer to found node

    int option;  // the numbe of menu item the user selects


    infile.open("lab8d.txt");

    while (!infile.eof())
    {
        infile >> fn >> ln >> s;
        //instantiate a student object
        new_st = new student;
        //load the object with data
        new_st->st_fn(fn);
        new_st->st_ln(ln);
        new_st->st_score(s);

        // check for empty list - its a special case
        if (head == NULL)
        {
            head = new_st;
            cp = new_st;
        }
        else   // list is not empty
        {
            cp->nxt_ptr = new_st;
            cp = new_st;
        }

    }  // end of loop

       // loop to give the user some options

    option = display_menu();

    while (option != 5)
    {
        if (option == 1)
            display_list(head);
        else if (option == 2)
            add_student(head);
        else if (option == 3)
            head = delete_front(head);
        else if (option == 4)
        {
            f = search_last_name(head);

            if (f != NULL)
            {
                cout << f->st_fn() << endl;
                cout << f->st_ln() << endl;
                cout << f->st_score() << endl;
                cout << f->st_pass_or_fail() << endl;
            }
            else
                cout << "Name not in the list" << endl;
        }
        else if (option == 6)
        {
            cout << "Enter the number of the node you would like to delete: " << endl;
            cin >> n;

        }

        option = display_menu();

    }


    system("pause");

    return 0;

}

【问题讨论】:

  • 问题是不清楚你删除了什么以及应该保留什么。例如,如果一个头应该被删除,你会调用你的函数 deleteNode(head, head)。但是 head 是指向您的列表的指针。如果你调用这个函数,指向你的列表的指针不会改变,但是头节点会消失。我的意思是这是你程序中的一个基本问题。还有很多其他问题。我建议开始考虑接口
  • 我建议将链表逻辑与所有其他逻辑分开。这使得测试和调试链表变得更加容易。让链表正常工作,然后添加Student,最后添加菜单系统。
  • 注意while (!infile.eof()) 这是一个非常常见的错误。好文章在这里:Why is iostream::eof inside a loop condition considered wrong?
  • 正如安德烈所说,不清楚您要删除什么以及何时删除。您知道如何删除一个节点,因此您需要能够决定是哪个节点并直接执行。那标准是什么?
  • @FeiXiang 是的,但至少他们会编译,并成为 OP 的起点,显然他们正在上一门教授 C'isms 的 C++ 课程。

标签: c++ linked-list


【解决方案1】:

您的函数越简单和独立,它们就越容易测试和调试,并且失败的可能性也就越小。

试试这样的:

学生.h:

#include <string>

class student_list;

class student
{
public:
    student();
    student(const std::string &fn, const std::string &ln, float s, student *nxt = NULL);

    void next(student *s);
    student* next() const;

    void firstName(const std::string &fn);
    std::string firstName() const;

    void lastName(const std::string &ln);
    std::string lastName() const;

    void score(float s);
    float score() const;

    std::string pass_or_fail() const;

    void display(bool showPassOrFail = false) const;

    friend class student_list;

protected:   // protected can be inherited
    student *m_next;
    std::string m_fn;
    std::string m_ln;
    float m_score;
};

学生.cpp:

#include "Student.h"
#include <iostream>

student::student()
    : m_next(NULL), m_score(0)
{
}

student::student(const std::string &fn, const std::string &ln, float s, student *nxt)
    : m_next(nxt), m_fn(fn), m_ln(ln), m_score(s)
{
}

void student::next(student *s)
{
    m_next = s;
}

student* student::next() const
{
    return m_next;
}

void student::firstName(const std::string &fn)
{
    m_fn = fn;
}

std::string student::firstName() const
{
    return m_fn;
}

void student::lastName(const std::string &ln)
{
    m_ln = ln;
}

std::string student::lastName() const
{
    return m_ln;
}

void student::score(float s)
{
    m_score = s;
}

float student::score() const
{
    return m_score;
}

std::string student::pass_or_fail() const
{
    if (m_score >= 60)
        return "PASSED";
    else
        return "FAILED";
}

void student::display(bool showPassOrFail) const
{
    std::cout << lastName() << std::endl;
    std::cout << firstName() << std::endl;
    std::cout << score() << std::endl;

    if (showPassOrFail)
        std::cout << pass_or_fail() << std::endl;
}

StudentList.h:

#include <string>

class student;

class student_list
{
public:
    student_list();
    ~student_list();

    student* search_last_name(const std::string &ln);

    student* insert(const std::string &fn, const std::string &ln, float s, student* after = NULL);

    bool remove(int idx);

    void display() const;

private:
    student *m_head;
};

StudentList.cpp:

student_list::student_list()
    : m_head(NULL)
{
}

student_list::~student_list()
{
    while (m_head)
        remove(0);
}

student* student_list::search_last_name(const std::string &ln)
{
    student *t = m_head;
    while (t)
    {
        if (t->lastName() == ln)
            break;   // found the last name

        t = t->next();
    }

    return t;
}

student* student_list::insert(const std::string &fn, const std::string &ln, float s, student* after)
{
    student **r;

    if (after)
    {
        // add to list after the specified node
        // get pointer to next node
        r = &(after->m_next);
    }
    else
    {
        // add to the back of the list

        // find pointer to last node
        r = &m_head;
        while (*r)
            r = &((*r)->m_next);
    }

    // instantiate a new node
    student *new_st = new student(fn, ln, s);
    if (after)
        new_st->next(*r);

    // add to list
    *r = new_st;

    return new_st;
}

bool student_list::remove(int idx)
{
    // delete a node at index

    // find pointer to node
    student **r = &m_head;
    while ((*r) && (idx-- > 0))
        r = &((*r)->m_next);

    if (*r)
    {
        // delete node
        student *t = *r;
        *r = t->next();
        delete t;
        return true;
    }

    return false;
}

void student_list::display() const
{
    student *t = m_head;
    if (!t)
        std::cout << "List is Empty!" << std::endl;
    else
    {
        do
        {
            std::cout << "******Student******" << std::endl;
            t->display();
            t = t->next();
        }
        while (t);
    }
}

Main.cpp:

#include "Student.h"
#include "StudentList.h"

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <limits>
#include <cstdlib>

int read_number()
{
    int value;

    while (!(std::cin >> value))
    {
        std::cout << "Must be a number, try again: ";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }

    return value;
}

int display_menu()
{
    int option;

    std::cout << std::endl << std::endl;

    std::cout << "1. Display List" << std::endl;
    std::cout << "2. Add a student" << std::endl;
    std::cout << "3. Delete first student" << std::endl;
    std::cout << "4. Search by Last Name" << std::endl;
    std::cout << "5. Delete student by index" << std::endl;
    std::cout << "6. Exit" << std::endl << std::endl;

    std::cout << "Choice: ";

    do
    {
        option = read_number();

        if ((option >= 1) && (option <= 6))
            break;

        std::cout << "Must be 1..6, try again: ";
    }
    while (true);

    return (option != 6) ? option : -1;
}

int main()
{
    student_list students;

    std::ifstream infile("lab8d.txt");
    if (infile.is_open())
    {
        student *cp = NULL;
        std::string ln, fn;
        float s;

        while (infile >> fn >> ln >> s)
            cp = students.insert(fn, ln, s, cp);

        infile.close();
    }

    // loop to give the user some options

    int option;  // the number of menu item the user selects

    while ((option = display_menu()) != -1)
    {
        switch (option)
        {
            case 1:
            {
                students.display();
                break;
            }

            case 2:
            {
                // prompt for student info
                std::string info;
                std::cout << "Enter new student's first name, last name, and score: ";

                std::string ln, fn;
                float s;

                if (std::cin >> fn >> ln >> s)
                    students.insert(fn, ln, s);

                break;
            }

            case 3:
            {
                if (!students.remove(0))
                    std::cout << "List is empty" << std::endl;

                break;
            }

            case 4:
            {
                // prompt for last name to search for
                std::string ln;
                std::cout << "Enter Last Name of the Student: ";

                if (std::cin >> ln)
                {
                    student *f = students.search_last_name(ln);
                    if (f)
                        f->display(true);
                    else
                        std::cout << "Name not found in List" << std::endl;
                }

                break;
            }

            case 5:
            {
                std::cout << "Enter the index of the Student to Delete: " << std::endl;
                int idx = read_number();

                if (!students.remove(idx))
                    std::cout << "Index not found in List" << std::endl;

                break;
            }
        }
    }

    std::system("pause");

    return 0;
}

话虽如此,您确实应该改用std::list 容器,例如:

学生.h:

#include <string>

class student_list;

class student
{
public:
    student();
    student(const std::string &fn, const std::string &ln, float s);

    void firstName(const std::string &fn);
    std::string firstName() const;

    void lastName(const std::string &ln);
    std::string lastName() const;

    void score(float s);
    float score() const;

    std::string pass_or_fail() const;

    void display(bool showPassOrFail = false) const;

    friend class student_list;

protected:   // protected can be inherited
    std::string m_fn;
    std::string m_ln;
    float m_score;
};

学生.cpp:

#include "Student.h"
#include <iostream>

student::student()
    : m_score(0)
{
}

student::student(const std::string &fn, const std::string &ln, float s)
    : m_fn(fn), m_ln(ln), m_score(s)
{
}

void student::firstName(const std::string &fn)
{
    m_fn = fn;
}

std::string student::firstName() const
{
    return m_fn;
}

void student::lastName(const std::string &ln)
{
    m_ln = ln;
}

std::string student::lastName() const
{
    return m_ln;
}

void student::score(float s)
{
    m_score = s;
}

float student::score() const
{
    return m_score;
}

std::string student::pass_or_fail() const
{
    if (m_score >= 60)
        return "PASSED";
    else
        return "FAILED";
}

void student::display(bool showPassOrFail) const
{
    std::cout << lastName() << std::endl;
    std::cout << firstName() << std::endl;
    std::cout << score() << std::endl;

    if (showPassOrFail)
        std::cout << pass_or_fail() << std::endl;
}

Main.cpp:

#include "Student.h"

#include <list>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <limits>
#include <algorithm>
#include <cstdlib>

int read_number()
{
    int value;

    while (!(std::cin >> value))
    {
        std::cout << "Must be a number, try again: ";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }

    return value;
}

int display_menu()
{
    int option;

    std::cout << std::endl << std::endl;

    std::cout << "1. Display List" << std::endl;
    std::cout << "2. Add a student" << std::endl;
    std::cout << "3. Delete first student" << std::endl;
    std::cout << "4. Search by Last Name" << std::endl;
    std::cout << "5. Delete student by index" << std::endl;
    std::cout << "6. Exit" << std::endl << std::endl;

    std::cout << "Choice: ";

    do
    {
        option = read_number();

        if ((option >= 1) && (option <= 6))
            break;

        std::cout << "Must be 1..6, try again: ";
    }
    while (true);

    return (option != 6) ? option : -1;
}

int main()
{
    std::list<student> students;

    std::ifstream infile("lab8d.txt");
    if (infile.is_open())
    {
        std::string ln, fn;
        float s;

        while (infile >> fn >> ln >> s)
            students.push_back(student(fn, ln, s));

        infile.close();
    }

    // loop to give the user some options

    int option;  // the number of menu item the user selects

    while ((option = display_menu()) != -1)
    {
        switch (option)
        {
            case 1:
            {
                if (students.empty())
                    std::cout << "List is Empty!" << std::endl;
                else
                {
                    for(const auto &s : students)
                    {
                        std::cout << "******Student******" << std::endl;
                        s.display();
                    }
                }

                break;
            }

            case 2:
            {
                // prompt for student info
                std::string info;
                std::cout << "Enter new student's first name, last name, and score: ";

                std::string ln, fn;
                float s;

                if (std::cin >> fn >> ln >> s)
                    students.push_back(student(fn, ln, s));

                break;
            }

            case 3:
            {
                if (students.empty())
                    std::cout << "List is empty" << std::endl;
                else
                    students.erase(students.begin());

                break;
            }

            case 4:
            {
                // prompt for last name to search for
                std::string ln;
                std::cout << "Enter Last Name of the Student: ";

                if (std::cin >> ln)
                {
                    auto f = std::find(students.begin(), students.end(),
                        [&](const student &s){ return (s.lastName() == ln); }
                    );
                    if (f != students.end())
                        f->display(true);
                    else
                        std::cout << "Name not found in List" << std::endl;
                }

                break;
            }

            case 5:
            {
                std::cout << "Enter the index of the Student to Delete: " << std::endl;
                int idx = read_number();

                if ((idx < 0) || (idx >= students.size()))
                    std::cout << "Index not found in List" << std::endl;
                else
                    students.erase(std::next(students.begin(), idx));

                break;
            }
        }
    }

    std::system("pause");

    return 0;
}

【讨论】:

    猜你喜欢
    • 2022-01-05
    • 2019-07-07
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    • 2020-02-11
    • 1970-01-01
    • 2019-02-23
    相关资源
    最近更新 更多