Is there any way to reverse linked list without using temp variable in C?
Thanks in advance.
the famous approach:
Element *reverse(Element *head)
{
Element *previous = NULL;
while (head != NULL) {
// Keep next node since we trash
// the next pointer.
Element *next = head->next;
// Switch the next pointer
// to point backwards.
head->next = previous;
// Move both pointers forward.
previous = head;
head = next;
}
return previous;
}
uses temp variable
Saurabh
Note that your temp usage is actually generating two swap() calls, and can be replaced with:
swap(head->next,previous);
swap(previous,head);
You can swap without temps using xor, it is called xor swap.
Use XOR-swaps on the pointers to fake an XOR-linked-list.
Implementation is left to the reader as an exercise.
Recursive approach :
Element *reverse(Element *head, Element **first)
{
if (head->next == NULL)
{
*first = head;
return head;
}
Element* NextElement= reverse (head->next, first);
NextElement->next = head;
head->next = null;
return head;
}
Call for recursive function:
Element *revLinkListHead;
reverse(head, &revLinkListHead);
If someone is still interested, here is the solution that uses no new variables at all, except for those passed in recursive call.
public static List invert(List l) {
invert(l.next, l, l);
l = l.next;
breakCycle(l, l);
return l;
}
private static void invert(List l, List toBeNext, List first) {
if(l.next == null) {
l.next = toBeNext;
first.next = l;
} else {
invert(l.next, l, first);
l.next = toBeNext;
}
}
private static void breakCycle(List l, List first) {
if(l.next == first) {
l.next = null;
} else {
breakCycle(l.next, first);
}
}
The idea is the following: first we run invert function recursively, and implement it so that when it reaches the last element it assigns it as a next element of current head (parameter first). After we executed it, we will have a reversed list but cycled, so the current head.next will point at the head of the reversed list. We reassign head to its next element (the actual head of the reversed list), and the last thing we have to do is to break the cycle. So we call breakCycle which does the job recursively!
Related
I am writing a C program to sort a linked list according to the largest values. I met an issue whereby the program just hangs when the program reached "prevPtr->next = headPtr".
I want the prevPtr->next to equate to headPtr, if the sum of prevPtr is larger than the sum of headPtr, however the program just hangs there.
compareNodes() function is used to compare the nodes to see if newNode has the same name as any other structs in the linked list, then it will add in the sum.
sortSimilarNodes() function is used to sort the nodes according to the sum of each struct.
The struct is here below:
struct purchase {
char name[30];
double sum;
struct purchase * next;
} ;
LOG * compareNodes(LOG * headPtr, char * name, char * price){
.
.
.
while (curPtr != NULL) {
if (strcmp(newNode->name, curPtr->name)==0) {
curPtr->sum += newNode->sum;
free(newNode);
similar = 1;
break;
}
//advance to next target
prevPtr = curPtr;
curPtr = curPtr->next;
}
/*if (curPtr == NULL){
if(strcmp(newNode->name, prevPtr->name)==0){
prevPtr->sum += newNode->sum;
free(newNode);
similar = 1;
}
}*/
if (similar == 1){
headPtr = sortSimilarNodes(curPtr, headPtr);
}
else{
headPtr = sortNodes(newNode, headPtr);
}
return headPtr;
}
LOG * sortSimilarNodes(LOG * newPtr, LOG * headPtr){
LOG * curPtr;
LOG * prevPtr;
if(headPtr->sum < newPtr->sum){
newPtr->next = headPtr;
return newPtr;
}
prevPtr = headPtr;
curPtr = headPtr->next;
while (curPtr == NULL){
}
while (curPtr != NULL){
if(strcmp(curPtr->name, newPtr->name)==0){
break;
}
prevPtr = curPtr;
curPtr = curPtr->next;
}
return headPtr;
}
This is the output of the program.
Thank you!
It's hard to tell from your code, because you haven't posted all of it, but you seem to have some misconceptions about linked lists. In particular:
There is no need for new nodes unless you really add new nodes to the list. That also means that you don't call malloc except when adding nodes. (There's no malloc in your code, but a suspicious free in your comparison function. Comparing does not involve creating or destroying anything; it just means to look what is already there.)
A corollary to the first point is that there should be no nodes in an empty list, not even dummy nodes. An empty list is a list whose head is NULL. Make sure that you initialise all head pointers before creating a new list:
LOG *head = NULL; // empty list
When you sort the list, the order of the list has changed and the old head is invalid. You cater for that by returning the new head:
head = sort(head);
But that seems redundant and it also seems to imply that the two pointers can be different. That's not the case, because the old pointer will point somehwre in the sorted list, not necessarily at its head. It's probably better to pass the head pointer's address in order to avoid confusion:
sort(&head);
Sorting linked lists can be tricky. One straightforward way is selection sort: Find the node with the highest value, remove it from the original list and add it at the front of a new list. Repeat until there are no more nodes in the original list.
Adding a new node n at the front of a list given by head is easy:
n->next = head;
head= n;
Adding a new node at the end of a list that is given by head is a bit more involved:
LOG **p = &head;
while (*p) p = &(*p)->next;
*p = n;
n->next = NULL;
Here, p is the address of the pointer that points to the current node, *p. After walking the list, that address is either the address of the head node (when the list is empty) or the address of the next pointer of the precedig node.
You could achieve something similar by keeping a prev pointer, but the pointer-to-pointer solution means that you don't have to treat the cases where there is no previous node specially at the cost of some extra & and * operators.
With that, your sorting routine becomes:
void sortByName(LOG **head)
{
LOG *sorted = NULL;
while (*head) {
LOG **p = head; // auxiliary pointer to walk the list
LOG **max = head; // pointer to current maximum
LOG *n; // maximum node
while (*p) {
if (strcmp((*p)->name, (*max)->name) > 0) max = p;
p = &(*p)->next;
}
n = *max;
*max = (*max)->next;
n->next = sorted;
sorted = n;
}
*head = sorted;
}
If you want to sort by sum, change the comparison to:
if ((*p)->sum > (*max)->sum) max = p;
Call the function like this:
LOG *head = NULL;
insert(&head, "apple", 2.3);
insert(&head, "pear", 1.7);
insert(&head, "strawberry", 2.2);
insert(&head, "orange", 3.2);
insert(&head, "plum", 2.1);
sortByName(&head);
print(head);
destroy(&head);
with the insert, destroy and print functions for completeness:
void insert(LOG **head, const char *name, double sum)
{
LOG *n = malloc(sizeof(*n));
if (n) {
snprintf(n->name, sizeof(n->name), "%s", name);
n->sum = sum;
n->next = *head;
*head = n;
}
}
void destroy(LOG **head)
{
LOG *n = *head;
while (n) {
LOG *p = n;
n = n->next;
free(p);
}
*head = NULL;
}
void print(LOG *l)
{
while (l) {
printf("%s: %g\n", l->name, l->sum);
l = l->next;
}
puts("");
}
i have a linked list like this :
1,jhon,19
2,sara,18
3,tom,20
4,jack,22
i have been trying forever to delete an element based on their id (witch is the first number). But in order to do that i need to delete this element from any position. so i came up with this code and i was wondering if it's correct :
temp1=head;
if(head!=NULL && head->id==givenID) // if the element is in the first position
{
temp = head;
head = head->next;
free(temp);
}
else if(head!=NULL && head->id!=givenID){// search for the element in the middle
do{
temp2=head;
head = head->next;
}while(head->id !=givenID && head->next !=NULL);
if(head->next !=NULL && head->id==givenID){// if the element is in the middle
temp2->next=head->next;
free(head);
head=temp1;
}
else if(head->next ==NULL && head->id==givenID){// if the element is in the last position
temp->next=NULL;
free(head);
head=temp1;
}
}
Thank you
This code is too complex, because it has unnecessary branches. You can unify your code by using a pointer to pointer.
The idea is to point your pointer to pointer to the head of the list, then to the next pointer of the initial element of the list, then to the next pointer of the second element of the list, and so on. The beauty of this approach is that no matter where you are in your list, the operation on a pointer to pointer remains the same!
Here is how it looks in code:
// Point your pointer to pointer to the head of the list
struct node **pptr = &head;
while (*pptr != NULL) {
// Dereference pptr to get the pointer to current node
node *current = *pptr;
// Check if the id of this node matches what we're looking for
if (current->id == givenID) {
// Here is the "magic": assign the next pointer of the current node
// to whatever is pointed to by pptr.
// It could be a head, or a next of some node.
*pptr = current->next;
free(current);
break;
}
pptr = &(current->next);
}
That's it! Since the pointer to pointer does not differentiate between head and other nodes, there is no additional checking going on.
Consider using a sentry node. All special cases disappear when you do.
This is how node erasure look in a linked list with sentry:
Iterator Erase( List* lst, Iterator here )
{
Iterator nxt = here->next;
Link( here->prev, here->next );
free( here );
lst->size -= 1;
return nxt;
}
with Link being no more complicated than
void Link( Iterator n1, Iterator n2 )
{
n1->next = n2;
n2->prev = n1;
}
All the other core functions, like insert etc. are similarly trivial.
So I'm running into a bit of a wall here. I have a main.c program that plays around with linked lists, and at some points passes in a value of a node that's to be deleted from the list. The kicker was that it was supposed to do it using call by reference. I'm fairly certain (like...85%) that I've got all the things I need for the remove node function, but I'm probably just not implementing it right.
So this is the initializing function that all the others in my List.c file derive from:
// Call by reference
// This is a linked list without dummy head node!
void init(List *alist, int (*fComp)(void *, void *), void (*fPrint)(void *), void (*fFree)(void *))
{
if(alist != NULL)
{
alist->head = NULL;
alist->tail = NULL;
alist->size = 0;
alist->cmpData = fComp;
alist->printData = fPrint;
alist->freeData = fFree;
}
else
{
printf("Invalid NULL list pointer passed in!\n");
}
}
This is my removeNode function:
int removeNode(List *alist, void *obj){
Node *cur, *prev = alist->head, *start = (*alist).head;
void *temp = obj;
if(temp == cur) {
alist->head = cur->next;
free(cur);
return 1;
}
else if(obj != alist->head) {
for (cur = start->next; cur != NULL; cur = cur->next) {
if (alist->cmpData(cur->data, temp) == 0) {
prev->next = cur->next;
free(cur);
return 1;
} // end if
prev = cur;
} // end for
} // end else if
return 0;
} // end removeNode
"List *alist" and "void *obj" are the linked list elements and the element to be deleted, respectively that are passed in from main.c. The function is supposed to use cmpData (which needs to be passed two void pointers) from the init function to compare the current element being looked at with the element to be deleted then either return 1 if it does delete it or 0 if it doesn't.
Thank you in advanced for any and all help!
UPDATE So my code posting is now the one that I've got to work. It deletes the node as it is supposed to. HOWEVER, do I have enough free() in it? I have a memory leak checking program and it keeps telling me that I need two more free()'s in here, and it seems to specifically be the removeNode function since nowhere else in my program gets flagged.
this is the case i am working on
[11] -> [12] -> [13] -> NULL
I am trying to delete the elements from the liked list above(example) but I keep getting segfault and on running GDB doesnot help much. I am not looking for an answer but and explanation on where I am going wrong logically.
here is the code
int
List:: remove( int val )
{
ListNode *headNode = _head;
ListNode *tempNode = NULL;
if(headNode->_value == val){
tempNode = headNode->_next;
delete headNode;
_head = tempNode;
}
else
{
while(headNode->_value != val){
tempNode = headNode;
headNode = headNode->_next;
}
tempNode->_next = headNode->_next;
delete headNode;
}
}
You're not accounting for the following conditions:
The list may be empty; i.e. _head is NULL;
The value may not be in the list at all.
Your function is declared to return int, but makes no such return
Assuming the rest of your code is correct (and that is a big assumption), I'm all-but-certain this is what you're trying to do:
void List::remove( int val )
{
ListNode *headNode = _head;
ListNode *tempNode = NULL;
while (headNode && headNode->_value != val)
{
tempNode = headNode;
headNode = headNode->next;
}
if (headNode)
{
if (tempNode)
tempNode->next = headNode->next;
else
_head = headNode->next;
delete headNode;
}
}
Alternatively, if so inclined this can get (arguably) simpler utilizing a pointer-to-pointer to traverse the pointers in the list, not just their values. It is worth investigating how the following works, which still covers all the bases described previously, but does so using the actual pointers in the list nodes themselves, including _head, by-address rather than by-value, thereby eliminating the need for a walk-behind temporary pointer:
void List::remove( int val )
{
ListNode **pp = &_head;
while (*pp && (*pp)->_value != val)
pp = &(*pp)->next;
if (*pp)
{
ListNode *p = *pp;
*pp = p->next;
delete p;
}
}
In your remove method you are assuming there are always elements in your list. - What if it is empty?
What if the value isn't in the list? You need to handle this case as well.
You're headed in the right direction - there are just a few cases that you haven't considered that can lead you to seg fault.
Example of forward traversal with deletion (forward-only linked list):
// Start from the beginning (head), then while the current isn't null,
// move to the next node.
for (ListNode* current = head; current != null; current = current->next) {
// Check the next item if there is one, and remove it if it matches the value.
// We check the next one because you can't delete the current node in a
// forward only linked list (can in a doubly-linked list however)
if (current->_next != nullptr && current->_value == value) {
// Make this item point to the next next item
// (Since we're gonna delete the next item)
current->_next = current->_next->next;
// Delete the next item.
delete current->_next;
}
}
I'm trying to add a node to a linked list. The idea is to pass in the pointer, see where new node will go to through a ranked order, in this case G, then D, then M, then S.
Yet, when I compile and run, I'm not actually generating a linked list (this has already been done in the main). I'm more than certain that there's something wrong with my addp() function. Is it that I should pass in double pointers instead?
Sorry for being rather unprofessional and clueless. I'm not the strongest of coders.
Any help would be helpful.
I have attached my method which I have gone through so many times.
typedef struct node {
char fname[1024];
char lname[1024];
char pos;
int val;
int rank;
struct node * next;
} player;
struct node* addp (player* newnode, struct node* list){
player* templist = list;
player* templist1;
// if the list is non empty.
if (list!=NULL){
if(newnode->pos == GOALKEEPER){ //insert if G.
newnode->next = list;
}
if(newnode->pos == DEFENDER){// after G bef M.
// iterate through templist.
while (templist->next != NULL && (templist->next)->rank < 1) { // go to end of G.
// when the list isn't empty next node rank is less than one, keep going
templist = templist -> next;
}
// when finally rank == or > 1, then add newnode.
templist1 = templist->next;
templist->next = newnode;
newnode->next = templist1;
}
if(newnode->pos == MIDFIELDER){ //after G and M but before S
while (templist->next != NULL && (templist->next)->rank <2 && (templist->next)->rank> 2){
templist = templist -> next;
}
// when stopped, then add newnode.
templist1 = templist->next;
templist->next = newnode;
newnode->next = templist1;
}
if(newnode->pos == STRIKER){ // at the end.
while (templist->next != NULL && (templist->next)->rank <3){
templist = templist -> next;
}
templist1 = templist->next;
templist->next = newnode;
newnode->next = templist1;
}
return list;
printf("player added");
}
// if list is empty
else{
newnode->next = list;
return 0;
}
}
The following is the list function I've come up with. It keeps saying that my linked list is empty. Maybe it's something wrong with this function.
int print(struct player* list){
// create temp list so non modify origin.
struct player* temp = list;
if (list == NULL && temp == NULL)
printf("linked list is empty");
while (temp != NULL){
printf("%s \n", temp->lname);
printf("%s \n", temp->fname);
printf("%c \n", temp->pos);
printf("d \n", temp->val);
temp = temp->next;
}
return 0;
}
Without knowing the player typedef this is hard to analyze, but I think you can make it much easier on yourself by simplifying the signature of the function to only use player.
void addp(player* newnode, player* firstnode)
The return is unnecessary since you're just returning the 2nd argument, which the caller already has. The 2nd argument should be a pointer to a player node, which is the first element in your linked list. If you can call the function without the compiler complaining about implicitly casting pointers then I don't see anything wrong with your algorithm, although it could certainly be simplified.
Ok so what I understood is that your player structure contains a variable pos that will indicate in which place insert the player in the list. Am I right ?
In that case the best thing you can do is to sorted the list by the rank variable. Then modify your pos variable (in the player structure) to match with the rank variable of your list.
Then you will just have to add it with a classic "add in sorted list" function : C++ Add to linked list in sorted orderenter link description here