I have a problem with copying some elements of list into the new one. It has to be done under one condition: elements that can be copied must be from entered range. The problem is that every single element is copied into newlist. Any suggestions? I want to note that my English is not perfect but I hope you gonna get it. Thank you :)
struct Node
{
Node* next;
int data;
};
struct List
{
Node* head;
Lista();
void push(int);
void addafter(int, int);
void delchosen(int);
void pop();
void print();
int count();
Node* find(int);
void pushback(int);
void popback();
void minmax(int&, int&);
List* range(int, int);
};
List::List()
{
head = NULL;
}
void List::push(int value)
{
Node *p = new Node;
p->data = value;
p->next = head;
head = p;
}
List* List::range(int x, int y)
{
Node* e = head;
List* newlist = new List;
while(e)
{
if(e->data > x && e->data <y)
{
newlist->push(e->data);
}
e = e->next;
}
return newlist;
}
int main()
{
List l;
srand(time(NULL));
const int size = 30;
int* arr = new int [size];
for(int i=0; i<size; i++)
{
arr[i]=rand()%20+1;
l.push(arr[i]);
}
l.range(3, 10);
return 0;
}
Didn't think it will be necessary, but I just have edited the code. Every single function works fine excepting this copying.
You never use the new list. That could probably mislead you. For example you could print or watch in the debugger the old list, which is still contain all the values. It happens sometimes with all the programmers, from freshmen to old long-bearded gurus.
Otherwise code should work:
auto newList = l.range(3, 10);
newList->print();
Bonus: General code review.
It would probably be easier to debug and test the code if you fill the list with deterministic values, rather than random content:
for (int i = 0; i < size; i++) {
l.push(i);
}
Most likely you don't need to allocate newlist on the heap. Use stack allocation:
List List::range(int x, int y) const {
...
List newlist;
...
newlist.push(...);
...
return newlist;
}
While it's nice and funny for self-education and various hacking, you should avoid using homebrew linked lists in the serious code. In C++ we tend to use Standard library facilities instead. Something like:
#include <iostream>
#include <iterator>
#include <list>
int main() {
// Construct original list from brace-initializer list
std::list<int> original{ 1, 2, 3, 4, 5, 6, 7 };
// Get the beginning of the new list by advancing
// beginning of the original list by 2 elements
auto begin = original.cbegin();
std::advance(begin, 2);
// Get the end of the new list by advancing
// beginning of the original list by 5 elements
auto end = original.cbegin();
std::advance(end, 5);
// Construct sublist from iterator range
std::list<int> sublist(begin, end);
// Print new list
for (auto&& e : sublist)
std::cout << e << ' '; // prints "3 4 5"
}
Related
I am learning how to program in C++, and have looked at linked lists. I have found many code snippets to get me started.
The code I am playing with is from studytonight. I understand how to insert nodes into a list. But what if I want to create a linked list and fill x-many nodes at once in a loop? The for loop in my main() works fine, but when I try turning it into a function, such as arrayToList(), I am running into problems.
The function would simply use the entries of an array and turn them into the data (like an index) and a second value stored in the node. Obviously, the function needs to return a list to continue any manipulation, like deleting or replacing, etc, but also needs to receive a list as a parameter as the created list inside won't exist outside this function. The call to traverse the list inside the for loop is just to highlight that inside the function that list isn't empty.
I am a little lost as to make the function work, and would appreciate any help regarding a method to iteratively add x-many at once nodes to a linked list. I hope I have explained my problem well enough.
#include <iostream>
#include <stdlib.h>
using namespace std;
struct node
{
int data; // Data
node *prev; // A reference to the previous node
node *next; // A reference to the next node
double x;
};
class Doubly_Linked_List
{
node *front; // points to first node of list
node *end; // points to first las of list
public:
Doubly_Linked_List()
{
front = NULL;
end = NULL;
}
void add_front(int, double );
void forward_traverse();
void arrayToList(int[], int);
};
void Doubly_Linked_List :: add_front(int d, double x)
{
// Creating new node
node *temp;
temp = new node();
temp->data = d;
temp->x = x;
temp->prev = NULL;
temp->next = front;
// List is empty
if(front == NULL)
end = temp;
else
front->prev = temp;
front = temp;
}
void Doubly_Linked_List :: forward_traverse()
{
node *trav;
trav = front;
while(trav != NULL)
{
cout<<trav->data<<" (" << trav->x << " )" << endl;
trav = trav->next;
}
}
void Doubly_Linked_List :: arrayToList(int arr[], int n)
{
Doubly_Linked_List list;
for(int i=n-1; i>=0;i--)
{
cout << i << endl;
list.add_front(arr[i], arr[i]);
list.forward_traverse();
}
}
int main()
{
Doubly_Linked_List list;
int arr[] = { 1, 2, 3, 4, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
// for (int i= 1; i< 10; i++)
// {
// list.add_front(i, i*2);
// }
list.arrayToList(arr, n);
cout << "after filling arrayList " << endl;
list.forward_traverse();
}
For starters the function should be declared like
void arrayToList( const int[], size_t );
and the function can be defined the following way if to take into account this commented statement in main
// list.add_front(i, i*2);
void Doubly_Linked_List :: arrayToList( const int arr[], size_t n )
{
while ( front )
{
node *current = front;
front = front->next;
delete current;
}
end = nullptr;
for ( size_t i = n; i != 0; i-- )
{
add_front( arr[i-1], 2 * arr[i-1] );
}
}
Though it would be better to declare the function at least like
void arrayToList( const std::pair<int, double>[], size_t );
Your arrayToList() is creating and filling a local Doubly_Linked_List object named list, which is a separate object from the list in main(). Creating a local object is fine (it is good for exception safety), but arrayToList() is then discarding that local object and not assigning its data to the object that arrayToList() was actually called on. That is why your call to forward_traverse() in main() does not see anything changed.
Try this instead:
#include <utility>
void Doubly_Linked_List :: arrayToList(int arr[], int n)
{
Doubly_Linked_List list;
for(int i=n-1; i>=0;i--) {
list.add_front(i, arr[i]);
}
// add this
std::swap(front, list.front);
std::swap(end, list.end);
}
Otherwise, get rid of the local list and modify the data in this instead:
void Doubly_Linked_List :: arrayToList(int arr[], int n)
{
// optional: clear the called-on object first, if needed...
// clear(); // <-- add this method to Doubly_Linked_List...
for(int i=n-1; i>=0;i--) {
add_front(i, arr[i]);
}
}
Otherwise, change arrayToList() to be static, and then have it return a new Doubly_Linked_List object (just make sure you also implement a copy constructor, copy assignment operator, and destructor, per the Rule of 3/5/0):
class Doubly_Linked_List
{
...
// implement these!
~Doubly_Linked_List();
Doubly_Linked_List(const Doubly_Linked_List &);
Doubly_Linked_List& operator=(const Doubly_Linked_List &);
// and change this
static Doubly_Linked_List arrayToList(int[], int);
...
};
Doubly_Linked_List Doubly_Linked_List :: arrayToList(int arr[], int n)
{
Doubly_Linked_List list;
for(int i=n-1; i>=0;i--) {
list.add_front(i, arr[i]);
}
return list;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
Doubly_Linked_List list = Doubly_Linked_List::arrayToList(arr, n);
cout << "after filling arrayList " << endl;
list.forward_traverse();
}
This question already has answers here:
Undefined, unspecified and implementation-defined behavior
(9 answers)
Closed 1 year ago.
The node Class is as follow:
class node
{
public:
int data; //the datum
node *next; //a pointer pointing to node data type
};
The PrintList Function is as follow:
void PrintList(node *n)
{ while (n != NULL)
{
cout << n->data << endl;
n = n->next;
}
}
If I try running it I get all three values (1,2,3) but I get an additional number as well which I'm unable to figure out what it represents, Can someone throw light on the same?
int main()
{
node first, second, third;
node *head = &first;
node *tail = &third;
first.data = 1;
first.next = &second;
second.data = 2;
second.next = &third;
third.data = 3;
PrintList(head);
}
I Know it can be fixed with
third.next = NULL;
But I am just curious what does this number represents in output, If I omit the above line
1
2
3
1963060099
As described in the comment by prapin, third.next is not initialized.
C++ has a zero-overhead rule.
Automatically initializing a variable would violate this rule as the value might be initialized (a second time) later on or never even be used.
The value of third.next is just the data that happened to live in the same memory location as third.next does now.
For this reason, it's recommended to always initialize your variables yourself.
It is better to initialize variables & it is better to use nullptr. Like that (See 1-3):
#include <iostream>
class node
{
public:
int data = 0; // 1
node* next = nullptr; // 2
};
void PrintList(node* n)
{
while (n != nullptr) // 3
{
std::cout << n->data << std::endl;
n = n->next;
}
}
int main()
{
node first, second, third;
node* head = &first;
node* tail = &third;
first.data = 1;
first.next = &second;
second.data = 2;
second.next = &third;
third.data = 3;
// third.next points to where?
PrintList(head);
}
Additional note:
I would prefer to use the STL container std::list:
#include <list>
#include <iostream>
std::list<int> int_list;
void PrintList()
{
for (auto i : int_list)
std::cout << i << std::endl;
}
int main()
{
int_list.push_back(1);
int_list.push_back(2);
int_list.push_back(3);
PrintList();
}
Or in case of list of node objects:
#include <list>
#include <iostream>
class node
{
public:
node(int data) : m_data{ data } {};
int m_data = 0;
// and maybe extra data-members
};
std::list<node> node_list;
void PrintList()
{
for (auto i : node_list)
std::cout << i.m_data << std::endl;
}
int main()
{
node_list.push_back(node(1));
node_list.push_back(node(2));
node_list.push_back(node(3));
PrintList();
}
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.
Hi I'm a beginner at c++ and I'm having trouble solving this issue. I have a linkedlist of nodes and the node contains data of int array and a pointer pointing to the next node.
struct node {
unsigned int numbers[6];
node* next;
};
I also have a class:
private:
ticket* ticketListHead;
ticket* ticketListTail;
and in a public method:
public:
void newNode() {
int arr[6];
for(int i = 0; i < 6; ++i) {
arr[i] = ( std::rand() % 49 ) + 1;
}
node *temp = new node;
temp->numbers=arr;
temp->next=NULL;
}
The problem I believe is with the temp->numbers=arr line as I believe arrays cannot be assigned like that in C++. I'm not sure how to solve the problem in this case and I've tried looking online. Some help would be appreciated!
You're correct about your suspicion that you cannot assign arrays. You could instead use a wrapper type that allows assignment and define
using array = std::array<unsigned,6>; // convenient short hand
struct node {
array numbers;
node* next = nullptr; // ensure next defaults to null
};
when your newNode() method may look like
node* newNode() {
array arr;
for(auto&x: arr)
x = ( std::rand() % 49 ) + 1; // std::rand() cannot be recommended
auto temp = new node;
temp->numbers = arr;
return temp;
}
but you can avoid the temporary object arr altogether by directly writing into the new node's data:
node* newNode() {
auto temp = new node;
for(auto&x: temp->numbers)
x = ( std::rand() % 49 ) + 1; // std::rand() cannot be recommended
return temp;
}
Btw, you shouldn't use std::rand() (see this post and this presentation for reasons why). Instead, use the methods provided by <random>, when your code becomes (see also this answer)
template<typename Generator>
node* newNode(Generator&rng) {
std::uniform_int_distribution<unsigned> uni(1,49);
auto temp = new node;
for(auto&x: temp->numbers)
x = uni(rng); // guaranteed unbiased in [1,49] inclusive
return temp;
}
Welcome to C++, it's awesome that you're taking your first steps into a brighter world! What you'll want to look into are C++ container classes, they'll get you out of the business of managing memory on your own. The closest to your code is std::list and std::vector. I'll neglect random number seeding, that's a complex topic better discussed elsewhere.
#include <vector>
#include <list>
#include <iostream>
#include <random>
#include <limits>
using namespace std;
struct node {
node() : num(6) {
numbers.reserve(num);
for (int i = 0; i < num; ++i)
numbers.push_back(random() % numeric_limits<int>::max());
}
vector<int> numbers;
const int num;
};
int main(int argc, char** argv) {
list<node> nodes;
nodes.push_back(node()); // this replaces your newNode function
nodes.push_back(node()); // another call to better illustrate
for (auto mynode : nodes) {
for (auto mynum : mynode.numbers)
cout << mynum << " ";
cout << endl;
}
}
// Change node struct to this
struct node{
unsigned int *numbers;
node* next;
};
/*
Remember that normal arrays are
implemented through pointers. So you
can use a pointer named numbers in
your node struct and it would behave
as an array.
*/
// Change newNode() to this
void newNode() {
int * arr = new int[6]; //Dynamic memory allocation
for(int i = 0; i < 6; ++i)
{
arr[i] = ( std::rand() % 49 ) + 1;
}
node *temp = new node;
temp->numbers = arr;
temp->next = NULL;
}
U got it ?
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;
}