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.
Related
The following code will not print the last line which displays the maximum element in the linked list below.
In the following code, I sum the linked list, print the entire linked list, print the length of the linked list, and would like to print the maximum value found in the linked list.
For some reason, the compiler does not print the last line.
#include <iostream>
#include <stdio.h>
using namespace std;
struct Node{ //if you want to convert to class, you need to assign access specifiers to public since they're private on default
int data;
struct Node *next;
}*first = NULL;
void create(int A[], int n)
{
struct Node *t; //create a temporary pointer t
struct Node *last; //pointer, points to the last node - helps me add a new node at the END of a linked list
//as of now, the linked list is empty, so we must create the first node!
first = new Node;//create new node on the heap, and first will be pointing on that new node
first -> data = A[0]; // Assign first the first element on the array
first -> next = NULL;//Should point to a null value as it is the only element on the list to start/currently
last = first; //last points on first node
for (int i = 1; i <n; i++)// i starts at element 1 since first has been assigned the 1st element in the array
{
t = new Node; //create a new node
t->data = A[i]; //fill up the data of t from A[i] which will be iterated through and assigned to data
t->next = NULL; // the next node should be pointing to NULL, as there is nothing at the moment when the iteration begins that it is initially pointing to
last -> next = t;
last = t;
}
}
int length (struct Node *p)
{
int l = 0;
while (p)
{
l++;
p = p->next;
}
return l;
}
int sum (struct Node *p){
int s= 0;
while(p){
s+=p->data;
p = p->next;
}
return s;
}
int max (struct Node *p){
int max = -32767;
while(p){
if(p->data > max){
max = p->data;
p = p->next;
}
}
return max;
}
void display (struct Node *p)
{
while (p != 0 )
{
cout<<p->data<<" ";
cout<<p->next<<" ";
p = p->next;
}
}
int main() {
int A [] = {1,2,3,18,5, 6, 7};
create (A,7);
display(first);
cout<<endl;
cout<<"The length of the linked list (the number of nodes) is: "<< length(first)<<endl;
cout<<"The sum of the linked list values (nodes) is: "<< sum(first)<<endl;
cout<<"The maximum value in the linked list (of the nodes) is: "<< max(first)<<endl;
return 0;
}
What am I doing wrong?
You have a little problem in your max function,your function never goes through the entire list since you put the p = p->next inside of the if block, you must edit it as below
int max (struct Node *p){
int max = -32767;
while(p !=nullptr ){
if(p->data > max){
max = p->data;
}
p = p->next;
}
return max;
}
It's because of that you put the p = p->next inside of the maximum checking scope and because of that if max set to 18, you couldn't point to the next of the list, since you don't have any data in the list that is bigger than 18,so list never finished and your iterator will be stopped in a fixed point and while loop will run forever!!
Your max() function is not incrementing the node pointer on every iteration, like your other functions do. If it encounters a data value that is not greater than the current max then it gets stuck in an endless loop.
You need to move the iteration out of the inner if block:
int max (struct Node *p){
int m = -1;
while (p){
if (p->data > max){
max = p->data;
}
p = p->next;
}
return m;
}
I am creating a program with linked list which has a function that destroys the nth element of the list and instead places the element whose number is stored in the nth element.
I have created a program that creates a linked list, but I can't find a way that searches for the nth element.
struct elem {
int value;
elem* next;
};
int main() {
elem* start = NULL, *last;
int a[4] = {1, 2, 3, 4};
/// creating
for(int i = 0; i < 4; i++) {
elem* p = new elem; /// s1
p->value = a[i]; /// s2
p->next = NULL; /// s3
if(start == NULL) start = p; /// s4a
else last->next = p; /// s4b
last = p; /// s5
}
/// printing
elem* p = start;
while (p) {
cout << p->value << " ";
p=p->next;
}
/// deleting
p = start; /// 1
while (p) {
start = p->next; /// 2
delete p; /// 3
p = start; /// 4
}
}
Could I get some help here please? Really struggling with linked list, thanks in advance!
first, you need to pass the value of "n" to your main() function through a args[]
then, add a while loop, just like the printing, increment index each time you go through the linked list elements, and check if index == n, get the element value, then delete that element by calling your delete function.
it is better to put your print/delete part as separate functions, then call these functions through your main(). and you can add some checking conditions for what parameters you got from the args[]
#include <iostream>
#include <memory>
using namespace std;
struct Node
{
int data;
Node* next;
};
void append(Node*&, int);
void printList(Node*);
void insertNode(Node*&, int, int);
void searchList(Node*, int, int);
int main()
{
Node* head = nullptr;
int initialCount = -1, userInput, newNodeLoc = -1, newNodeVal, searchVal;
/// INITIALIZE LIST
while(initialCount <= 0)
{
cout<<"Enter the number of initial nodes (must be at least 1): ";
cin>>initialCount;
}
cout<<endl;
for(int i = 0;i<initialCount;i++)
{
cout<<"Enter a number: ";
cin>>userInput;
append(head,userInput);
}
cout<<endl;
cout<<"Here are the initial values in the linked list: "<<endl;
printList(head);
cout<<"\nEnter a number for a new node to insert to the linked list: ";
cin>>newNodeVal;
cout<<endl;
cout<<"Enter which position you want to insert it (ex. "<<head->data<<" is at pos 1): ";
cin>>newNodeLoc;
while((newNodeLoc<=0 || newNodeLoc>initialCount))
{
cout<<"New position must be greater than 1 and less than " << initialCount+1 <<": ";
cin>>newNodeLoc;
}
newNodeLoc--;
insertNode(head, newNodeVal, newNodeLoc);
cout<<"\nHere is the updated linked list: "<<endl;
printList(head);
/// SEARCH
cout<<"\nEnter the number that you want to search for in the list: ";
cin>>searchVal;
cout<<endl;
initialCount++;
cout<<initialCount;
searchList(head,searchVal,initialCount);
return 0;
}
void printList(Node* head)
{
Node *n = head;
cout<<n->data<<endl;
while(n->next != nullptr) // print out all nodes values'
{
cout << n->next->data<<endl;
n = n->next;
}
}
void append(Node*& head, int val)
{
Node* temp = new Node;
temp->data = val;
temp->next = nullptr;
Node* ptr = head;
if(head == nullptr) // check if list is empty
{
head = temp;
}
else
{
while(ptr->next != nullptr) // if list isn't empty, get to last element set it equal to temp
{
ptr = ptr->next;
}
if(ptr->next == nullptr)
{
ptr->next = temp;
}
}
delete temp;
temp = nullptr;
}
void insertNode(Node*& head, int val, int loc)
{
Node* temp = new Node;
Node* prevLoc = new Node;
Node* curr = head;
temp->data = val;
int tempPos = 0;
while(curr->next != nullptr && tempPos != loc)
{
prevLoc = curr;
curr = curr->next;
tempPos++;
}
prevLoc->next = temp;
temp->next = curr;
delete temp;
delete prevLoc;
curr = nullptr;
prevLoc = nullptr;
}
void searchList(Node* head, int sVal, int iCount)
{
Node* curr = head;
int index=0;
while(curr->next != nullptr && curr->next->data != sVal)
{
curr = curr->next;
index++;
}
cout<<index;
cout<<iCount;
if(index != iCount)
{
cout<<"Number found at index "<<index<<" in the linked list!";
}
if(index-1 == iCount)
cout<<"Number could not be found in this linked list.";
delete curr;
curr = nullptr;
}
Hi there! I'm trying to implement append/prntlist/insertnode/search functions and I'm getting extremely inconsistent compiling results. Sometimes the code will run fine. Sometimes the code will randomly break. Other times it'll print out numbers on an infinite loop. I'm thinking it's a memory leak somewhere (in append/print functions), but I'm not super confident. It might also be a loop that's breaking the code. Any and all help is appreciated! I understand that the search function doesn't work so you can ignore it. Thank you!
In your append():
delete temp;
temp is your new element, that you've just append()ed to the list. Now that it's a part of the list, it gets immediately deleted. Good-bye!
The next to the last element of your linked list now points to deleted memory. Subsequent attempt to walk the list results in undefined behavior. Subsequent attempts to append more elements to the list will just make things even worse, scribbling over deleteed memory (if it wasn't scribbled over anyway, by the next new) and generally making a major mess of everything.
The memory allocation logic in insert() is similarly flawed. It's even worse. Two news and two deletes. Furthermore, the overall logic is also wrong. Its ostensible purpose is to insert one more element to the list, so it shouldn't be allocating two new nodes, only one will do. Both append() and insert() add one more node to the list; so only one node needs to be newed in both cases.
But the overall problem is erroneous deletions of newed elements, when they should not be newed, and they continue to be used. You cannot use anything after it gets deleted. It's gone. It ceased to exist. It joined the choir-invisible. It's an ex-object. But the shown code erroneously deletes an element after it gets added to the link list and, ostensibly, is still logically a part of the link list.
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.
Basically I want to print the data part of the Linked list which is basically an Integer pointer and I am assigning it an array at the time of creation, I want to print all the values of it how to do so ???
Thank you.
Here is my code
using namespace std;
struct Node{
Node *next;
int *data;
};
class DataLine{
private:
Node *first;
public:
DataLine(){
first=NULL;
}
void create_list(){
Node *temp=new Node;
int i=2;
int dat[5]={12,13,14,13,16};
temp->data=dat;
temp->next=NULL;
if(first==NULL){
//cout<<"hello 1"<<endl;
first=temp;
}
else{
Node *curr=first; //We are now doing trevercing so we are assigning the first to the node because we donot want to move the first bacuse link break if we move the first
while(curr->next!=NULL) //searching end of list
{
curr=curr->next; //Moving to the next node
}
curr->next=temp; //insert node
temp=NULL; //Making the temp enpty to use it for the new purpose
//delete temp;
}
}
void print_list()
{
Node *prnt=first; //We are now again want trevercing so we agin run the node by the new node
while(prnt!=NULL) //Checking the loop will run till it get the null in the node means its address part and data part both are nUll
{
for(int i=0;i<5;i++)
cout<<" ***** The "<<" node is "<<*(prnt->data+i)<<endl; //Printing the data
prnt=prnt->next; //Moving to the next node
}
}
};
int main(){
DataLine dl;
dl.create_list();
dl.print_list();
_getch();
return 0;
}
The idea of your void print_list(void) is correct but you can make it much cleaner, note however I changed your output to print a single node per line (change that back if you want). The structure of a for loop seems, to me, perfect for linked lists and keeps the linked list code our of the body of the loop.
void print_list(void) const
{
for (Node* p = first; p != NULL; p = p->next)
{
for (int i = 0; i < Node::unLength; ++i) std::cout << p->data[i] << ", ";
std::cout << std::endl;
}
}
However, as pointed out in some of the comments, there are other problems in your create list code. The way I would suggest to fix these (for this program) would be to redefine your structure to always hold a fixed number of integers.
struct Node
{
enum { unLength = 5 };
Node* next;
int data[unLength];
};
I have also added here a constant for the length of the array, since its bad practice to have magic numbers floating around your code, what happens if you mistype one of them?
Now in your void create_list() you can go:
void create_list()
{
Node* temp = new Node;
// Set the next node of temp
temp->next = NULL;
// Add some data to temp (we can't just assign the data pointer in C/C++)
int data[Node::unLength] = {0, 1, 2, 3, 4};
for (int i = 0; i < Node::unLength; ++i) temp->data[i] = data[i];
Node *p = first;
while (p != NULL) p = p->next;
p->next = temp;
}
There is no point setting temp to NULL since temp is deleted straight after the function returns. In your previous code you set the pointer in Node to data (temp->data=dat;, this doesn't work either since dat was deleted as soon as the function returned, you need to instead allocate memory and copy the values from dat which is what the for loop in the above code does.
For you class constructor (and destructor) I would suggest:
class DataLine
{
private:
Node* first;
public:
DataLine(void) : first(NULL) {}
~DataLine(void)
{
while (first != NULL)
{
Node *temp = first->next;
delete first;
first = temp;
}
}
You had the right idea, but there are a few subtle things about C/C++ that aren't obvious in higher level languages, such as copying arrays and the scope of variables.
If you are using C++ however, I would really suggest not worrying about linked lists, just create a std::vector, in C++ 11 something like the following might work (untested):
#include <vector>
#include <array>
int main(int argc, char** argv)
{
std::vector< std::array<int, 5> > myData;
myData.push_back({0, 1, 2, 3, 4});
myData.push_back({0, 1, 2, 3, 4});
myData.push_back({0, 1, 2, 3, 4});
for (const auto& i : myData)
{
for (int j : i) std::cout << j << ", ";
std::cout << std::endl;
}
return 0;
}