【问题标题】:C++ Doubly Linked List with Pointers: Object of class isn't constructed properly [closed]带指针的 C++ 双向链表:类的对象构造不正确[关闭]
【发布时间】:2018-11-03 00:23:24
【问题描述】:

我正在用 C++ 实现循环链​​表。

我想在测试期间使用我的静态函数进行打印;但是,stdout 没有被执行(没有任何东西打印到控制台)。我一直在试图找出崩溃的原因,但我被卡住了。

请注意,我已经超出了循环链表的规范,并实现了一个名为tail 的变量,它将地址存储到头部左侧的变量中。这在当时似乎是一种简化问题的方法。

主要功能:

#include <iostream>
int main() {
    std::cout << "Testing linked_list class:" << endl;
    linked_list::linked_list_test();
}

linked_list.h:

#include <vector>
#include <iostream>

using namespace std;

class linked_list {
private:
    struct Node {
        int value;
        Node* next;
        Node* previous;

        Node() {
            value = 0;
            next = nullptr;
            previous = nullptr;
        }

        Node(int n) {
            value = n;
            next = nullptr;
            previous = nullptr;
        }

        Node(int n, Node* p) {
            value = n;
            next = p;
        }
    };

    int size;
    Node* head;
    Node* tail;

    Node* get_node(int index) {
        if(index < 0 or index >= size) {
            throw out_of_range("IndexError: Index out of range");
        }

        Node* current = head;
        for (int i=0; i<index; i++) {
            current = current->next;
        }
        return current;
    }

public:
    linked_list();
    linked_list(vector<int> initial);
    ~linked_list();

    int operator [](int i);

    int length();

    int pop(int index);
    int pop();

    void insert(int value, int index);
    void remove(int index);
    void append(int value);
    void print();

    static void linked_list_test();
};

#endif

linked_list.cpp:

#include "linked_list.h"


linked_list::linked_list() {
    size = 0;
    head = nullptr;
    tail = nullptr;
}

linked_list::~linked_list() {
    Node* current;
    Node* next;

    current = head;

    while (current != nullptr) {
        next = current->next;
        delete current;
        current = next;
    }
}

int linked_list::operator[] (int index) {
    return get_node(index) -> value;
}

linked_list::linked_list(vector<int> initial) {
    size = 0;
    head = nullptr;
    tail = nullptr;

    for (int n: initial) {
        append(n);
    }
}

int linked_list::length() {
    return size;
}

void linked_list::append(int value) {
    if(head == nullptr && tail == nullptr) {
        head = new Node(value);
        tail = head;
        size++;
        return;
    }

    tail -> next = new Node(value);
    tail = tail ->next;
    size++;
}

void linked_list::remove(int index) {
    if(index == 0) {
        Node* current = head -> next;
        delete head;
        head = current;

    }
    else if(index == size -1) {
        Node* current = tail -> next;
        delete tail;
        tail = current;
    }

    Node* current;
    Node* previous = new Node;
    current = head;
    for (int i=0; i<index; i++) {
        previous = current;
        current = current->next;
    }
    previous->next = current->next;

    size--;
}

int linked_list::pop(int index) {
    if(index <= size) {
        int n = get_node(index) -> value;
        remove(index);

        return n;
    }

    else if(index > size) {
        throw out_of_range("IndexError");
    }
}

int linked_list::pop() {
    return pop(size - 1);
}

void linked_list::insert(int val, int index) {
    Node* previous = get_node(index-1);
    Node* next = previous -> next;
    previous ->next = new Node(val, next);
}

void linked_list::print() {
    Node* current = head;
    cout << "[";
    while (current->next != nullptr) {
        cout << current->value;
        cout << ", ";
        current = current->next;
    }
    cout << current->value << "]" << endl;
}

void linked_list::linked_list_test() {
    linked_list dynamic_list;
    dynamic_list.print();
    dynamic_list.append(9);
    dynamic_list.append(2);

    cout <<"appended 9 and 2"<< endl;
    dynamic_list.print();

    cout << "Instantiating an array with elements 3, 4, and 5" << endl;
    linked_list t_array({3, 4, 5});
    t_array.print();

    cout << "Inserting 6 to index 1 on the new array" << endl;
    t_array.insert(1, 6);
    t_array.print();

    cout << "Using pop() to remove last element in list" << endl;
    t_array.print();
}

【问题讨论】:

  • “像 stackoverflow 上的许多其他人一样,我也在实现双向链表” - 不幸的是,这可能是真的。但是您是否真的尝试使用一个(例如std::list)来实际编写一个有用的应用程序?
  • 嘿,你的linked_list.h其实就是你的linked_list.cpp
  • 当您说没有任何内容打印到控制台时,您到底是什么意思?附加 9 和 2" ?
  • 旁注:将using namespace std; 放在标头中的文件范围内可能会产生灾难性的后果。只有经过长时间的考虑并有充分的理由才这样做。
  • 我的意思是previous 没有被使用。总是nullptr。取而代之的是,您将get_nodeindex-1 一起使用,这是一个缓慢而痛苦的原因,当您手头应该已经有指向它的指针时要找到前一个节点。这就是@phillipvoyle 在他的编辑中正在修复的内容。

标签: c++ data-structures circular-list


【解决方案1】:

我想我要开始的是你的打印功能,它不能很好地处理列表为空的情况。在这里,我确保当指针current 为空时不使用它。我们可以确定在 while 循环范围内使用它是安全的,因为我已将其限制为 current != nullptr

void linked_list::print() {
    Node* current = head;
    cout << "[";
    bool bFirst = true;
    while (current != nullptr) {  // was current->next
        if (bFirst) {
            bFirst = false;
        } else {
            cout << ", ";
        }
        cout << current->value;
        current = current->next;
    }
    cout << "]" << endl; //no longer referencing current->value here where it's unsafe
}

在插入或删除节点时,您还需要注意保存下一个和前一个指针

void linked_list::append(int value) {
    if(head == nullptr && tail == nullptr) {
        head = new Node(value);
        tail = head;
    } else { 
        tail->next = new Node(value);
        tail->next->previous = tail;
        tail = tail->next;
    }
    size++;
}

void linked_list::remove(int index) {
    Node* current = head;
    for (int i = 0; (i < index) && (current != null) ; i++) {
        current = current->next;
    }
    if (current != null) {
        Node* next = current->next;
        Node* previous = current->previous;

        if (next == null) {
            tail = previous; // no next
        } else {
            next->previous = previous;
        }

        if (previous == null) {
            head = next; //no previous
        } else {
            previous->next = next;
        }
        size --; //only if we found something
    }
}

【讨论】:

  • 我会将您的贡献添加到问题中(给您信用)
  • @CanHicabiTartanoglu 作为为什么打印不起作用的答案,这几乎就是答案。您应该选择它作为答案并开始编写下一个处理 insert 中的错误的问题。
  • @CanHicabiTartanoglu 我猜对于循环链表你可能不需要尾巴?就在前面。我从来没有尝试过实现其中之一。如果它是双重链接的,您仍然需要注意您的头脑和以前的指针,并确保它们在进行更改时不会过时。
  • @CanHicabiTartanoglu 你误解了。我并不是说它是多余的,我是说它在您的实现中未被使用。因为previous 是使双向链表工作的秘诀,所以这是一个奇怪的设计选择。菲利普正在向您展示如何解决这个问题。
  • 关于循环链表,一步一步。首先让常规链表工作,然后担心循环它。您可能会发现绘制图片可以帮助您可视化列表。如果您非常仔细地绘制列表并记下您所做的事情以及您是如何做到的,那么这些笔记可以构成代码的基础。它们还形成了一组很好的期望,以便在调试时进行比较。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-20
相关资源
最近更新 更多