Console crashes when creating linked list class
Jun 13, 2016 at 6:47am UTC
All the code barring the "remove" function in LinkedL seems to work. When I try to remove a node from the linked list, the console crashes. Can anyone help me solve this problem because no explicit error is thrown which makes me think its a runtime issue as it compiles OK.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
#ifndef NODE_H
#define NODE_H
template <typename T>
class Node
{
private :
T m_Data;
Node<T>* m_Next;
Node<T>* m_Prev;
public :
Node();
Node(const T& m_Data);
~Node();
Node<T>* getNext() const ;
Node<T>* getPrev() const ;
T& getData();
void setNext(Node<T>* n);
void setPrev( Node<T>* p);
void setData(const T& data);
};
template <typename T>
Node<T>::Node()
{
m_Data = T();
m_Next = 0;
m_Prev = 0;
}
template <typename T>
Node<T>::Node(const T& data)
{
m_Data = data;
m_Next = 0;
m_Prev = 0;
}
template <typename T>
Node<T>::~Node()
{
delete m_Next;
delete m_Prev;
m_Next = 0;
m_Prev = 0;
}
template <typename T>
Node<T>* Node<T>::getNext() const {
return m_Next;
}
template <typename T>
Node<T>* Node<T>::getPrev() const {
return m_Prev;
}
template <typename T>
void Node<T>::setNext(Node<T>* n) {
m_Next = n;
}
template <typename T>
void Node<T>::setPrev(Node<T>* p) {
m_Prev = p;
}
template <typename T>
void Node<T>::setData(const T& data) {
m_Data = data;
}
template <typename T>
T& Node<T>::getData() {
return m_Data;
}
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "Node.h"
#include <iostream>
using namespace std;
template <typename T>
class LinkedL
{
public :
LinkedL();
~LinkedL();
bool isEmpty();
void insertFirst(const T& data);
void insertLast(const T& data);
void insertAfter(const T& key, const T& data);
int getSize()const ;
Node<T>* getNode(int i) const ;
bool remove(int i);
T& operator [](int i);
private :
Node<T>* m_First;
Node<T>* m_Last;
int m_Size;
};
template <typename T>
LinkedL<T>::LinkedL()
{
m_First = 0;
m_Last = 0;
m_Size = 0;
}
template <typename T>
LinkedL<T>::~LinkedL()
{
if (m_First != 0) {
Node<T>* current = m_First;
while (current != 0) {
Node<T>* oldNode = current;
current = current->getNext();
delete oldNode;
oldNode = 0;
}
}
}
template <typename T>
bool LinkedL<T>::isEmpty() {
if (m_First == 0) {
return true ;
} return false ;
}
template <typename T>
void LinkedL<T>::insertFirst(const T& data) {
Node<T>* newNode = new Node<T>(data);
if (isEmpty()) {
m_First = newNode;
m_Last = newNode;
}
else {
m_First->setPrev(newNode);
newNode->setNext(m_First);
m_First = newNode;
}
m_Size;
}
template <typename T>
void LinkedL<T>::insertAfter(const T& key, const T& data) {
if (isEmpty()) {
return ;
}
Node<T>* current=0;
for (int i = 0; i <= this ->getSize(); i++) {
if (this ->operator [](i) == key) {
current = this ->getNode(i);
}
}
Node<T>* newNode = new Node<T>(data);
if (current == 0) {
cout << "Node could not be found." << endl;
return ;
}
else if (current==m_Last) {
m_Last = newNode;
newNode->setNext(0);
}
else {
current->getNext()->setPrev(newNode);
newNode->setNext(current->getNext());
}
current->setNext(newNode);
newNode->setPrev(current);
}
template <typename T>
int LinkedL<T>::getSize() const {
return m_Size;
}
template <typename T>
void LinkedL<T>::insertLast(const T& data) {
Node<T>* newNode = new Node<T>(data);
if (isEmpty()) {
m_Last = newNode;
m_First = newNode;
}
else {
m_Last->setNext(newNode);
newNode->setPrev(m_Last);
m_Last = newNode;
}
m_Size++;
}
template <typename T>
T& LinkedL<T>::operator [](int i) {
int counter = 0;
Node<T>* current = m_First;
while (true ) {
if (counter == i) {
return current->getData();
}
current = current->getNext();
counter++;
}
}
template <typename T>
Node<T>* LinkedL<T>::getNode(int i) const {
int counter = 0;
Node<T>* current = m_First;
if (i<0 && i>this ->getSize()) {
return nullptr ;
}
while (true ) {
if (counter == i) {
return current;
}
current = current->getNext();
counter++;
}
}
template <typename T>
bool LinkedL<T>::remove(int i) {
if (isEmpty() || i<0 || i>getSize()) {
cout << "No nodes to remove in specified index" << endl;
return false ;
}
else if (getNode(i - 1) != 0 && getNode(i + 1) != 0) {
getNode(i)->getPrev()->setNext(getNode(i)->getNext());
getNode(i)->getNext()->setPrev(getNode(i)->getPrev());
delete getNode(i);
return true ;
}
else if (i==0) { //remove first element
getNode(i + 1)->setPrev(0);
m_First = getNode(i + 1);
delete getNode(i);
return true ;
}
else {//remove last element
getNode(i - 1)->setNext(0);
m_First = getNode(i - 1);
delete getNode(i);
return true ;
}
}
#endif // !LINKEDLIST_H
#include <iostream>
#include "LinkedL.h"
using std::cout;
using std::endl;
int main() {
LinkedL<int > list;
list.insertFirst(31);
list.insertLast(23);
list.insertAfter(23, 67);
list.insertAfter(23, 45);
list.remove(1);
cout << list[0] <<endl;
system("PAUSE" );
}
Jun 13, 2016 at 8:17am UTC
The problem in the remove(...) function is the use of getNode(i)
.
The point is that getNode(i)
searches an existing node. As soon as you remove the node from the list (line 243) it cannot not be found and the wrong node (line 245) will be deleted.
Jun 13, 2016 at 10:01am UTC
ahhhh i get it. thanks. could you suggest a solution?
I was thinking of this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
bool LinkedL<T>::remove(int i) {
Node<T>* prev = getNode(i - 1);
Node<T>* next = getNode(i + 1);
if (isEmpty() || i<0 || i>getSize()) {
cout << "No nodes to remove in specified index" << endl;
return false ;
}
else if (prev != 0 && next != 0) {
delete getNode(i);
prev->setNext(next);
next->setPrev(prev);
return true ;
}
But this doesnt work either
I jsut want to see if I can make a solution with my current functions
Last edited on Jun 13, 2016 at 10:03am UTC
Jun 13, 2016 at 10:14am UTC
The next problem is this:
1 2 3 4 5 6 7 8 9
template <typename T>
Node<T>::~Node()
{
delete m_Next;
delete m_Prev;
m_Next = 0;
m_Prev = 0;
}
Once you delete a single node you delete the whole list recursively.
Jun 13, 2016 at 2:37pm UTC
Ok that does make sense. It's because it literally keeps on deleting the next pointers to nodes.
I think I have a good idea on how to execute the remove method as you can apparently set the getNode(i) equal to a node ptr variable and deleting the node ptr variable will delete the shared memory as well.
But what should i do with the destructor? Like I would need to delete the node and free memory but then deleting the nodes deletes all the next/prev elements.
Jun 13, 2016 at 4:52pm UTC
I'm looking to approach it like in this document:
http://faculty.cs.niu.edu/~mcmahon/CS241/Notes/doubly_linked.html
But I'm wondering how the dtor of node would look like because as you said it would recursively delete the whole list.
I solved the problem like this:
1 2 3 4 5 6 7 8 9 10 11 12
Node<T>* iNode = getNode(i);
if (isEmpty() || i<0 || i>getSize()) {
cout << "No nodes to remove in specified index" << endl;
return false ;
}
else if (getNode(i-1) != 0 && getNode(i+1) != 0) {
getNode(i - 1)->setNext(getNode(i + 1));
getNode(i + 1)->setPrev(getNode(i - 1));
iNode->setNext(T());
iNode->setPrev(T());
delete iNode;
but I have a feeling this isnt a good solution as the delete should be able to do all the work.
Jun 14, 2016 at 7:04am UTC
But I'm wondering how the dtor of node would look like because as you said it would recursively delete the whole list.
It doesn't make sense to have a destructor for node at all. You could make
Node
a private class of
LinkedL
because it is not used anywhere else.
I would suggest that you remove the public setter/getter of
Node
and make the member variables public because otherwise you have just overhead without gain.
Further i would suggest that you use getNode(...) only once at the beginning. The rest can be done with Prev/Next.
Topic archived. No new replies allowed.