Delete last node from single-linked list - c++

I have to write a method that's going to delete the last node from the List. Do you guys have any ideas on how I should approach this?

If you have a single-linked list, you have no choice but to iterate through the entire list to the last node, maintaining a pointer to the previous node so you can reset its next field when freeing the last node:
if (head)
{
node *curNode = head;
node *prevNode = NULL;
while (curNode->next)
{
prevNode = curNode;
curNode = curNode->next;
}
if (prevNode) prevNode->next = NULL;
delete curNode;
}
If you were using a double-linked list instead, this would be easier, as you can keep a pointer to the last node in the list and just operate on it directly:
if (head == tail)
{
delete head;
head = tail = NULL;
}
else if (tail)
{
node *curNode = tail;
tail = curNode->previous;
tail->next = NULL;
delete curNode;
}
Of course, if you are really using C++ then you should be using the STL's std::list (double-linked) or std::forward_list (single-linked) containers instead, which handle these details for you.

To delete the last element on a list all you need to do is maintain two separate nodes. Initially one should point to the head of the list and the other should point to the second element on the list. You should do something like the following :
if(head == NULL)
return 0;
else if(head->next == NULL){
Node *temp = head;
delete temp;
head = NULL;
}
else{
Node *one = head;
Node *two = head->next;
while(two->next != NULL){
two = two->next;
one = one->next;
}
one->next = NULL;
delete two;
}

Related

Inserting at the end in doubly linked list

**following is my linked list code...
its not working for some reason. Can someone help me out here?
void insertAtTheEnd(node *&head, int data){
node *newNode= new node(data);
newNode->data=data;
node *temp=head;
while(temp!=NULL){
temp=temp->next;
}
temp->next=newNode;
newNode->next=NULL;
newNode->prev=temp->next;
}
As you have it coded, temp is guaranteed to be NULL when your while loop exits. Hence, temp->next=NULL will crash.
When you probe for a position in the list, you typically need to keep "previous" variable to point to the item before the one you are iterating with.
node* temp = head->next;
node* previous = head;
while (temp)
{
previous = temp;
temp = temp->next;
}
// when the while loop returns, `previous` is the last element in the list
previous->next = newNode;
newNode->prev = previous;
newNode->next = nullptr;
Another case you missing in your code. When head is NULL (empty list), you need to update head to be your newNode
// empty list - return the new node as head
if (head == nullptr)
{
newNode->next = nullptr;
newNode->prev = nullptr;
head = newNode;
return;
}

What is the best way to reject duplicates in a sorted doubly linked list

I am trying to make a sorted doubly linked list that doesn't insert duplicates, but I am having trouble finding a way to do this. I looked at posts on how to remove duplicates, but no posts on preventing duplicate insertions.
Here is the code I have to insert and sort without rejecting duplicates. The parameter, dataIn takes values from a predefined Student object list in main (Student s = {{gpa, name}, ..., {gpa, name}}:
void StudentList::insertNode(Student dataIn)
{
ListNode *newNode; // A new node pointer
ListNode *pCur; // To traverse the list
// Allocate a new node and store num there.
newNode = new ListNode;
newNode->stu = dataIn;
newNode->forw = NULL;
newNode->back = NULL;
//Check if there is node in list
if(head ->forw == NULL && head->back == NULL){
head->forw = newNode;
newNode->back = head;
newNode->forw = head;
head->back = newNode;
}
else{
// Initialize pointers
pCur = head->forw;
// Find location: skip all nodes whose name is less than dataIn's name
while (pCur != head && pCur->stu.name < dataIn.name)
{
pCur = pCur->forw;
}
// Insert the new node between pPre and pCur
ListNode *pPre = pCur->back; // The previous node
newNode->back = pPre;
newNode->forw = pCur;
pCur->back = newNode;
pPre->forw = newNode;
}
// Update the counter
count++;
}
Does anyone know a way for rejecting duplicates without deleting? Thanks everyone!
What is the best way to reject duplicates in a sorted doubly linked list?
I suggest delaying the creation of the new ListNode until you know that the new node isn't a duplicate.
Assuming that the ListNode looks like this
struct ListNode {
Student stu;
ListNode *back;
ListNode *forw;
};
and that you have a head and tail ListNode* that is set to nullptr when the StudentList is empty, then the insertNode function could look like this:
bool StudentList::insertNode(const Student& dataIn) { // return true if node is inserted
ListNode* prev = nullptr;
ListNode* pCur = head;
// search for a good insertion spot
for(; pCur; prev = pCur, pCur = pCur->forw) {
if(dataIn.name == pCur->stu.name) return false; // equal, reject
if(dataIn.name < pCur->stu.name) break; // found a good spot before pCur
}
// delayed creation until here:
ListNode* newNode = new ListNode{dataIn, prev, pCur};
// linking
if(prev) prev->forw = newNode;
else head = newNode;
if(pCur) pCur->back = newNode;
else tail = newNode; // comment this line out if you don't have a "tail"
++count;
return true; // node inserted
}

Why does destructor run into unallocated memory?

I have a singly-linked, circular linked list and am writing a destructor to delete all the nodes. The destructor first severs the head from the rest of the lest to prevent infinite circulation and then I loop through the list and delete all the nodes, eventually, the loop comes back to the head and deletes it as well. In the program I check to make sure that the pointer to the nodes is not NULL and I ran the debugger and it shows that it is NULL at a point which should end the loop, but instead the loop continues and runs into un-allocated memory. Here is my code:
node<T> *cur = head;
node<T> *nxt = head->next;
if (nxt) cur->next = nullptr;
cur = nxt;
// walk through the list and delete nodes
while (cur) {
cur = cur->next;
delete cur;
}
EDIT: Changed code to
node<T> *cur = head;
node<T> *nxt = head->next;
if (nxt) cur->next = nullptr;
cur = nxt;
// walk through the list and delete nodes
while (cur) {
nxt = cur->next;
delete cur;
cur = nxt;
}
EDIT 2: Changed code once more to handle edge cases, same problem still occurs.
if (head == NULL) return;
else if (head->next == head) delete head;
else {
node<T> *cur = head;
node<T> *nxt = head->next;
cur->next = nullptr;
cur = nxt;
while(cur) {
nxt = cur -> next;
delete cur;
cur = nxt;
}
}
It has nothing to do with the severing, your code to walk the list while deleting elements would be just as faulty in a non-circular list. You advance the pointer then delete what it points to (the next item).
You need to delete the current item (but, of course, you also need to have extracted its next field before that point because, once deleted, all content becomes undefined), something like:
while (cur != nullptr) {
node<T> *toDelete = cur;
cur = cur->next;
delete toDelete;
}
In terms of a full solution to what you need, the algorithm should be:
def delCircList(head):
# Ignore empty list.
if head == null:
return
# Special for one-element list.
if head.next == head:
free head
return
# Sever link and set start point.
curr = head.next
head.next = null
# Use normal deletion algorithm.
while curr != null:
toDelete = curr
curr = curr.next
free toDelete

Copy constructor for Linked List

I am having problem with a copy constructor for my Linked List class.
Function works properly but visual studio debugger has a "lag" so I can assume that something bad happens inside that function.
I cannot catch an error, and I don't know what is wrong in my logic.
Here's the code:
Linked_List::Linked_List(const Linked_List & obj)
: head(nullptr)
{
Node * currrentNode = obj.head;
Node * lastNode = nullptr;
while (currrentNode != nullptr)
{
Node * newNode = new Node;
newNode->character = currrentNode->character;
if (head != nullptr)
{
head = newNode;
lastNode = head;
}
else
{
lastNode->next = newNode;
lastNode = newNode;
}
currrentNode = currrentNode->next;
}
}
That code is inserting new nodes in the wrong direction. You are looping through the source list from front-to-back (as you should be), but you are trying to insert nodes into the target list in back-to-front order. But you are never assigning head at all, and you access lastNode before it has been assigned to point at a node. And worse, even if you were assigning the head and lastNode correctly, you are not updating each new node to point at the previous head node as its next node when you replace the current head with the new node. So your target list will still be malformed and leak memory.
The code should be inserting new nodes in front-to-back order instead:
Linked_List::Linked_List(const Linked_List & obj)
: head(nullptr)
{
Node * currentNode = obj.head;
Node * lastNode = nullptr;
while (currentNode)
{
Node * newNode = new Node;
newNode->character = currentNode->character;
if (lastNode)
lastNode->next = newNode;
else
head = newNode;
lastNode = newNode;
currentNode = currentNode->next;
}
}
Which can be simplified to this:
Linked_List::Linked_List(const Linked_List & obj)
: head(nullptr)
{
Node * currentNode = obj.head;
Node ** newNode = &head;
while (currentNode)
{
*newNode = new Node;
(*newNode)->character = currentNode->character;
newNode = &(newNode->next);
currentNode = currentNode->next;
}
}

Why wont my Insert function for a list make new nodes?

Hello My problem with this code is on my 2nd else loop; i never enter it and therefore i never make new nodes for my list. can anyone help me see what i am missing?
bool List::Insert(int data)
{
Node* P = new Node;
if(P==NULL)
{
return false;
}
else
{
P ->info = data;
P ->next = NULL;
if(Head == NULL)
{
Head = P;
}
else
{
Node* lastNode;
for(lastNode = Head; lastNode ->next != NULL; lastNode = lastNode ->next)
{
lastNode ->next = P;
}
}
return true;
}
}
This:
Node* lastNode;
for(lastNode = Head; lastNode ->next != NULL; lastNode = lastNode ->next)
{
lastNode ->next = P;
}
is dead wrong. It will change the next pointer, for every single node currently in the list, to point to your new node. You need to only change the pointer in the last node:
Node* lastNode = Head;
while (lastNode->next != NULL)
lastNode = lastNode->next;
lastNode->next = P;
You may also, for efficiency, want to maintain a separate Tail pointer (in addition to your Head) so that you can simply replace that whole operation with:
Tail->next = P;
Tail = P;
That way, you won't have to traverse the entire list every time you want to append a new node. Your code then becomes something like (without the traversal, and with updating the tail pointer as well):
// Prepare new node.
Node *P = new Node;
P->info = data;
P->next = NULL;
// If list empty, set head and tail to new node, otherwise
// append it.
if (Head == NULL) {
Head = P;
Tail = P;
} else {
Tail->next = P;
Tail = P;
}
I'll stop short of criticising the fact that your Insert method doesn't actually insert but rather appends. My near-anal-retentive nitpicking nature is unlikely to endear me to you:-)
lastNode ->next = P; // this must go after the for