删除 LinkedList 类中的指针

Deleting a pointer in a LinkedList class

本文关键字:指针 LinkedList 删除      更新时间:2023-10-16

我正在尝试在C++中实现我的第一个 LinkedList 类,但在删除指针时遇到问题。

LinkedList.h:

#pragma once
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <iostream>
#include "ListNode.h"

class LinkedList
{
private:
int theSize;
ListNode* head;
ListNode* tail;
public:
LinkedList();
~LinkedList();
LinkedList(const LinkedList&);
const LinkedList& operator=(const LinkedList&);
void push_front(const Line&);
void push_back(const Line&);
void pop_front();
void pop_back();
int const size();
bool const empty();
void insert(const Line&, int);
void remove(int);
void print();
void print(int);
};
#endif //!LINKEDLIST_H

链表的一部分.cpp:

LinkedList::LinkedList() : theSize{ 0 }, head{ nullptr }, tail{ nullptr } {
}

//Destructor: Need to go through entire list and delete one by one
LinkedList::~LinkedList() {
if (!empty()) {
cout << "Destroying List" << endl;
ListNode* currPtr{ head };
ListNode* tempPtr{ nullptr };
while (currPtr != nullptr) {
tempPtr = currPtr;
currPtr = currPtr->next;
delete tempPtr;
}
}
}

//LinkedList::LinkedList(const LinkedList& ll) {
//
//}
//const LinkedList& LinkedList:: operator=(const LinkedList& ll) {
//
//}
void LinkedList::push_front(const Line& l) {
ListNode* ln = new ListNode(l);
if (empty())
head = tail = ln;
else {
ln->setNext(*head);
(*head).setPrev(*ln);
head = ln;
}
theSize++;
}
void LinkedList::push_back(const Line& l) {
ListNode* ln = new ListNode(l);
//If List is empty, head and tail will point to one node
if (empty())
head = tail = ln;
else {
(*tail).setNext(*ln);
(*ln).setPrev(*tail);
tail = ln;
}
theSize++;
}
void LinkedList::pop_front() {
if (empty())
return;
else {
ListNode* tempPtr = head;
if (head == tail) //If there is only one Node in the List
head = tail = nullptr;
else            
head = head->next;
delete tempPtr;
}
//theSize--;
}

ListNode.h:

#pragma once
#ifndef LISTNODE_H
#define LISTNODE_H
#include<iostream>
#include"Line.h"
//using namespace::std;
class ListNode
{
friend class LinkedList;
private:
Line data;
ListNode* next;
ListNode* prev;
public:
ListNode();
~ListNode();
ListNode(const Line&);
ListNode(const Line&, ListNode*, ListNode*);
Line& getData();
ListNode& getNext();
ListNode& getPrev();
void setData(const Line&);
void setNext(ListNode&);
void setPrev(ListNode&);
friend ostream& operator<<(ostream&, const ListNode&);
friend istream& operator>>(istream& input, ListNode&);
};

pop_front() 方法只是删除链接列表中的第一个节点:

void LinkedList::pop_front() {
if (empty())
return;
else {
ListNode* tempPtr = head;
if (head == tail) //If there is only one Node in the List
head = tail = nullptr;
else            
head = &((*tempPtr).getNext()); //getNext() returns a Node&
//delete tempPtr;
}
}

在我的主要情况下,我创建了一个链接列表并添加了一些节点,效果很好。pop_front() 方法工作正常,直到我在末尾包含 delete 语句,此时我收到运行时错误。我似乎不明白为什么它不起作用。这是针对双向链表的。

好吧,你的代码令人困惑,但由于这是你的第一个链表,让我帮助你实现。在以后的帖子中,发布您的所有代码,因为我看不到方法返回的内容,而且更多的是猜测,那么没有人可以帮助您。

# include <stdio.h>
# include <iostream>

using namespace std;

struct LinkedListItem
{
LinkedListItem(int c) : content(c), next(nullptr)
{
}
int content;
LinkedListItem * next;
};
struct LinkedList
{
LinkedList() : Start(nullptr), End(nullptr) //initialize it to null, tgis is faster than in body
{}
~LinkedList()
{
//to delete
LinkedListItem * ptrtodelete;
while(Start)
{//while there is something
//archive the current first element
ptrtodelete = Start;

//we move to next item
Start = Start -> next;

delete ptrtodelete;
//i can afford destroying Start (by moving it) because this is destructor
}
//be paranoid
Start = End = nullptr;
}
void AddItem(int i)
{
if(!Start) //or if Start == nullptr
{
Start = new LinkedListItem(i);
End = Start; //both point to the one element
return;
}
LinkedListItem * newelement = new LinkedListItem(i);
End -> next = newelement; //let last item point to this one
End = newelement; //let end point to the last item
}
LinkedListItem * Start; /**< Pointer to first element */
LinkedListItem * End; /**< Pointer to last element */
};

int main()
{
LinkedList l;
l.AddItem(5);
l.AddItem(980);
return 0;
}

现在这正在工作,可能会有所帮助。 您可以稍后考虑将其转换为模板:]

当我编译它并放到瓦尔格林德时,这是输出

user@Horse:~/Desktop/tmp/AAA$valgrind ./a.out
==11699== Memcheck, a memory error detector
==11699== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==11699== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==11699== Command: ./a.out
==11699== 
==11699== 
==11699== HEAP SUMMARY:
==11699==     in use at exit: 0 bytes in 0 blocks
==11699==   total heap usage: 2 allocs, 2 frees, 16 bytes allocated
==11699== 
==11699== All heap blocks were freed -- no leaks are possible
==11699== 
==11699== For counts of detected and suppressed errors, rerun with: -v
==11699== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
user@Horse:~/Desktop/tmp/AAA$

现在让我们看看为什么...?这是如何工作的...?

列表中的每个项目都有一个指向另一个元素的指针。最后一个节点的指针设置为 null,如果列表为空,

Start

变量为空。

现在在

void AddItem(int i)

我必须检查一个特殊情况。如果列表中没有项目。 然后,我创建新项目,并在添加完成后返回。(我会解释

End

后来)

如果一个节点在那里,理论上,我将不得不遍历所有节点直到结束,到达最后一个节点,能够链接那里的新元素。 这将需要我 N 个步骤,假设我们在列表中有 N 个项目。这在最坏的情况下称为复杂性,称为O(n),代表Omikron数学函数。

它只是告诉你:从所有可能发生的情况中,如果我选择最坏的情况,那么 metdos 会带我走 N 步,但这是最大的。很糟糕,对吧? 想象一下,那里有百万件物品...F. 游戏中的示例...

所以我做了什么,我创造了一个

End

变量,指向链表中的最后一个项目。 像这样,我只是将新项目链接到最后一个节点,

End -> next = newelement; //let last item point to this one

并将 End 变量设置为新添加的项目,这是最后一个

End = newelement; //let end point to the last item

现在,现在的复杂性是O(1)。理论上,对于方法中的任何操作,它都是 +1,所以 O(4),但这被称为 O(1)。

现在我还必须删除链表。它可以通过更多方式完成,还有一种方式是优雅的,但我对这个循环没意见。

~LinkedList()

由于我们将不再需要第一个元素的浮桥,我可以开始增加它。因此,虽然 Start 元素不为空,

while(Start)

我们保存指针 - 开始。

ptrtodelete = Start;

让开始指向下一个项目,然后删除我们存档的项目

理论上,可以使用 End 代替 ptrtodelete 来保存一个变量(指针为 4 或 8 个字节)

现在我来问你...这是什么复杂性...?如果你回答了O(n),其中n是项目数,你是对的

最后,你可以在构造函数中看到

LinkedList() : Start(nullptr), End(nullptr)

我在双点后初始化变量。为什么不像这样...?

LinkedList()
{
Start = nullptr; 
End = nullptr;
}

原因是,看看上面的代码:创建了一个新的列表项,代码转到构造函数。

"开始"和"结束"变量设置为随机值。事实就是如此。 然后,我们在正文中将它们更改为 null(4 个操作)。

但是考虑到上面的例子, 将创建一个列表项,并为"开始"和"结束"分配值 nullptr。 这是 2 个操作。

它不会为你节省太多,但拥有庞大的项目,游戏,也许,在百万分配下,它可以节省一些东西。

这是我们在我的教师那里学到的令人难以置信的东西,我喜欢它,因为当我环顾四周时,我在互联网上的任何地方都没有找到它。现在我正在与你们分享:]