I'm trying to implement a linked list, with a addToFront function to start with.
Where here I'm just adding the number 5, to the front of the list. I know that if the list is empty, the list pointer should be Null, however, this does not seem to be the case.
EDITED FILES:
I've edited the files( thanks to taskinoor's answer), which now provide the output of
0 5
Instead of
5
I have the header file:
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
typedef struct List {
struct list * next;
int value;
int size;
}list;
void addToFront(int num, list **l);
void printList(list * l);
int getSize(list * l);
void initialize(list * l);
void freeList(list *l);
A c file "main.c"
#include "Header.h"
int main() {
list l;
initialize(&l);
addToFront(5, &l);
printList(&l);
_getch();
freeList(&l);
return 0;
}
void printList(list * l) {
list *current = l;
while (current != NULL) {
printf("%d ", current->value);
current = current->next;
}
}
void freeList(list *l) {
list *current = l;
while (current != NULL) {
list *tmp = current;
current = current->next;
free(tmp);
}
}
And an interface c file (which is incomplete)
#include "Header.h"
int getSize(list * l) {
return l->size;
}
void initialize(list * l) {
l->next = NULL;
l->value = 0;
l->size = 0;
}
// need to pass **l to update it
void addToFront(int num, list **l) {
// allocate memory for new node
list *tmp = (list *)malloc(sizeof(list));
tmp->value = num;
// new node should point to whatever head is currently pointing
// even if head is NULL at beginning
tmp->next = *l;
// finally l needs to point to new node
// thus new node becomes the first node
*l = tmp;
}
However, when the addToFront function is called, the if statement is never executed. Which doesn't make sense, if the list is empty, shouldn't the list pointer be null?
Next I tried to manually set l == NULL in the Initialize function, but that didn't do anything either. Also, my print function loops infinity, which I presume is an issue with malloc. Any help would be greatly appreciated.
The condition if (l == NULL) is not true in addToFront because l is NOT NULL here. You have called l = malloc(sizeof(list)); at the beginning of the main which made l not NULL. There is no need to malloc and initialize l in this way. I suppose that by l you meant the head pointer to the list. This should be NULL at beginning (i.e. do not call malloc at main and assign the returned address to l) and your memory for node should be allocated in addToFront like this:
// need to pass **l to update it
void addToFront(int num, list **l) {
// allocate memory for new node
list *tmp = (list *) malloc(sizeof(list));
tmp->value = num;
// new node should point to whatever head is currently pointing
// even if head is NULL at beginning
tmp->next = *l;
// finally l needs to point to new node
// thus new node becomes the first node
*l = tmp;
}
Remove malloc from main.
int main() {
list *l;
addToFront(5, &l); // pass address of l
printList(l);
// other stuffs
}
And printing will be like this:
void printList(list * l) {
list *current = l;
while (current != NULL) {
printf("%d ", current->value);
current = current->next;
}
}
Finally it is not enough to free only l. You need to traverse whole list and free every node in it.
void freeList(list *l) {
list *current = l;
while (current != NULL) {
list *tmp = current;
current = current->next;
free(tmp);
}
}
Ok, lets begin from the last part:
I tried to manually set l == NULL in the Initialize function, but that didn't do anything either
Actually it did something, but once you returned from the initialize function, that change was lost. Here's why:
When you say initialize(l), in the initialize function body you get a copy of the original pointer l. Then you make that pointer, point to NULL. When that function returns the original pointer l still points to the initial memory (the one allocated with malloc). If you do want this initialize function to have such behavior, you should change it to:
initalize(list **l)
Regarding the addToFront() function, actually if it was executed, you would get a segfault! You check:
if (l == null)
and if it is, you try to dereference the NULL pointer!
l->value = num;
l->next = NULL;
l->size++;
Lastly, in your print fucntion you do not advance your pointer. You should write something like
l=l->next
in order to work
This is because of your printing function.
your are only printing the values that have a next node after them. so having only 1 value will not print anything. instead you should have:
void printList(list * l) {
while (l !=NULL)
{
printf("%d ", l->value);
l=l->next;
}
}
also in your addToFront function, you have a logical error, you are only setting the data and size IF the list passed in is in fact NULL, which is not the case.
Use:
void addToFront(int num, list **l) {
list *tmp= malloc(sizeof(list));
tmp->value = num;
tmp->next = *l;
*l= tmp;
}
Note: initialize is not needed. Just pass an empty or non-empty list so main can just do:
int main()
{
list * l= NULL;
addToFront(5, &l);
...
See ForeverStudent his solution to fix the print bug.
Related
I have this problem, where user inputs n and my program needs to remove any elements form a linked list that come after n and are not equal to n. For example, if my list is 1,2,4,8,4,6,1 and user inputs 4 it should output 1,2,4,4.
So far I only have this code (if list is 1,2,4,8,4,6,1 it outputs 4 8 4 6 1):
#include <iostream>
#include <algorithm>
using namespace std;
struct elem
{
int num;
elem *next;
elem(int n){num = n; next= NULL;}
};
void append(elem *&first, elem *&last, int n){
elem *p = new elem(n);
if(first==NULL)
first=last=p;
else {
last->next=p;
last = p;
}
}
void deleteListItems(elem *&first, int n){
elem *p;
while(first){
if(first->num==n){
break;
}
else{
p = first->next;
delete first;
first=p;
}
}
}
void print(elem *first){
elem *p = first;
while(p!=NULL){
cout<<p->num<<" ";
p = p->next;
}
cout<<endl;
}
int main () {
int aa[] = {1,2,4,8,4,6,1};
elem *first=NULL;
elem *last=NULL;
elem *p;
int n;
for(int i=0; i<7; ++i){
append(first, last, aa[i]);
}
print(first);
cout<<"Input n: "<<endl;
cin>>n;
elem *prev;
print(first);
deleteListItems(first, n);
print(first);
/// delete list
p = first;
while (p!=NULL){
first = first->next;
delete p;
p = first;
}
};
Your problem needs to be broken down into two parts
Find the first instance of the target value.
If found, advance to the node past it, and delete every node not the target value.
This is made trivial with a pointer to pointer approach. The code to do that is shown below, and I did my best to document how it works in comments.
void deleteListItems(elem *&first, int n)
{
// start at head of the list
elem **pp = &first;
// find the first instance of n
while (*pp && (*pp)->num != n)
pp = &(*pp)->next;
// if we found one...
if (*pp)
{
// advance past it
pp = &(*pp)->next;
// now walk the rest of the list
while (*pp)
{
// if this does NOT match the target value
if ((*pp)->num != n)
{
// remember the node, overwrite the list pointer
// referring to it with it's own 'next', and then
// delete now-unhitched node.
elem *p = *pp;
*pp = p->next;
delete p;
}
else
{
// otherwise, it's another instance of the target
// value, so just skip to the next node.
pp = &(*pp)->next;
}
}
}
}
This will work in every case I could think of, including lists without duplicates, lists entirely of duplicates, empty lists, single-node lists etc. Worth mentioning, the tail pointer in main can easily end up dangling, but that was an original problem with your code, and I suspect you'll address that soon enough.
I've a uni assignment and unfortunately, encountered a problem.
I'm still struggling with pointers and references so it's quite hard for me to find a solution, even though I've searched for it for an entire day.
Here are essential parts of my code:
struct BuenoList
{
int value;
BuenoList* prev;
BuenoList* next;
};
Declaration:
void insertNode(BuenoList*, int);
Definition:
void insertNode(BuenoList* tail, int _id)
{
BuenoList* temp = new BuenoList;
temp->value = _id;
temp->prev = tail;
tail->next = temp;
tail = temp;
tail->next = NULL;
}
Now, in main() I do this:
int main(int argc, char **argv)
{
BuenoList* BuenoListing = new BuenoList;
BuenoListing->value = 1;
BuenoListing->prev = NULL;
BuenoListing->next = NULL;
BuenoList* BuenoHead = BuenoListing;
BuenoList* BuenoTail = BuenoListing;
insertNode(BuenoTail, 2); // Add value 2 to the list
insertNode(BuenoTail, 3); // Add value 3 to the list
return 0;
}
Okay, so here's the problem:
When I print the list from the first element it prints like this:
1
1 2
1 3
So apparently this line
insertNode(BuenoTail, 3);
overwrites value 2.
My guess would be that BuenoTail does not change so there must be a problem with the reference.
How can I solve this?
Print should be: 1 2 3
#EDIT
void deleteNode(BuenoList*& tail, int _id) // Search list for specified value and delete it
{
BuenoList* temp = tail;
while (temp->prev != NULL)
{
if (temp->value == _id) break;
else temp = temp->prev;
}
if (temp->value == _id)
{
temp->prev = temp->next;
free(temp);
}
else std::cout << "ERROR KEY DOES NOT EXIST\n";
}
Considering you wanted to keep your code structure the same, I will show you two possible solutions. In a C fashion, you can use a pointer to a pointer to update your head and tail pointers. Or, in C++ you can pass your head and tail pointers by reference. Personally, in C++ I would make a LinkedList class that keeps track of your head and tail nodes though.
Passing pointer by reference (C++)
In order to pass your pointer by reference, first change your insertNode declaration,
void insertNode(BuenoList *&tail, int _id);
Next, change your insertNode definition with the same function arguments. That is it, your code should work now. This minute change works, because your tail node in the insertNode function is aliased with the tail node in your main function.
Passing pointer by pointer (C)
I know you put a C++ tag, but you can also update your head and tail nodes using a more C like method. First, in the main function, you will need to declare BuenoHead and BuenoTail as a pointer to a pointer.
int main(int argc, char **argv)
{
BuenoList* BuenoListing = new BuenoList;
BuenoListing->value = 1;
BuenoListing->prev = NULL;
BuenoListing->next = NULL;
BuenoList** BuenoHead = new BuenoList*;
BuenoList** BuenoTail = new BuenoList*;
*BuenoHead = BuenoListing;
*BuenoTail = BuenoListing;
insertNode(BuenoTail, 2); // Add value 2 to the list
insertNode(BuenoTail, 3); // Add value 3 to the list
return 0;
}
Then you need to update the insertNode function declaration to take a pointer to a pointer.
void insertNode(BuenoList** tail, int _id);
Then, you need to update the function definition to deference your pointer to a pointer correctly,
void insertNode(BuenoList** tail, int _id)
{
BuenoList* temp = new BuenoList;
temp->value = _id;
temp->prev = *tail;
temp->next = NULL;
(*tail)->next = temp;
*tail = temp;
}
EDIT
Deleting a node
You modified your question, asking for help on deleting a node. You have several problems with your deleteNode function.
You mix new with free. Whenever you allocate with new, you should correspondingly use delete.
You call temp->prev without checking whether temp could be NULL or not.
You need to change the function arguments to include your head pointer. It might turn out the node you want to delete is the head of your linked list. If so, you'll need to update the head node accordingly.
You need to check whether the node you are deleting is in the middle of the list, the head of the list, the tail of the list, or if is is the only node of the list. Each of these cases requires different operations to update your linked list.
Considering this is a university assignment, I don't want to give you the full blown solution. Here is a partially modified deleteNode function. I left some parts for you to fill out though. Hopefully that helps. Maybe next time focus the question a bit more, so I don't have to give a partial solution.
void deleteNode(BuenoList*& tail, BuenoList*& head, int _id) {
BuenoList* toDelete;
toDelete = tail;
// Traverse list and find node to delete
while( ( toDelete != NULL ) && ( toDelete->value != _id ) ) {
toDelete = toDelete->prev;
}
// If node not found, return
if( toDelete == NULL ) {
std::cout << "ERROR KEY DOES NOT EXIST\n";
return;
}
// Check to see if node to delete is tail
if( toDelete == tail ) {
if( toDelete->prev != NULL ) {
tail = toDelete->prev;
tail->next = NULL;
} else { //Deleting only node in list
tail = NULL;
head = NULL;
}
delete toDelete;
return;
}
// Check to see if node to delete is head
if( toDelete == head ) {
// FILL OUT WHAT TO DO HERE
return;
}
// Node to delete is neither head nor tail.
// FILL OUT WHAT TO DO HERE
return;
}
You are updating tail within insertNode(), but the updated value is not communicated back to the caller in any way. So BuenoTail does not change, as you suspected.
One easy way to fix that is to change your function to:
BuenoList *insertNode(BuenoList* tail, int _id)
and return the new tail from that function. Also change the calls to
BuenoTail = insertNode(BuenoTail, 2); // Add value 2 to the list
You may want to consider using a node structure and a list structure:
struct BuenoNode
{
int value;
BuenoNode* prev;
BuenoNode* next;
};
struct BuenoList
{
BuenoNode* head;
BuenoNode* tail;
size_t count; // having a count would be optional
}
The list functions would take a pointer to the list structure, such as InsertNode(BuenoList * blptr, int data); The list structure would be initialized so that both head and tail pointers == NULL, and you'll need to check for adding a node to an empty list or removing the only node in a list to end up with an empty list.
I have implemented this function in this way:
typedef node* List;
void DeleteFromPos(List &l, unsigned int p) {
List lAux = l;
unsigned int count = 1;
while (lAux) {
if (p == 1) {
while (l) {
List del = lAux;
lAux = lAux->next;
delete del;
del = NULL;
}
lAux = NULL;
} else if (count < p-1) {
lAux = lAux->next;
count++;
} else {
List del = lAux->next;
if (del) {
lAux->next = del->next;
delete del;
del = NULL;
} else
lAux = NULL;
}
}
}
The problem is when p==1, in this especial case all the elements are deleted but it looks like the l pointer still exist at the end.
I need some advice about this.
EDIT: with some sugerence, the p ==1 case have his own loop, its ugly but it works.
Simplify your task by modularising. First have a function that deletes all elements in a list.
deleteList(List *&head) {
while (head) {
List *l = head->next;
delete head;
head = l;
}
}
Note *& - reference to a pointer. Thus the function modifies head parameter.
Then have a function that locates n-th element. When you have n-th node call the above function.
If you really need to do the job in a single function then do something like:
deleteFromPosition(List *&head, unsigned int pos) {
loop one: iterate through the list until n-th node is reached;
loop two: iterate through the list tail deleting nodes as in the function above;
}
I am leaving details out for your exercise.
void DeleteFromPos(List &l, unsigned int p)
I believe you pass a pointer to node by reference so that if the head of your list is to be deleted, you can update the pointer itself so that this change is visible to the caller. Yet you do:
List lAux = l;
which throws this potential away. In case p equals 1, you should do:
if (p == 1) {
List del = l;
l = l->next; // <-- updates pointer that was passed by reference
delete del;
}
Pointer l is not changed in your function. You change pointer lAux but l keeps its original value.
I've checked the boards and could not find any help with this. I find it easy to implement recursive functions given base and general cases, but this doesn't work the way I do it. I'm supposed to iterate down a list until I reach the tail of a linked list. If the next node is NULL, then I have to store the value at the last node, remove that node, and return the value. So it's similar to a dequeue method, except it's performed recursively. What am I doing wrong?
int LinkedList::removeTailRec(Node *n)
{
// check for the base case(s)
if(n->next == NULL)
{
Node *tmp = new Node();
tmp = n;
int val = n->value;
tmp = NULL;
return val;
}
else
return removeTailRec(n->next);
// else call the recursive method
}
First, I recommend you use nullptr instead of NULL.
Then, onto your code. You're actually not removing anything from your list.
if(n->next == NULL)
{
Node *tmp = new Node();
^^^^^^^^^^
//Useless, and dangerous. This memory is never free'd
tmp = n;
int val = n->value;
tmp = NULL;
^^^^^^^^^^
//You just set a local variable to NULL, you're not deleting anything
return val;
}
If you want to remove the node, you'll have to keep a reference to the previous node (e.g. having a doubly linked list, that is, having a pointer to the next element and a pointer to the previous element in each node, or working on the previous node directly).
Set this previous node's next to nullptr, store the node's value and then delete the Node pointer.
One way to do this is to work with the pointer to the next node :
int LinkedList::removeTailRec(Node *n)
{
//EDIT: Adding a check for n validity
if(!n){
//Here, you should have a way of detecting
//a call to your method with a null pointer
return 0;
}
Node* nextNode = n->next;
// check for the base case(s)
if(nextNode->next == nullptr)
{
//Get the next node value
int val = nextNode->value;
//Set the current node next member to nullptr
n->next = nullptr;
//Free the last node
delete nextNode;
return val;
}
else{
return removeTailRec(n->next);
}
// else call the recursive method
}
You are storing the result but not deleting it from linked list. You can return result in another variable (pointer : result).
Node* getTail(Node *n,int *result){
//u can even free the memory
if(!n->next)
{
result=n->value;
return NULL;
}
n->next=getTail(n->next,result);
}
or you can do it other way
int getTail(Node *n)
{
if(!n) return 0;
if(n->next)
{
if(!n->next->next)
{
Node *frnode=n->next;
int result=n->next->value;
n->next=NULL;
delete frnode;
return result;
}
getTail(n->next);
}
You are not removing last node in your code, and you leak another (temporary) node here.
To remove last node you have to zero the link in the previous node.
Your code should look like
...
if (n == NULL || n->next == NULL)
throw std::out_of_range("node");
if(n->next->next == NULL)
{
int val = n->next->value;
delete n->next;
n->next = NULL;
return val;
}
else ...
Be aware of the fact that c++ is not a functional language and has no optimizations for tail recursion, so in real application as your lists grow big enough you'll eventually have failure with stack overflow =) use Haskell or Erlang for this style of programming, in c++ use for or while.
You should set the Node n's previous Node's next field to NULL when n is the tail Node.
I'm trying to reverse a linked list by using C++ and then print out the reversed one.
For example:
the original list is 1->2->3
after reversion: 3->2->1
But when I tried to print out the reversed linked list, 3->2->1 became a circular linked list like 3<->2
Followings are my codes:
#include <iostream>
#include <sstream>
using namespace std;
class List{
public:
int value;
List *next;
List(int);
List(int, List *);
};
List::List(int v){
value = v;
next = NULL;
}
List::List(int v, List *ne){
value = v;
next = ne;
}
string IntToString(int val){
stringstream temp;
temp<<val;
return temp.str();
}
void print(List *l){
string output= "";
while(l->next != NULL){
output+=(IntToString(l->value)+"-->");
l = l->next;
}
output+=(IntToString(l->value)+"-->NULL");
cout<<output<<endl;
}
List reverse(List L){
if(L.next == NULL) return L;
List remain = reverse(*(L.next));
List *current = &remain;
while(current->next != NULL)
current = (current->next);
L.next = NULL;
current->next = &L;
//print(remain);
return remain;
}
List copy(List l){
return l;
}
int main() {
List L3(3);
List L2(2, &L3);
List L1(1, &L2);
List L4 = reverse(L1);
print(&L4);
return 0;
}
Can anyone tell me why this happens? Thanks a lot!
First of all, I want to point out to you that a list containing a pointer to another list is conceptually wrong.
Create a list node class seperately, e.g.
struct ListNode {
int value;
Node *next;
};
Then your List becomes,
class List {
...
ListNode *head;
...
};
Now onto reversing. In the method List reverse( List L ), L is simply a local variable. It goes out of scope after,
return remain;
} // Here the scope of L ends
So it is logically incorrect to return a List whose next value is location of L,
current->next = &L;
return remain; // remain is equal to *current and current->next = &L
This causes undefined behavior in your implementation.
EDIT: I have some free time, so I came up with this implementation. It uses the same algorithm although modifies the original list on which it is called.
I think your reverse algorithm is correct, but remain is a local variable, which is invalid after return, therefore L4 will contain invalid pointer. Change the signature of reverse() to take and return List *.
List *reverse(List *L){
if(L->next == NULL) return L;
List *remain = reverse(L->next);
List *current = remain;
while(current->next != NULL)
current = (current->next);
L->next = NULL;
current->next = L;
//print(remain);
return remain;
}
Just looking at your reverse() function you are creating an object on the stack called remain and insert this into your list. This can't work: this object will go out of scope once your return from the function (the original objects in main() have the same problem but you don't try to use them after you left main()). Also, your reverse() function seems to have quadratic performance while it should be linear. I think something like this would do the trick:
List* reverse(List* head) {
List* tail(0);
while (head) {
List* tmp(head);
head = head->next;
tmp->next = tail;
tail = tmp;
}
return tail;
}
The above implementation also avoids the recursion.