How to remove an item from a structure array in C++? - c++

I have the following array structure (linked list):
struct str_pair
{
char ip [50] ;
char uri [50] ;
str_pair *next ;
} ;
str_pair *item;
I know to create a new item, I need to use
item = new str_pair;
However, I need to be able to loop through the array and delete a particular item. I have the looping part sorted. But how do I delete an item from an array of structures?

What you've shown is not an array of struct, but a linked list of struct containing arrays (of type char).
An array of struct would look like this:
str_pair array_of_structs[10];
// or:
str_pair* dynamically_allocated_array_of_structs = new str_pair[10];
If you actually have something like this, you don't need to delete single items from an array. Let's say you've initialized your array as follows:
str_pair* array_of_structs = new str_pair[10];
Then you delete the whole array (including all of its items) using:
delete[] array_of_structs;
Again, you can't delete single items in an array allocated with new[]; you perform a delete[] on the whole array.
If, on the other hand, you intended to say "linked list of struct", then you'd generally delete an item similarly to the following:
str_pair* previous_item = ...;
str_pair* item_to_delete = previous_item->next;
if (item_to_delete != 0)
{
previous_item->next = item_to_delete->next; // make the list "skip" one item
delete item_to_delete; // and delete the skipped item
}
Or, in English: Find the item (A) preceding the item which you want to delete (B), then adjust A's "next" pointer so that B will be skipped in the list, then delete B.
You need to be careful with special cases, i.e. when the item to be removed from the list is the first item or the last one. The above code is not sufficient when you want to delete the first item in the list, because there will be no previous_item. In this case, you'd need to change the pointer to the list's first element to the second element.
Your code:
void deleteitem(char *uri)
{
str_pair *itemtodelete;
curr = head;
while (curr->next != NULL) {
if ((strcmp(curr->uri, uri)) == 0) {
itemtodelete = curr;
curr = itemtodelete->next;
delete itemtodelete;
curr = head;
return;
}
curr = curr->next;
}
}
Some things are wrong here:
If head is null, the test curr->next != NULL will cause a segfault. (You must never dereference a null pointer!)
Your code for removing an item from the list is completely incorrect. Worst of all, you delete a node without changing the previous item's next pointer. The previous item will thus reference an item that's no longer there.
A detail: curr = head; before the return statement doesn't do anything useful at all.
Suggested code:
Do it in two steps: One function to find the node to be deleted via its attached uri, and one function to remove the node. You could separate it even better than the code below does, but it should be a starting point:
str_pair* finditemwithuri(char* uri)
{
str_pair* current = head;
while (current)
{
if (strcmp(current->uri, uri) == 0) return current;
current = current->next;
}
return 0;
}
void deleteitem(char* uri)
{
// find linked list node with that uri; abort if uri not in list
str_pair* itemtodelete = finditemwithuri(uri);
if (!itemtodelete) return;
// special case: node to be deleted is the list's head
if (itemtodelete == head)
{
head = itemtodelete->next;
delete itemtodelete;
return;
}
// else, iterate over list nodes
// up to the one preceding the node to be deleted
str_pair* current = head;
while (current)
{
if (itemtodelete == current->next)
{
current->next = itemtodelete->next;
delete itemtodelete;
return;
}
current = current->next;
}
}

Just use std::list. There's no reason to manually write such a construct.
http://msdn.microsoft.com/en-us/library/802d66bt(VS.80).aspx
std::list offers remove.

You can delete it using the ordinary delete keyword, but that will not shift all other members of the array. If you want this kind of behaviour take a look at std::vector or something like that.

It is maybe off topic, but why dont you use the std::list library ?

As others have pointed out, this is a Linked List, not an array. To answer your question for linked lists:
To insert an item:
str_pair* p = // iterate over the linked list to your insertion point
str_pair* item = new str_pair;
item->next = p->next;
p->next = item;
That inserts a new str_pair after p.
To remove an item:
str_pair* p = // iterate to just before your deletion point
str_pair* item = p->next;
p->next = p->next->next;
delete item;
This will remove the element after p
To do this with your code:
void deleteitem(char *uri)
{
str_pair *previous = NULL;
curr = head;
while (curr != NULL) {
if ((strcmp(curr->uri, uri)) == 0) {
// modify the previous element to skip over our deleted one
if (previous)
previous->next = curr->next;
else
head = curr->next;
// safely delete the element, now that no one points to it
delete curr;
curr = head;
return;
}
// always remember our previous element, so we can fix its 'next' pointer
previous = curr;
curr = curr->next;
}
}
You need a better add method too:
void additem(char *uri, char *ip)
{
curr = head;
// traverse the list until we're at the last item
while (curr->next != NULL) {
curr = curr->next;
}
// attach a new element to the list
curr->next = new str_pair;
// go to that new element
curr = curr->next;
// set the values of the new element
strcpy(curr->ip, ip);
strcpy(curr->uri, uri);
curr->next = NULL;
curr = head;
}

Related

how can I reverse my Linked list . I wrote following code but this is giving only first node's data as output

Node *reverse(Node *head)
{
Node *answer = NULL, *p = head, *address = NULL;
while (p != NULL)
{
address = p;
address->next = answer;
answer = address;
p = p->next;
}
return answer;
}
In order to reverse a singly linked list, you need to keep one node in memory to be able to relink backwards.
It could look like this:
Node* reverse(Node* head) {
if(head) { // must have at least one node
Node* curr = head->next; // head + 1
head->next = nullptr; // this will be the new last node
Node* next; // for saving next while relinking
while(curr) { // while curr != nullptr
next = curr->next; // save the next pointer
curr->next = head; // relink backwards
head = curr; // move head forward
curr = next; // move curr forward
}
// head now points at the new start of the list automatically
}
return head;
}
Demo
I wrote following code but this is giving only first node's data as output
Because, in reverse() function, you are breaking the link of first node from rest of the list and returning it.
Look at this part of code:
address = p;
address->next = answer;
answer = address;
p = p->next;
In first iteration of while loop this is what happening:
Pointer address will point to head of list (as p is initialised with head) and, in the next statement, you are doing address->next = answer (note that answer is initialised with NULL). So, address->next is assigned NULL. Both, pointer p and pointer address are still pointing same node. After this, you are doing p = p->next, this will assign NULL to p because p->next is NULL. As, p is NULL, the while loop condition results in false and loop exits and function end up returning the first node.
You should assign p to its next before assigning answer to address->next, like this:
while (p != NULL)
{
address = p;
p = p->next; // moved up
address->next = answer;
answer = address;
}
Suggestion:
In C++, you should use nullptr instead of NULL.
Reversing a linked list, in essence, is pretty much flipping the arrows:
Original: A->B->C->D->null
Intermediate: null<-A<-B<-C<-D
Reversed: D->C->B->A->null
void reverseList(void)
{
Node *prev = nullptr;
Node *curr = head;
while (curr)
{
Node *nxt = curr->next;
curr->next = prev;
prev = curr;
curr = nxt;
}
head = prev;
}
The crux of the solution will be to use the previous and current node strategy to loop through the list. On lines two and line 3, I set the prev to null and curr to the head respectively. Next, I set the while loop, which will run until curr is equal to null or has reached the end of the list. In the 3rd and 4th lines of the body of the while loop, I set prev to curr and curr to nxt to help me move through the list and keep the traversal going while keeping track of the previous and current nodes.
I am storing the next of the current node in a temporary node nxt since it gets modified later.
Now, curr->next = prev is the statement that does some work. Flipping of the arrows takes place through this statement. Instead of pointing to the next node, we point the next of the current node to the previous node.
Now, we need to take care of the head node only. On the last line, head=prev, prev is the last node in the list. We set the head equal to that prev node in the list, which completes our code to reverse a list.
Suppose you have any trouble visualizing the algorithm. In that case, you even have the privilege to print the data stored in the current and previous nodes after each line in the while loop for a better understanding.
Hope this helps getting the gist of how we reverse a linked list.

How can I delete a node in my linked list in C++?

I've pasted my work so far here:
http://codepad.org/WhJuujRm
The concepts of linked lists boggle my mind, so I thought I'd practice. I know how to add nodes, and edit nodes, but I don't know how to remove nodes in my particular scenario.
My Pseudo Code:
previous == now - 1;
if(stdid == now->getID());
previous->setNext(now->getNext);
delete now;
return;
How could I implement this?
The mind-tease in deleting an element from a linked list is updating the pointer that brought you to the element in the first place. In your list case, that could be top (and/or possibly bottom), it could be some node's next. As you walk through the list hunting with a cur pointer, keep a prev pointer which you advance one step behind as you enumerate. Assuming you find the victim node (if you don't, there's nothing to do, woot!), prev will be in one of two states:
It will be NULL, in which case top is the pointer that refers to your victim node and top must be updated, or...
It will be some pointer to a node, in which case that node's next member needs to be updated to the reflect the victim node's next member value.
In both cases bottom may need updating as well. In the first case bottom will need to change if the list only had one node and you're deleting it. i.e. you will have an empty list when finished. Easy enough to tell, since top will be NULL after to detach cur and set top equal to cur->next. Even easier for you, since you're keeping a size member in your list container; if it was 1, you know both head and bottom
In the second case, the last node may be the victim node. In that case bottom has to be updated to reflect the new end of the list (which is coincidentally in prev, and may be NULL if, once again, the list had only a single element. How do you tell if the victim was the last node in the list? If it's next member is NULL, it has to be the last node, and bottom must be updated.
So something like this, a delete function based on ID search
void deleteStudent(int id)
{
student *cur = top, *prev = nullptr;
while (cur && cur->getID() != id)
{
prev = cur;
cur = cur->getNext();
}
// found a node?
if (cur)
{
student *pNext = cur->getNext();
// set new next pointer for prev, or new top
if (prev)
prev->setNext(pNext);
else
top = pNext;
// update bottom if needed
if (!pNext)
bottom = prev;
delete cur;
--scnt;
}
}
Other delete options and criteria I leave to you.
Best of luck.
This should work, but I have not tested it.
There is a special case, when the first node is deleted. previous is set to NULL for the first iteration, and the top has to be adjusted in this case.
I didn't use bottom, because it's not the way I would do it. If you use bottom, there is a second special case, when you delete the last student. I would mark the end of the list with a next pointer set to NULL, because this eliminates this special case.
bool deleteStudent(int id)
{
student* now = top;
student* prev = NULL;
while(now != NULL) {
student* next = now->getNext();
if(id == now->getID()) {
delete now;
if(prev) prev->setNext(next);
else top = next;
return true;
}
prev = now;
now = next;
}
return false;
}
I did not use your notation but I think you can get the point.
prev = NULL;
current = top;
while (current != NULL && !isfound(current)){
prev = current;
current = current->next;
}
// current point to the element you want to delete (if not NULL)
if(current != NULL) {
if(previous != NULL) {
previous->next = current->next;
}
else {
top = current->next;
}
delete current;
}

Crash when deleting nodes in a circular list

I got some problems with the algorithm for "clearing" nodes in a circular list: most of times the program crashes and sometimes not. I'm quite sure that the algorithm is ok and I have no clue about the solution... :-(
Here some piecies of code:
The clear() function (Note: mFreenode is the "head-tail free" node for the circular list):
List* clear() {
if (mFreenode->getNext() != 0) {
Node<T>* current = mFreenode->getNext();
Node<T>* temp = 0;
while (current != mFreenode) {
temp = current->getNext();
delete current;
current = temp;
}
}
mFreenode->setNext(0);
mFreenode->setPrev(0);
mSize = 0;
return this;
}
And this is the Node destructor:
~Node() {
delete &item;
}
Any suggestion?
Your destructor looks very suspicious -- I'm assuming that item is a member variable of Node. If item is a value type (eg int or std::string), then you shouldn't be deleting it at all. If it's a pointer, then perhaps you should be doing delete item; -- but only if the Node has ownership of the item that it has a pointer to.
When you delete item; you do not make the previus Node to point to the Node after the Node you delete. As a result the Node previus to the one you delete points to nowhere.
Please never do the following with a circular linked list:
while (current != mFreenode) {
temp = current->getNext();
delete current;
current = temp;
}
Why do you think it is a circular linked list?? Because the tail node points to the first one, so when you do that the loop will go ahead and delete all nodes except the node before current.
and then you try to access it bad idea:
mFreenode->setNext(0);
mFreenode->setPrev(0);

why i cannot delete my node with reference

void deleteElement(LinkedListElement<char> *&pending)
{
if (pending->Next) {
char value = pending->Next->Data;
pending->Data = value;
LinkedListElement<char> *temp = pending->Next;
pending->Next = pending->Next->Next;
delete temp;
}else{
delete pending;
pending = NULL;
}
}
LinkedListElement<char> *l1 = new LinkedListElement<char>('a');
LinkedListElement<char> *l2 = new LinkedListElement<char>('b');
LinkedListElement<char> *l3 = new LinkedListElement<char>('a');
LinkedListElement<char> *l4 = new LinkedListElement<char>('c');
l1->setNext(l2); l2->setNext(l3); l3->setNext(l4);
printLinkedList(l1);
deleteElement(l4);
printLinkedList(l1);
Simple tricky delete node in C++ what i want to ask is in the else statement, if the linked list is end , so i can just delete the end itself.
but the two print function, will always print abac, and second way abac.
because i just pass the parameter with reference, (&), i think if i want to delete l4
i do not need to change l3->Next, becasue i can change l4 to NULL, and l3->Next will be NULL.
i try to use
delete pending; pending=NULL;
why it is does not work, two print function always print abac
You delete l4, but you never change l3, and it points to l4s memory (now deleted) which still contains the data ('c')
You need to
l3->setNext(NULL);
to remove the element from the list (and you must still delete it of course)
To use the deleteElement function, you would need to change it to iterate through the list (Pseudo code):
void deleteElement( Element head , Element toBeDeleted)
{
//are we deleting head (the first element of the list?)
//yes then head should be nulled, and delete as normal
current = head ; ancestor = head;
//scan through list (current becomes current->next until no more)
//until we find toBeDeleted
//maintain ancestor as we go
//if found set ancestor->next to current->next
//delete toBeDeleted
}

What is the pointer-to-pointer technique for the simpler traversal of linked lists? [duplicate]

This question already has answers here:
An interesting C linked list idiom
(11 answers)
Closed 5 years ago.
Ten years ago, I was shown a technique for traversing a linked list: instead of using a single pointer, you used a double pointer (pointer-to-pointer).
The technique yielded smaller, more elegant code by eliminating the need to check for certain boundary/edge cases.
Does anyone know what this technique actually is?
I think you mean double pointer as in "pointer to a pointer" which is very efficient for inserting at the end of a singly linked list or a tree structure. The idea is that you don't need a special case or a "trailing pointer" to follow your traversal pointer once you find the end (a NULL pointer). Since you can just dereference your pointer to a pointer (it points to the last node's next pointer!) to insert. Something like this:
T **p = &list_start;
while (*p) {
p = &(*p)->next;
}
*p = new T;
instead of something like this:
T *p = list_start;
if (p == NULL) {
list_start = new T;
} else {
while (p->next) {
p = p->next;
}
p->next = new T;
}
NOTE: It is also useful for making efficient removal code for a singly linked list. At any point doing *p = (*p)->next will remove the node you are "looking at" (of course you still need to clean up the node's storage).
By "double-pointer", I think you mean "pointer-to-pointer". This is useful because it allows you to eliminate special cases for either the head or tail pointers. For example, given this list:
struct node {
struct node *next;
int key;
/* ... */
};
struct node *head;
If you want to search for a node and remove it from the list, the single-pointer method would look like:
if (head->key == search_key)
{
removed = head;
head = head->next;
}
else
{
struct node *cur;
for (cur = head; cur->next != NULL; cur = cur->next)
{
if (cur->next->key == search_key)
{
removed = cur->next;
cur->next = cur->next->next;
break;
}
}
}
Whereas the pointer-to-pointer method is much simpler:
struct node **cur;
for (cur = &head; *cur != NULL; cur = &(*cur)->next)
{
if ((*cur)->key == search_key)
{
removed = *cur;
*cur = (*cur)->next;
break;
}
}
I think you mean doubly-linked lists where a node is something like:
struct Node {
(..) data // The data being stored in the node, it can be of any data type
Node *next; // A pointer to the next node; null for last node
Node *prev; // A pointer to the previous node; null for first node
}
I agree with the comments about using the STL containers for handling your list dirty work. However, this being Stack Overflow, we're all here to learn something.
Here's how you would normally insert into a list:
typedef struct _Node {
void * data;
Node * next;
} Node;
Node * insert( Node * root, void * data ) {
Node * list = root;
Node * listSave = root;
while ( list != null ) {
if ( data < list->data ) {
break;
}
listSave = list;
list = list->next;
}
Node * newNode = (Node*)malloc( sizeof(Node) );
newNode->data = data;
/* Insert at the beginning of the list */
if ( listSave == list ) {
newNode->next = list;
list = newNode;
}
/* Insert at the end of the list */
else if ( list == null ) {
listSave->next = newNode;
newNode->next = null;
list = root;
}
/* Insert at the middle of the list */
else {
listSave->next = newNode;
newNode->next = list;
list = root;
}
return list;
}
Notice all the extra checking you have to do depending on whether the insertion occurs at the beginning, end or middle of the list. Contrast this with the double pointer method:
void insert( Node ** proot, void * data ) {
Node ** plist = proot;
while ( *plist != null ) {
if ( data < (*plist)->data ) {
break;
}
plist = &(*plist)->next;
}
Node * newNode = (Node *)malloc( sizeof(Node) );
newNode->data = data;
newNode->next = *plist;
*plist = newNode;
}
As Evan Teran indicated, this works well for singly linked lists, but when it's doubly linked, you end up going through just as many if not more manipulations as the single pointer case. The other draw back is that you're going through two pointer dereferences for each traversal. While the code looks cleaner, it probably doesn't run as quickly as the single pointer code.
You probably mean a doubly-linked list, with one of the pointers going forward and the other going backward. This allows you to get to the next and previous nodes for a given node without having to remember the last one or two nodes encountered (as in a singly-linked list).
But the one thing I discovered which made the code even more elegant was to always have two dummy elements in the list at all times, the first and the last. This gets rid of the edge cases for insertion and deletion since you're always acting on a node in the middle of the list.
For example, an empty list is created:
first = new node
last = new node
first.next = last
first.prev = null
last.next = null
last.prev = first
// null <- first <-> last -> null
Obviously, traversing the list is slightly modified (forward version shown only):
curr = first.next
while curr <> last:
do something with curr
curr = curr.next
The insertions are much simpler since you don't have to concern yourself with whether you're inserting at the start or end of the list. To insert before the current point:
if curr = first:
raise error
add = new node
add.next = curr
add.prev = curr.prev
curr.prev.next = add
curr.prev = add
Deletions are also simpler, avoiding the edge cases:
if curr = first or curr = last:
raise error
curr.prev.next = curr.next
curr.next.prev = curr.prev
delete curr
All very much cleaner code and at the cost of only having to maintain two extra nodes per list, not a great burden in today's huge memory space environments.
Caveat 1: If you're doing embedded programming where space still might matter, this may not be a viable solution (though some embedded environments are also pretty grunty these days).
Caveat 2: If you're using a language that already provides linked list capabilities, it's probably better to do that rather than roll your own (other than for very specific circumstances).