Deleting a node from array of linked lists? - c

I'm writing a hashtable as an array of linked lists.Currently I'm trying to have a simple hash table where the key is the index of the array and value is a singly linked list for implementing chaining.
This is my code to delete a node:
Basic Struct:
struct Node
{
int value;
int page;
struct Node *next;
};
int searchAndDelete(int frame,int page,int delete)
{
struct Node** iter;
iter=&hashtable[(page-1)%7];
struct Node** prev=iter;
for(;*iter;iter=&(*iter)->next)
{
if(page==((*iter)->page))
{
if(frame==((*iter)->value))
{
if(delete)
{
(*prev)->next=(*iter)->next;
free(*iter);
}
return 1;
}
}
prev=iter;
}
return 0;
}
For insertion please take a look here, AddNode
When I'm deleting a node, the value for that changes to 0. When I search for the node it gives back that node is not preset aka 0 as output from the function.
Are there any mistakes in my code which I haven't thought about?Am I leaving any memory leaks or any other problems?
Edit
Added this piece of code to the delete function:
int searchAndDelete(int frame,int page,int delete)
{
struct Node** iter;
iter=&hashtable[(page-1)%7];
struct Node** prev=iter;
struct Node** curr=iter;
for(;*curr;curr=&(*curr)->next)
{
if(page==((*curr)->page))
{
if(frame==((*curr)->value))
{
if(delete)
{
if(curr==iter)
{
iter=(*curr)->next;
free(*curr);
}
else
{
(*prev)->next=(*curr)->next;
free(*curr);
}
}
return 1;
}
}
prev=curr;
}
return 0;
}
Problem I'm seeing is that when I delete the first time, the element is not freed, it's value is set to 0, but it still says in the linked list. In the second deletion the value of the last elements goes to some garbage and hence that element will never be deleted in my comparison checks. Can someone shed light on what I might be doing here?

If the hash table you're using is seven elements wide (i.e. 0..6 for indexes), and from your AddNode code, it appears it is, then the arithmetic you're using is suspect for the initial iterator find.
iter=&hashtable[page-1%7];
should likely be:
struct Node** iter = hashtable + (page % 7);
This will give you the address of the element in your hash table at the page location modulus 7, i.e. [0..6].
Also, your delete from your hash table head node doesn't account for clearing the table element itself. You may need to (a) set it to null, or (b) chain in the next ptr. Do that as well. You have the ability to since the hash table and the initial node pointer are both available.
EDIT: OP asked for sample. This is just a quick jot of how this can be done. I'm sure there are plenty of better ways, maybe even ones that compile. This assumes both the page AND frame must match EXACTLY for a node to be considered delete'able.
void searchAndDelete(int frame, int page, int del)
{
struct Node** head = hashtable + (page % hashtable_size);
struct Node* curr = *head;
struct Node* prev = NULL;
while (curr)
{
// if they match, setup for delete.
if ((curr->page == page) && (curr->value == frame) && del)
{
// so long as the header pointer is the active node prev
// will be NULL. move head along if this is the case
if (prev == NULL)
*head = curr->next;
// otherwise, the previous pointer needs it next set to
// reference the next of our vicitm node (curr)
else
prev->next = curr->next;
// victim is safe to delete now.
free(curr);
// set to the new head node if we just deleted the
// old one, otherwise the one following prev.
curr = (prev == NULL) ? *head : prev->next;
}
else
{ // no match. remember prev from here on out.
prev = curr;
curr = curr->next;
}
}
}
Eh, close enough =P

I see couple of issues:
mod operator % needs parenthesis. So change iter=&hashtable[page-1%7]; to iter=&hashtable[(page-1)%7];
Handle the case when you will delete 1st element in linked list. In such cases prev will be same as iter so (*prev)->next=(*iter)->next; will not make any different. You need to update the array to store next element aka (*iter)->next.

Related

Deleting List With One Node In C

I have a function here that will remove a node from a sorted list of any type.
I am having difficulties with one specific case: when there is 1 node in the list and you want to delete it.
In this case, I want to make the list empty, so when the list is printed out, no data is printed to the screen, but I can't seem to get that result. Just say, for example, the list is of type double, and the list consists of just one node 2.0. If this node is the target for deletion, the proceeding output should be an empty list. Instead my code prints out 0.0.
I am not sure how to handle this error. I have found the specific part of the function where this is to be taken care of, but its implementation escapes me. I first check if the previous node is null, and then check if the list length is equal to 1.
The function returns 1 if it was successful and 0 if it failed.
int SLRemove(SortedListPtr list, void *newObj) {
Node ptr, iterptr, prev = NULL;
if(list==NULL || newObj ==NULL) {
return 0;
}
int size= listlength(list);
for(ptr=list->start; ptr!=NULL; ptr=ptr->next) {
if(list->cf(newObj, ptr->info)==0){//found matching entry in list
//deleting first node;
if(prev==NULL) {
if(size == 1) {
printf("attempting to delete list with 1 node\n");
/*code to delete node where it's the only element in the ist, should make the list empty.*/
return 1;
}
list->start = ptr->next;
destroyNode(ptr);
return 1;
} else {
prev->next = ptr->next;
destroyNode(ptr);
return 1;
}
}
prev = ptr;
}
return 0;
}
Any help you can provide would be much appreciated. Thank you.
The first check should be:
if(list==NULL || list->start == NULL || newObj ==NULL) {
return 0;
}
Once past this check, there's at least one node in the list. If prev == NULL, then you need to set list->start = list->start->next to delete the first node. It doesn't matter if there is one node or more than one node.
The other functions you have need to check for list->start == NULL (or size == 0) to avoid printing garbage.
Using a double pointer can eliminate checking for prev == NULL, but I can't explain for your code since I don't know how node is defined, and it's not really needed, since checking for prev == NULL is just as good. As an example:
typedef struct Node_{
struct Node_ *next;
...
}Node;
/* in the delete function */
Node **ppNode = &list->start; /* ptr to list->start or ...->next */
/* to advance ppNode */
ppNode = &(*ppNode->next);
/* to remove a node from the list */
*ppNode = (*ppNode)->next;

Deallocating binary-tree structure in C

I have a linked list, I guess a tree looks like this:
-> grandma
-> dad
-> me
-> sister
-> niece
-> brother
-> uncle
-> cousin
and I have a struct as following
struct Node{
Node *parent;
Node *next;
Node *child;
}
How would I free that linked list?
My idea is to do a depth first search and deallocate each node?
Recursive depth-search (DFS): You're right, it's a good way to dealocate binary-tree memory:
remove(node):
if node is null: return
//else
remove(left node)
remove(right node)
free(node)
Iterative solution:
https://codegolf.stackexchange.com/questions/478/free-a-binary-tree
Since you don't want to use any recursive solution, there you can find well-described iterative one.
You can optimize allocation/deallocation of the tree.
Imagine, you want to create tree with 20 or 30 persons. You can allocate an array of 30 Node structs:
size_t currentArraySize = 30;
Node* nodes = (Node*)malloc(currentArraySize * sizeof(Node));
size_t nextFreeIndex = 0;
To add new element you can write simple function:
Node* allocateNode()
{
// Oops! There's not more memory in the buffer.
// Lets increase its size.
if (nextFreeIndex >= currentArraySize) {
currentArraySize *= 2;
Node* newNodes = (Node*)realloc(nodes, currentArraySize * sizeof(Node));
// Should correct pointers (thanks to user3386109)
if (newNodes != nodes) {
for (size_t i = 0; i < nextFreeIndex; i++) {
if (newNodes[i]->parent != NULL)
newNodes[i]->parent -= nodes += newNodes;
if (newNodes[i]->next != NULL)
newNodes[i]->next -= nodes += newNodes;
if (newNodes[i]->child != NULL)
newNodes[i]->child -= nodes += newNodes;
}
}
}
return nodes[nextFreeIndex++];
}
To deallocate all nodes you can just free the single pointer nodes.
Now the code looks a little scary as wrote user3386109, so we may simplify it a little:
Node* allocateNode()
{
// Oops! There's not more memory in the buffer.
// Lets increase its size.
if (nextFreeIndex >= currentArraySize) {
currentArraySize *= 2;
Node* newNodes = (Node*)realloc(nodes, currentArraySize * sizeof(Node));
// Should correct pointers (thanks to user3386109)
if (newNodes != nodes)
correctPointers(newNodes, nodes);
}
return nodes[nextFreeIndex++];
}
#define correctPointer(pointer, oldOffset, newOffset) if (pointer != NULL) { \\
pointer -= oldOffset; \\
pointer += newOffset; \\
}
void correctPointers(Node* newNodes, Node* nodes)
{
for (size_t i = 0; i < nextFreeIndex; i++) {
correntPointer(newNodes[i]->parent, nodes, newNodes);
correntPointer(newNodes[i]->child, nodes, newNodes);
correntPointer(newNodes[i]->next, nodes, newNodes);
}
}
Iterative version, inspired by Day–Stout–Warren algorithm:
void removetree(Node *node)
{
while(node != NULL)
{
Node *temp = node;
if(node->child != NULL)
{
node = node->child;
temp->child = node->next;
node->next = temp;
}
else
{
node = node->next;
remove(temp);
}
}
}
This algorithm somewhat like tries to convert the tree into a list single-linked with next pointers, which is very simple to destroy just by iterative unlinking and destroying the first item. However it never completes the conversion, because it unlinks and removes the head node as soon as it can, despite the rest of tree not being converted yet. So to say, it interleaves a relink step with unlink-and-destroy step.
We test with the if instruction whether the first (head) node has any children. If so, we make its child a new head and the current node becomes the new head's next node. This way we have one more next link in the first-level list. What was 'next' to the now-head node becomes a child to a previous-head node, which is now the head's first next.
On the other hand if the head node has no children, it may be removed and its next becomes a new head.
These two steps are iterated by the while loop until all children are converted into siblings and removed afterwards.
You may use recursive solution
free(root)
{
if (root->next == null)
{
free(node)
}
free(root->left)
free(right->)
}

inserting element into a sorted list

I'm having trouble figuring out how to insert an element into a sorted list. I am new to linked lists and I'm still having trouble.The following function takes an predefined list and an element as arguments. I have white boarded the whole thing but I still can't figure it out. Thank you for your help.
/*
* function: lst_insert_sorted
*
* description: assumes given list is already in sorted order
* and inserts x into the appropriate position
* retaining sorted-ness.
* Note 1: duplicates are allowed.
*
* Note 2: if given list not sorted, behavior is undefined/implementation
* dependent. We blame the caller.
* So... you don't need to check ahead of time if it is sorted.
*/
void lst_insert_sorted(LIST *l, ElemType x) {
NODE *p = l->front;
NODE *temp;
NODE *current = p;
NODE *prev;
NODE *next;
if (p->val >= x) { // Base Case if
p->val = x;
}
while (p !=NULL) {
prev = current;
temp = prev->next;
next = current->next;
if (next->val >= x) {
temp->val = x;
}
}
return 0;
}
You did not show how NODE is defined. So I suppose that the list is a single-linked list. In this case the function can look like
void lst_insert_sorted( LIST *l, ElemType x )
{
NODE *current = l->front;
NODE *prev = NULL;
while ( ( current != NULL ) && !( x < current->val ) )
{
prev = current;
current = current->next;
}
NODE *node = malloc( sizeof( NODE ) );
node->val = x;
node->next = current;
if ( prev != NULL )
{
prev->next = node;
}
else
{
l->front = node;
}
}
Generally speaking, a linked list consists of "nodes" joined together in sequence by links pointing from each node to the next one (or to the previous one, or both). The nodes each point also (perhaps trivially) to one of the actual elements of the list.
To insert an element into a linked list at a given position, you just create a node pointing to that element, and update the other pointers as needed. With a doubly-linked list such as yours (where each node points both to the next one and to the previous one), you must
update the next pointer of the node immediately preceding the insertion position to point at the new node,
update the prev pointer of the node immediately following the insertion position to point at the new node, and
set the prev and next pointers of the new node to point to these other nodes.
There are typically special cases for inserting at the beginning or end of the list; details depend on your list and node implementation.
In your case, you must also find an appropriate insertion point. Since the list is sorted, you can just traverse it from the beginning, comparing each node's element to the one to be inserted, until you find the right spot. Such a "linear search" is not terribly efficient if the list is long, but you cannot do better with a generic linked list.
if (p->val >= x) { // Base Case if
p->val = x;
}
there is a loss data so you wrote the x with overwriting in to first data in the list.
İf ı understood the problem you should create a node and insert this to list.

Deleting Duplicates From a Doubly Linked List in C

I am trying to work with a doubly linked list of SAT grades between 200-800. I need to remove from all the duplicates from the list, i.e. make sure each grade appears only once by deleting all its duplicates.
#define HIGHEST_GRADE 800
typedef struct dListNode{
int* dataPtr;
struct dListNode* next;
struct dListNode* prev;
}DListNode;
typedef struct dList
{
DListNode* head;
DListNode* tail;
}DList;
void removeDuplicates(DList* lst)
{
int i;
int gradesBucket [numOfGrades];
DListNode* temp;
temp = lst->head;
for(i=200 ; i<HIGHEST_GRADE ; i++) /*creating 600 buckets - each bucket for a grade*/
gradesBucket[i] = FALSE;
while (temp)
{
if ((gradesBucket [*temp->dataPtr]) == TRUE) /*if current grade has already */
/* appeared earlier on the list */
{
deleteFromList (temp); /*delete that grade's cell*/
}
else
gradesBucket[*temp->dataPtr] = TRUE; /* mark grade bucket as true, meaning */
/* the grade already appeared*/
temp = temp->next; /*moving on to next grade*/
}
}
void deleteFromList(DListNode* toRemove)
{
toRemove->prev->next = toRemove->next;
toRemove->next->prev = toRemove->prev;
deAllocateListCell (toRemove);
}
void deAllocateListCell (DListNode* cell)
{
free (cell->dataPtr);
free (cell);
}
Please help me understand what's wrong.
here's the fixed code, which still doesn't work properly. Now it compiles but nothing is shown on screen. And by the way, I dont need to take care of deleting the head, because the first number can never be a duplicate... but I took care of it in case the head was NULL;
I also send the previous cell of the one i want to delete, to the function deleteFromList. It still doesn't work. Any ideas? Thanks!
void deleteFromList(DList* lst, DListNode* p)
{
DListNode* del_cell = p->next; /* cell to delete*/
if (p->next->next == NULL) /*if cell to remove is the tail*/
{
deAllocateListCell (p->next); /* freeing current tail */
lst->tail = p; /* p is the new tail */
p->next = NULL; /* tail points to NULL */
}
else /* if cell to remove is not the tail (note: can't be head beacuse no duplicates can be found in the first grade) */
{
p->next = del_cell->next;
del_cell->next->prev = p;
deAllocateListCell (del_cell);
}
}
The code of your function deleteFromList() doesn't account for (literal) edge cases: Deleting the first or last node of a list.
Plus, your code dereferences a pointer to a deallocated node; the pointer can become outright invalid, or the free() function can overwrite its contents (as the Microsoft Debug C RunTime is known to).
Try to be specific - What is it that doesn't work? Does your code compile? Do you get an error during runtime? You don't get the results you expected in a scenario?
Your deleteFromList function should take care of removing the head or tail (That is when toRemove->prev or toRemove->next are null (respectively).
temp = lst->head; and what happens when lst is null? You'll get a run-time error
You are not updating head or tail in case they are deleted
That's what I found in first glance.
you should write while(temp->next) for correcting this....and also u can simply deallocate the node using free. and to eliminate dangling pointer problem you should make it NULL after freeing that node

Maintaining chain of pointers to address

This is something of a followup to a question I asked earlier. I'm still learning my way around pointers, and I'm finding it difficult to maintain a reference to the physical address of a struct while iterating through a data structure. For example, I have a simple, barebones linked list that I'd like to delete from via a searching pointer:
struct Node{
int value;
struct Node* next;
};
struct Node* createNode(int value){
struct Node* newNode = malloc(sizeof *newNode);
newNode->value = value;
newNode->next = NULL;
return newNode;
}
void nodeDelete(Node **killptr){
free(*killptr);
*killptr = NULL;
}
int main(){
struct Node* head = createNode(16);
head->next = createNode(25);
head->next->next = createNode(51);
head->next->next->next = createNode(5);
// Working code to delete a specific node with direct reference address
struct Node** killptr = &head->next;
nodeDelete(killptr);
return 0;
}
The above shows deleting by passing nodeDelete a pointer to the address of the head pointer. What I want to do is be able to move my pointer ->next until it finds something that satisfies a delete condition, and call nodeDelete on that. I've tried the following:
struct Node* searchAndDestroy = head;
while(searchAndDestroy->value != NULL){ // Search until the end of the structure
if (searchAndDestroy->value == 25){ // If the value == 25
nodeDelete(&searchAndDestroy); // Delete the node (FAILS: Nullifies the
// address of search variable, not the
break; // original node)
}else{
searchAndDestroy = searchAndDestroy->next;
}
}
I've also tried something along the lines of:
if (searchAndDestroy->value == 25){
struct Node** killptr = (Node**)searchAndDestroy);
nodeDelete(killptr); // Still fails
}
I need to be able to move my pointer to the ->next point, but also maintain a reference to the address of the node I want to delete (instead of a reference to the address of the search node itself).
EDIT: Some clarification: I realize that deleting from a linked list in this fashion is naive, leaks memory, and drops half the list improperly. The point is not to actually delete from a linked list. Ultimately the idea is to use it to delete the leaves of a binary search tree recursively. I just figured a linked list would be shorter to portray in the question as an example.
struct Node **searchAndDestroy;
for (searchAndDestroy = &head;*searchAndDestroy; searchAndDestroy = &(*searchAndDestroy)->next ){
if ((*searchAndDestroy)->value == 25){
nodeDelete(searchAndDestroy); // Function should be changed to assign the ->next pointer to the **pointer
break;
}
}
And change nodeDelete like this:
void nodeDelete(Node **killptr){
Node *sav;
if (!*killptr) return;
sav = (*killptr)->next;
free(*killptr);
*killptr = sav;
}
Unless I'm missing something, your nodeDelete function is working as designed, but you want to keep a way of accessing the next node in the chain. The easiest way of doing this is just to add a temporary variable:
struct Node *searchAndDestroy = head, *temp = NULL;
while(searchAndDestroy != NULL){ // Need to check if the node itself is null before
// dereferencing it to find 'value'
temp = searchAndDestroy->next;
if (searchAndDestroy->value == 25){
nodeDelete(&searchAndDestroy);
break;
}else{
searchAndDestroy = temp;
}
}
if you give the Address of the previous Node that is where the link to deleting node present then it is very simple
code snippet for that:-
void delete_direct (struct Node *prevNode)
{/*delete node but restrict this function to modify head .So except first node use this function*/
struct Node *temp;/*used for free the deleted memory*/
temp=prevNode->link;
prevNode->link=temp->link;
free(temp);
}
struct Node * find_prev(struct Node *trv_ptr,int ele)
{
/*if deleting element found at first node spl operation must be done*/
if(trv_ptr->data==ele)
return trv_ptr;
while((trv_ptr->link)&&(trv_ptr->link->data!=ele))
{
trv_ptr=trv_ptr->link;
}
if(trv_ptr->link==NULL)
{
return NULL;
}
else
return trv_ptr;
}
main()
{
/*finding Node by providing data*/
struct Node *d_link;
struct Node *temp;
d_link=find_prev(head,51);
if(d_link==NULL)
{//data ele not present in your list
printf("\nNOT FOUND\n");
}
else if(d_link==head)
{//found at first node so head is going to change
temp=head;
head=head->link;
free(temp)
}
else
{//other wise found in some where else so pass to function
delete_direct (d_link);
}
}

Resources