Differences between Insert & Delete for singly linked lists with sentinel nodes - singly-linked-list

We were assigned with the task of coding the Insert(L,k) & Delete(L,k) functions for a singly-linked list with a sentinel node. My questions are:
Is it correct or close to the right answer?
assuming what i've done is correct, i'm not
seeing any significant difference from a normal Delete() of a singly
linked list without a sentinel node. Am i correct in that statement?
Description of Insert(L,k):
The function inserts a new node with key == k in the list (if it doesn't already exist).
Description of Delete(L,k):
The function looks for the node whose key == k and if it finds it, it deletes it.
We can assume that the key of each node is unique.
My implementation of Insert:
fun Insert(pointer L,Key k) {
pointer p;
pointer currNode = L; // first element
while(currNode != NULL && currNode->data != k) {
currNode = currNode->next;
}
if(currNode == NULL) { // element doesn't exist
p = newcell(Node); // allocate memory for a new node
p->data = k;
p->next = L;
L = p;
return;
}
else { // element exists
throw error;
}
}
My implementation of Delete:
fun Delete(pointer L, Key k) {
pointer currNode = L; //first element
pointer prev = NULL; // A pointer to the previous node
if(currNode != NULL && currNode->data == k) { // first elemenent has k
L = currNode->next;
free(currNode);
}
// look for the elemenent to delete
while(currNode->next != NULL && currNode->data != k) {
prev = currNode;
currNode = currNode->next;
}
if(currNode->next == NULL) throw error; // element not found
// elemenent found
prev->next = currNode->next;
free(currNode);
}
P.S. Here's how a singly linked list with a sentinel node looks like in our examples

Related

c++ replace values in linked list by changing pointers

Having a problem with linked list. Need to create a method, which will replace data in list, by not creating a new element but by changing pointers. For now I have such method:
void replaceValues(Node* head, int indexOne, int indexTwo)
{
Node* temporaryOne = NULL;
Node* temporaryTwo = NULL;
Node* temp = NULL;
Node* current = head;
int count = 0;
while (current != NULL) {
if (count == indexOne)
{
temporaryOne = current;
}
else if (count == indexTwo)
{
temporaryTwo = current;
}
count++;
current = current->next;
}
current = head;
count = 0;
while (current != NULL) {
if (count == indexOne)
{
head = temporaryTwo;
}
else if (count == indexTwo)
{
head = temporaryOne;
}
count++;
current = current->next;
}
}
I am sure, that exists a more simpler way, how to do it, but I don't fully understand, how it works...
Thanks in advance for help.
I assume that with "replace" you actually mean "swap"/"exchange".
Some issues:
The argument head should be passed by reference, as one of the nodes to swap may actually be that head node, and then head should refer to the other node after the function has done its job.
The node before temporaryOne will need its next pointer to change, so you should stop your loops one step earlier in order to have access to that node and do that.
In some cases head may need to change, but this is certainly not always the case, so doing head = temporaryOne or head = temporaryTwo is certainly not right. In most cases you'll need to link to the swapped node from the preceding node (see previous point).
The next pointer of the node that is swapped will also need to change, as the node that follows it will be a different one than before.
As mentioned already in comments, it is advised to split the task into removals and insertions, as the fiddling with next pointers can get confusing when you try to cover all possible cases, notably making the distinction between the case where the two nodes are adjacent and when they are not.
Here are some functions that split the work into removal, insertion and finally exchanging nodes:
Node* removeNode(Node* &head, int index) {
// If index is out of range, no node is removed, and function returns nullptr
// Otherwise the extracted node is returned.
if (head == nullptr || index < 0) return nullptr;
Node* current = head;
if (index == 0) {
head = head->next;
current->next = nullptr;
return current;
}
while (--index > 0) {
current = current->next;
if (current == nullptr) return nullptr;
}
Node* temp = current->next;
if (temp != nullptr) {
current->next = temp->next;
temp->next = nullptr;
}
return temp;
}
void insertNode(Node* &head, Node* node, int index) {
// If index is too large, node is inserted at the end of the list
// If index is negative, node is inserted at the head of the list
if (index <= 0 || head == nullptr) {
node->next = head;
head = node;
return;
}
Node* current = head;
while (--index > 0 && current->next != nullptr) {
current = current->next;
}
node->next = current->next;
current->next = node;
}
bool exchangeNodes(Node* &head, int indexOne, int indexTwo)
{
// Returns true when successful, false when at least one index
// was out of range, or the two indexes were the same
if (head == NULL || head->next == NULL || indexOne == indexTwo || indexOne < 0) return false;
// To ensure the right order of operations, require the first index is the lesser:
if (indexOne > indexTwo) return exchangeNodes(head, indexTwo, indexOne);
Node* two = removeNode(head, indexTwo);
if (two == nullptr) return false; // out of range
Node* one = removeNode(head, indexOne);
insertNode(head, two, indexOne);
insertNode(head, one, indexTwo);
return true;
}

Having trouble figure out why my doubly linked list is falling apart and I could use some direction [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Full disclosure: This is a project for my class, but I'm not here to ask you to do my homework for me. I'm looking for a little direction as to what I seem to be missing.
The assignment: From a file of formatted data (see below). You are to create 3 doubly linked lists. (so one set of data with three "chains" that orders the data numerically) If you come across an piece of data with the same timestamp as a previous piece of data, that data is considered to be unreliable and needs to be deleted from the doubly linked list.
The Problem: I have four linked list heads, timeHead, tempHead, and windHead are for the data being read in from the file. The last is duplHead (duplicateHead) is for a list of duplicates. My issue is that whenever I try to delete a particular node from my linked list. I cant seem to do it correctly. I either crash the program or the doubly linked list falls apart.
Here is my code: I feel my main problem is either not creating the list correctly OR not deleting the problem nodes correctly.
The int main function only calls two functions addData and print report. I have included what I felt was relevant.
//ADD TO LINKED LIST
void linkedlist::addToLinkedList(weatherdata *newNode){
int doubleMarker = 0;
weatherdata *newNodeCopy;
weatherdata *currentNode;
weatherdata *nextNode;
newNodeCopy = new weatherdata; // <-- NEW
newNodeCopy = newNode;
/*_____ lINKED lIST FOR TIMESTAMP _____*/
//checks the duplicate list so as not to add a deleted triple
if (isItInDuplicateList(newNode) == 1){
doubleMarker = 1;
}
//if something exists in the list do this: traverse the list, check for duplicates.
if ((timeHead != nullptr) && (doubleMarker != 1)){
currentNode = timeHead;
while (currentNode != nullptr){
//if its the same as another item DELETE
if (newNode->time == currentNode->time) {
addToDuplicateList(newNode);
deleteNodeFromList(newNode);
doubleMarker = 1; // <-- this double marker will ensure that the function doesnt add a duplicate item
break;
}
currentNode = currentNode->timeN;
}
}
//if the incoming number is not a duplicate of something we already have on our list we add it
if (doubleMarker != 1){
//very first item on list
if (timeHead == nullptr){
timeHead = newNodeCopy;
}
//first position on list
else if (newNode->time < timeHead->time){
nextNode = timeHead;
timeHead = newNodeCopy;
newNodeCopy->timeN = nextNode;
nextNode->timeP = newNodeCopy;
}
//either between 2 entries or at the end of the list
else {
//traverse the list and find the appropriate placement for the newNode
currentNode = timeHead;
nextNode = timeHead->timeN;
//while "not yet at the end of the list"
while (nextNode != nullptr){
//newNode belongs somewhere in between two other entries
if ((currentNode->time < newNode->time) && (newNode->time < nextNode->time)){
currentNode->timeN = newNodeCopy;
newNodeCopy->timeP = currentNode;
newNodeCopy->timeN = nextNode;
nextNode->timeP = newNodeCopy;
break;
}
//otherwise increment currentNode and nextNode and compare again
else {
currentNode = nextNode;
nextNode = nextNode->timeN;
}
}
//newNode goes at the end of the linked List
if (nextNode == nullptr){
currentNode->timeN = newNodeCopy;
newNodeCopy->timeP = currentNode;
}
}
}
/*_____ lINKED lIST FOR TEMPERATURE _____*/
//if the incoming number is not a duplicate of something we already have on our list we add it
if (doubleMarker != 1){
//very first item on list
if (tempHead == nullptr){
tempHead = newNodeCopy;
}
//first position on list
else if (newNode->temp < tempHead->temp){
nextNode = tempHead;
tempHead = newNodeCopy;
newNodeCopy->tempN = nextNode;
nextNode->tempP = newNodeCopy;
}
//either between 2 entries or at the end of the list
else {
//traverse the list and find the appropriate placement for the newNode
currentNode = tempHead;
nextNode = tempHead->tempN;
//while "not yet at the end of the list"
while (nextNode != nullptr){
//newNode belongs somewhere in between two other entries
if ((currentNode->temp <= newNode->temp) && (newNode->temp <= nextNode->temp)){
currentNode->tempN = newNodeCopy;
newNodeCopy->tempN = nextNode;
nextNode->tempP = newNodeCopy;
break;
}
//otherwise increment currentNode and nextNode and compare again
else {
currentNode = nextNode;
nextNode = nextNode->tempN;
}
}
//newNode goes at the end of the linked List
if (nextNode == nullptr){
currentNode->tempN = newNodeCopy;
newNodeCopy->tempP = currentNode;
}
}
}
/*_____ lINKED lIST FOR WINDSPEED _____*/
//if the incoming number is not a duplicate of something we already have on our list we add it
if (doubleMarker != 1){
//very first item on list
if (windHead == nullptr){
windHead = newNodeCopy;
}
//first position on list
else if (newNode->wind < windHead->wind){
nextNode = windHead;
windHead = newNodeCopy;
newNodeCopy->windN = nextNode;
nextNode->windP = newNodeCopy;
}
//either between 2 entries or at the end of the list
else {
//traverse the list and find the appropriate placement for the newNode
currentNode = windHead;
nextNode = windHead->windN;
//while "not yet at the end of the list"
while (nextNode != nullptr){
//newNode belongs somewhere in between two other entries
if ((currentNode->wind <= newNode->wind) && (newNode->wind <= nextNode->wind)){
currentNode->windN = newNodeCopy;
newNodeCopy->windN = nextNode;
nextNode->windP = newNodeCopy;
break;
}
//otherwise increment currentNode and nextNode and compare again
else {
currentNode = nextNode;
nextNode = nextNode->windN;
}
}
//newNode goes at the end of the linked List
if (nextNode == nullptr){
currentNode->windN = newNodeCopy;
newNodeCopy->windP = currentNode;
}
}
}
}
//ADD TO DUPLICATE LIST
void linkedlist::addToDuplicateList(weatherdata *duplicateNode){
weatherdata *currentNode;
weatherdata *nextNode;
weatherdata *addDuplicateNode;
addDuplicateNode = new weatherdata; // <-- NEW
//make a complete copy for the duplicate list (since were going to delete that node)
addDuplicateNode->time = duplicateNode->time;
addDuplicateNode->temp = duplicateNode->temp;
addDuplicateNode->wind = duplicateNode->wind;
addDuplicateNode->timeN = duplicateNode->timeN;
addDuplicateNode->timeP = duplicateNode->timeP;
addDuplicateNode->tempN = duplicateNode->tempN;
addDuplicateNode->tempP = duplicateNode->tempP;
addDuplicateNode->windN = duplicateNode->windN;
addDuplicateNode->windP = duplicateNode->windP;
addDuplicateNode->duplN = duplicateNode->duplN;
if (duplHead == nullptr){
duplHead = addDuplicateNode;
}
else {
currentNode = duplHead;
nextNode = duplHead->duplN;
while (nextNode != nullptr){
currentNode = nextNode;
nextNode = nextNode->duplN;
}
currentNode->duplN = addDuplicateNode;
}
}
/DELETE FROM LINKEDLIST
void linkedlist::deleteNodeFromList(weatherdata *toBeDeletedNode){
weatherdata *currentNode;
weatherdata *nextNode;
currentNode = timeHead;
nextNode = timeHead->timeN;
while (nextNode != nullptr){
if (nextNode->time == toBeDeletedNode->time){
currentNode->timeN = nextNode->timeN;
//currentNode->tempN = nextNode->tempN;
//cout << ".";
delete toBeDeletedNode;
toBeDeletedNode = nullptr;
break;
}
currentNode = nextNode;
nextNode = nextNode->timeN;
}
}
//DUPLICATE LIST CHECK
bool linkedlist::isItInDuplicateList(weatherdata *checkThisNode){
bool found = false;
weatherdata *currentNode;
currentNode = duplHead;
if (duplHead == nullptr){
found = false;
}
else {
do {
if (currentNode->time == checkThisNode->time) {
found = true;
break;
}
currentNode = currentNode->duplN;
} while (currentNode != nullptr);
}
return found;
}
So either the first (long) function linkedlist addToLinkedList();
or the last (short) function linkedlist deleteNodeFromList();
If you need me to post anymore code please let me know and I'll so so.
Again, I feel like I'm either not making the doubly linked list correctly or not deleting it right.
Thanks again!
First take a look at these lines:
newNodeCopy = new weatherdata; // <-- NEW
newNodeCopy = newNode;
In the first line you create a new object of type weatherdata and saves a pointer to the new object in newNodeCopy.
In the second line you overwrite the value of newNodeCopy with the value of newNode which means you have lost the pointer to the new object (i.e. you have a memory leak).
If you want to copy the values from the object that newNode points to into the newly created object, you need to do:
*newNodeCopy = *newNode;
In general I'll recommend that you split the function into three smaller functions (i.e. one for each list). Smaller functions are easier to understand and debug.
Also I noticed this part:
if (isItInDuplicateList(newNode) == 1){
doubleMarker = 1;
}
In all the remaining code in the function you do:
if (doubleMarker != 1){
.....
}
In other words - once doubleMarker is set to 1, you don't execute more code. Therefore you can simplify your code by returning right away. Like:
if (isItInDuplicateList(newNode) == 1){
return;
}
Then you can remove all the if (doubleMarker != 1){ and your code gets more simple to read, understand and debug.
The delete function
Your void linkedlist::deleteNodeFromList(weatherdata *toBeDeletedNode) have some serious problems - consider this:
1) What will happen if timeHead is nullptr ?
2) Where do you check if timeHead->time == toBeDeletedNode->time ?
3) Where do you update the timeP pointer ?
The answers are:
1) Program crash
2) Never - so you can't delete the head element.
3) Never - so your list is broken! You need to add code that updates the "previous" pointer

Remove function removes all nodes in hash table

I have this bit of code below to remove an entry from hash table. When I run the code, the program does not crash, but rather, all nodes in the specific bucket where I need to remove an element are all removed.
The count of inserted and removed elements is as it should be.
Sample
Before Remove.
Number of Nodes = 11
Bucket[0]
Node01, Node02, Node03
Bucket[1]
Node11, Node12, Node13, Node14
Bucket[2]
Node21, Node22
Bucket[3]
EMPTY
Bucket[4]
Node41, Node42
Remove Node12
Hash Table Becomes.
Number of Nodes = 10
Bucket[0]
Node01, Node02, Node03
Bucket[1]
EMPTY //This should be Node11, Node13, Node14
Bucket[2]
Node21, Node22
Bucket[3]
EMPTY
Bucket[4]
Node41, Node42
Remove Method
void HashT::Remove(string key)
{
size_t index = HashFunc(key);
if (table[index] != NULL)
{
node* prev = NULL;
node* curr = table[index];
while (curr->next != NULL && entry->item.GetKey() != key)
{
prev = curr;
curr = curr->next;
}
if (curr->item.GetKey() == key)
{
node* nextEntry = curr->next;
table[index] = nextEntry;
delete entry;
size--;
cout << "Removed\n";
}
}
}
I use this function to insert into the hash table
void HashT::Ins(Data& data)
{
size_t index = HashFunc(data.GetKey());
node * newData = new node(data);
if(table[index] != NULL && table[index]->item.GetKey() == data.GetKey())
cout << "Do nothing\n";
else
newData->next = table[index];
table[index] = newData;
size++;
}
Calls to Remove inside main() looks something like this
HashT ht(cout);
ht.Ins(Data(node1));
ht.Ins(Data(node2));
ht.Ins(Data(node3));
ht.Ins(Data(node4));
ht.Remove("string3"); //This does not work
ht.Ins(Data(node5));
ht.Ins(Data(node6));
ht.Ins(Data(node7));
ht.Ins(Data(node8));
ht.Remove("string2"); //This Works
ht.Remove("string5"); //This doesnt work
I propose following change:
void HashT::Remove(string key)
{
size_t index = HashFunc(key);
if (table[index] != NULL)
{
node* prev = NULL;
node* curr = table[index];
while (curr->next != NULL && entry->item.GetKey() != key)
{
prev = curr;
curr = curr->next;
}
if (curr->item.GetKey() == key) // change (1) !!!!
{
node* nextEntry = curr->next;
if (prev) // change 2 !!!!
prev->next = nextEntry; // change 2 !!!!
else table[index] = nextEntry; // change 2 !!!
delete entry;
size--;
cout << "Removed\n";
}
else if (curr->next!=NULL) // change 1 !!!
cout << "Not found in bucket\n"; // change 1 !!!
}
}
change 2 : you shall update the table[index] only if the found element is the first in the bucket. In all other case, it's the classic removal of elements where you change the next pointer of the previous element to the next element (classic linked list update).
Edit: my previous change 1 was mislead by the initial entry, sorry for that. I've updated it to make explicit the cases where an item is not found in a bucket.

Simple AVL tree delete is only working sometimes

I'm working on an AVL tree. It seems the my remove only works correctly some of the time. I built a tree that looks like this
f
/ \
e j
/ / \
a h s
by inserting in the order f e h s j a. I know that it is working correctly on insert and balancing.
When I remove a, or j, or h, or s, or e, everything works fine. If I remove f, then it replaces f with h, which is correct, but I lose j and s.
This is the first function that is called.
void remove(const ItemType& item)
{
if(root == NULL)
return;
else
{
remove(root, item);
}
};
The first function calls this one to recursively find the correct node.
void remove(Node<ItemType>* & node, const ItemType& item)
{
if(item > node->item)
{
if (node->rightChild == NULL)
{
return; // there is nothing here to remove
}
else
{
// recurse to next node
remove(node->rightChild, item);
}
}
else if (item < node->item)
{
if (node->leftChild == NULL)
{
return; // there is nothing here to remove
}
else
{
// recurse to next node
remove(node->leftChild, item);
}
}
else if (node->item == item)
{
remove(node);
}
if (node != NULL)
node->updateHeight();
};
This is the last function to be called. This is where the deletion and swaps are done.
void remove(Node<ItemType>* & node)
{
if (node->rightChild == NULL && node->leftChild == NULL)
{
delete node;
node = NULL;
}
else if (node->rightChild == NULL)
{
Node<ItemType>* temp = node;
node = node->leftChild;
delete temp;
}
else
{
Node<ItemType>* & temp = node->rightChild;
while (temp->leftChild != NULL)
temp = temp->leftChild;
node->item = temp->item;
delete temp;
temp = NULL;
}
if(node != NULL)
node->initializeHeight();
};
I am wondering if it has something to do with the lines
Node<ItemType>* & temp = node->rightChild;
while (temp->leftChild != NULL)
temp = temp->leftChild;
node->item = temp->item;
delete temp;
temp = NULL;
and the temp pointer is acting in a behavior I am not familiar with, or if my whole implementation is wrong. I know the missing nodes are out there somewhere because my memory leak shows me those two nodes that go missing are never deleted.
I am wondering if it has something to do with the lines
Yes. Node<ItemType>* & temp = node->rightChild; says temp is an alias for node->rightChild. So the while loop modifies node->rightChild and you lose the handle to the original right child.
Take an ordinary pointer and walk it down the right subtree until you have gotten to the parent of its smallest member. Then get the value of the smallest member to copy it into node->item, and delete the parent's left child.

Delete a node from the middle of a C++ queue

I have a linked list with a c-style ctor and dtor.
I just got too frustrated when this if statement decided not to test true, putting me in
an infinite loop. I dont understand why it will never test true.
I am trying to delete a node (the address of a class object) from my LinkedList.
Maybe someone could help me out?
Node *Current = first_; // I want this to be my only Node Ptr Varaible Declaration.
if ( NULL == first_ )
std::cout << "Cannot delete from an empty list: \n";
while ( Current != NULL )
{
if ( first_->data_ == node->data_ )
{
//check to see if we are deleteing the head.
first_ = first_->next_;
--listLen_;
delete Current;
std::cout << "Head Deleted!\n";
}
if ( Current->data_ == node->data_ ) // FOR SOME REASON this is never true?
{
--listLen_;
node->data_ = NULL;
Current = Current->next_;
node->data_ = Current;
}
else // we must not of found it. // else should match previous i
{
Current->prev_ = Current;// since we are not deleting the first node we are OK here.
Current = first_->next_;
if ( Current->next_ == NULL ) // see if we are at the end of the list.
{
first_ = NULL;
last_ = Current->prev_;
}
}
}
return;
This should really be rewritten, since it has too many problems...also why not use a STL container? I assume this is a homework question.
The answer to the infinite loop is the else case that increments to the next node:
Current = first_->next_;
This will make you loop forever if the data is not found in in the first two nodes...since you will set the next test to the first's next node always and it will never set the current to NULL provided there are more than 2 nodes in the list.
Keep your loops small, it easier to figure out what went wrong. Assuming your data compare makes sense, look at this the following:
curr = first_;
while( curr && (curr->data_ != node->data_) ) {
curr = curr->next_;
}
if (!curr) return // didnt find it, nothing to remove
if ( curr == first_ )
first_ = curr->next_
else
curr->prev_->next_ = curr->next_
curr->next_->prev_ = curr->prev_ // always fix next's prev
delete curr
I'm not entirely sure what you're trying to accomplish, but I'm certain you're doing it wrong. If you're merely trying to remove an element from a doubly-linked list that matches node->data_, it's as easy as this:
Node *Current = first_;
while (Current != NULL)
{
if (Current->data_ == node->_data)
{
//If Current isn't the head of the list, set prev to next
if (Current != first_)
Current->prev_->next_ = Current->next_
else
{
first_ = Current->next_;
if (first_ != NULL)
first_->prev_ = NULL;
}
//If Current isn't the tail of the list, set next to prev
if (Current->next_ != NULL)
Current->next_->prev_ = Current->prev_
else if (Current->prev_ != NULL)
Current->prev_->next_ = NULL;
delete Current;
Current = NULL;
}
else
{
Current = Current->next_;
}
}
return;
You don't show where node comes from or how data_ is defined, but if it is a pointer type, you probably need to compare the contents, not the addresses.
Assuming that data_ is a pointer to something and what it points to has operator== defined or is a built in type and it has the value you are looking for then you can do this instead:
if ( *Current->data_ == *node->data_ )
if first_->data_ == node->data_ ever evaluates to true then the second if statement will always evaluates to true then the second if condition will always evaluate to false Current->data_ == node->data_ because on the first iteration first_ == Current and you delete Current without ever updating it
To delete a node from a linked list you seem to be doing way too much work.
Not really an answer here for the actual question but a suggestion.I would never iterate through a linked list to delete an entry in the list. Each entry should have a valid next and previous pointer and when you go to delete an entry from the list you just make the previous record point to the next one and vice versa to remove yourself from the list. An empty list should have a head record and a tail record that just point to each other and all valid entries are inserted in between.
Delete a node with value passed.
void deleteBegin()
{
Node* temp =Head;
if(temp==NULL)
return;
Head=Head->next;
free(temp);
}
void deleteMiddle(int _data)
{
Node* curr = Head;
Node* prev = Head;
if(curr==NULL)
return;
if(curr->next==NULL)
{
deleteBegin();
return;
}
while(curr->next!=NULL && curr->data!=_data)
{
prev=curr;
curr=curr->next;
}
if(curr->data == _data)
{
if(prev==curr)
{
deleteBegin();
return;
}
prev->next = curr->next;
free(curr);
}
else
{
cout<<"Element Not Found\n";
return;
}
}