I'm trying to add elements to a list, but can't figure out why the push_back method is repeating the last added element. To illustrate:
Each node object consists of a data and head field. In the code below, I iterate through an array of ints, create a new node to store each int, and push_back the element to the list L. The repeated node is always the last one added to the list (in the picture above when iteratror i=1)
void addElements(std::list<node>& L, int arr[],std::list<node>::iterator Itor,int size){ //array decays to pointer
for (int i=1;i<size;i++){
node* n = new node;
n->data = arr[i];
n->head = Itor->head; //head of the first element in the list
L.push_back(*n);
}
}
I included the complete code of the disjoint data structure below. I read on cplusplus.com that push_back increases the container size by 1. So I'm a little perplexed why an extra node is being added to the list.
#include <iostream>
#include <list>
struct node{
int data;
node* head;
};
void makeSet(std::list<node>& L,int arr[]){ //asterick is before the variable name
node *headNode = new node;
headNode->data = arr[0]; //representative node
headNode->head = headNode; //point to itself
L.push_back(*headNode);
}
void addElements(std::list<node>& L, int arr[],std::list<node>::iterator Itor,int size){ //array decays to pointer
for (int i=1;i<size;i++){
node* n = new node;
n->data = arr[i];
n->head = Itor->head; //head of the first element in the list
L.push_back(*n);
}
}
int findSet(node* element){
return element->head->data;
}
int main(int argc, const char * argv[]) {
std::list<node>List;
std::list<node>::iterator Itor;
int dataArr[]={1,2,3,4,5};
int size = sizeof(dataArr)/sizeof(dataArr[0]);
Itor = List.begin();
makeSet(List,dataArr);
addElements(List,dataArr,Itor,size);
for (Itor = List.begin();Itor!=List.end();Itor++){
std::cout << Itor->data << std::endl;
}
}
Note that the size of the list in your example is 2. This means only nodes 0 and 1 are valid. This extra duplicate link is likely a Sentinel Value.
Often you'll find linked lists terminate with a null pointer, but it's just as easy to define the end of the list as a link that points to itself. This may have additional advantages, such as providing a one-past-the-end link to return as list::end.
Whatever its benefits, it is outside the bounds of the list so best that you not mess with it.
Related
In an article about linked list, it is said that accessing a random element is not allowed and to access a certain node we need to traverse it from the head node
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node* next;
};
// This function prints contents of linked list
// starting from the given node
void printList(Node* n)
{
while (n != NULL) {
cout << n->data << " ";
n = n->next;
}
}
// Driver code
int main()
{
Node* head = NULL;
Node* second = NULL;
Node* third = NULL;
// allocate 3 nodes in the heap
head = new Node();
second = new Node();
third = new Node();
head->data = 1; // assign data in first node
head->next = second; // Link first node with second
second->data = 2; // assign data to second node
second->next = third;
third->data = 3; // assign data to third node
third->next = NULL;
printList(head);
return 0;
}
This was the example code on traversing a linked list and printing it's values
If i change the argument of printList() to second, it would still work
My question is, did i misinterpret the meaning to "access an element of a linkedlist", what does an element of a linkedlist contain?
I think you overinterpreted the article. You should store in your program only pointer to the first element (head) and in that case, you are not able to access n-th element directly. You need to find it "manually" by jumping to "next" element (n-1) times.
It doesn't mean that you are not able to access n-th element if you have pointer to that element.
accessing a random element is not allowed
That statement isn't quite precise about linked lists.
What is true is that given a linked list (and nothing more), it isn't possible find an element at any given index in constant time.
However, if you have an iterator or a reference to an element of a list, you can access that element in constant time through the iterator / reference.
To clear your confusion we probably should add the example of an array
Say we have an array
[1,2,3,4,5]
and a linkedlist
1->2->3->4->5
now if you want to access the 5th element in both the data structure what can you do
for array you just have to access the array[4] to get the element which is a O(1) operation to get the element
but for linkedList this doesn't happen
for accessing the 5th element of the linkedList you ll have to iterate in a manner like this
int element = 5;
while(element--){
head = head->next;
}
and when the loop ends you ll get your element
I am writing a code to delete a node from a linked list when only the pointer to the node is given and the head node is not given
/*
struct Node {
int data;
struct Node *next;
Node(int x) {
data = x;
next = NULL;
}
}*head;
*/
// This function should delete node from linked list. The function
// may assume that node exists in linked list and is not last node
// node: reference to the node which is to be deleted
void deleteNode(Node *node)
{
node=(node->next);
}
does not delete the present pointer in the list, but,
/*
struct Node {
int data;
struct Node *next;
Node(int x) {
data = x;
next = NULL;
}
}*head;
*/
// This function should delete node from linked list. The function
// may assume that node exists in linked list and is not last node
// node: reference to the node which is to be deleted
void deleteNode(Node *node)
{
*node=*(node->next);
}
Deletes the node from the linked list
Why? what is the difference between the approach?
let's take a simpler example with integers instead of nodes:
void Modify_1 (int *piVal, int *piNewVal)
{
//piVal has adresse of i passed as argument
// similar to node = (node->next);
piVal = piNewVal; // This change just the VALUE of the pointer passed as argument !
//piVal has adresse of j now
}
void Modify_2 (int *piVal)
{
// similar to *node=*(node->next);
*piVal = 0; // This change de content of pointer
}
int main ()
{
int i = 3;
int j = 5;
Modify_1 (&i, &j);
cout << i << endl; // This print 3 !
Modify_2 (&i);
cout << i << endl; // This print 0
return 0;
}
piVal is a pointer that contains i address VALUE. Exemple : 0x00bcfdb4
This address is passed as a value (0x00bcfdb4) if you want to function.
As long as you do not write *piVal, you are not going to change the pointed content but just the VALUE of the address.
If you want to change the pointer, you need an **int (in your case **node)
void Modify_3 (int **piVal, int *piNewVal)
{
*piVal = piNewVal; // this change de pointer adresse
}
int main ()
{
int x = 5;
int *pi = &x;
Modify_3 (&pi, &x);
cout << *pi << endl; // This print 5
}
Assigning to a (non-reference) argument of a function has no effect outside that function.
(The most important thing to learn about pointers is that there is nothing special about pointers.)
It's the same as how
void f(int x) { x = 1000; }
int main()
{
int x = 0;
f(x);
std::cout << x << std::endl;
}
will print 0, not 1000.
Thus, your first attempt does not modify anything and has no observable effect.
Your second attempt also has a problem - it copies the next node but doesn't delete it.
If your nodes are dynamically alloacted, and they usually are, this is a memory leak.
You need something like this:
void deleteNode(Node *node)
{
Node* old = node->next;
*node = *(node->next);
delete old;
}
It's a bit unconventional to modify a list by copying nodes, though, since it is very inefficent if the node's data is big.
Usually, you update the links in the list, but in order to do that you need to know what the previous node is.
To delete a node from a linked list when only the pointer to the node is given - that's possible only in doubly linked list or in indexed list. The nature of list itself says that you have to modify another node to remove one from existing chain.
In first case node contains pointer to previous node and cost is O(1), while with indexed list you have index (key) and access to mapping\indexing mechanism, cost of getting previous node depends on method used. For the last reason indexed lists are sometimes implemented as doubly-linked.
I have to face this problem: I have a doubly linked list and I have to make insertion at the tail. My list is made of Nodes such as
struct Node {
int val; // contains the value
Node * next; // pointer to the next element in the list
Node * prev; // pointer to the previous element in the list
};
and my class list declares only
private:
Node * first; // Pointer to the first (if any) element in the list
at first.
Now, I wrote such a method for inserting:
void List::insert(int n){
Node * tmp = new Node;
tmp->val = n;
tmp->next = 0;
if (!first) {
first = tmp;
}
else {
Node * p = new Node;
p = first;
while (p->next) {
p = p->next;
}
p->next = tmp;
tmp->prev = p;
}
};
and if I take several numbers from cin (say, 1 2 3 4), I call insert but I end up not having all the elements I wanted to store. I have only first and tmp, which contains the last number from the input (e.g. 4).
I struggle to figure out what's wrong - my first suggestion is variable scope.
Or is there anything wrong during the pointer setting?
OBS: I'd use a tail pointer of course, but the aim is traversing the list.
Any feedback is really appreciated.
I have to develop a library function for a phonebook which uses lists.
This function has to delete the nth entry from the list.
It is a linked list,and the entries are structs which contain the strings name,srnm,nmbr,addr,the int number and the next pointer.
Every time I call the function,however,VS gives me lot of exceptions and triggered breakpoints,and says I've corrupted the heap.
I have no idea of where I could have made this mistake that corrupts the heap.Please Help.
Here's what I've done so far :
typedef struct list {
char name[20];
char srnm[20];
char nmbr[20];
char addr[20];
unsigned int number;/*Contact index*/
struct list *next;
} entry;
static unsigned int count = 0;
static entry *hol = NULL;/*pointer to the head of the list*/
int delete_contact(unsigned int n) {
int i=0,k=0;
if(n>count) return -1;
hol[n-1].next = hol[n-1].next->next;
for(i=n;i<count;i++) {
hol[i]=hol[i+1];
}
for(i=n;i<count;i++)
hol[i].number = hol[i].number-1; /*Updates the contact index*/
count--; /*Updates the global variable that gives the number of contacts */
return 0;
}
Suggested solution
hol is a pointer, so, hol[n-1] etc. might not refer to a entry struct in memory, consider when n = 0. Either way, this is not how you should access different entries in your list structure.
For a singly-linked list you have to consider 3 cases,
If n = 0 (i.e. the first entry) is being deleted
If the entry to be deleted is somewhere inside the list
If the entry is the last entry in the list.
It is my understanding that number is the index of the list entry and that you've used dynamic memory allocation for the list entries. Furthermore, since you appear to be using the C89 standard (which does not allow loop variable initialization) I have adapted the code below as best as I could to C89, but I do not use that standard myself:
int delete_contact(unsigned int n) {
int i = 0;
int k = 0;
// Check if the index refers to an element not included in the list
if (n > count) { return -1; }
entry* tmp = hol;
if (n == count - 1) {
// Iterate to the last entry
while (tmp->next) {
tmp = tmp->next;
}
free(tmp); // Free the list entry
// Decrement the global counter keeping track of the
// amount of list elements
count--;
// No need to edit the contact indexes
return;
}
entry* remaining_list = hol;
if (n == 0) {
// Free the head of the list
hol = hol->next;
remaining_list = hol;
free(tmp); // tmp points to the head of the list already
} else {
// The list entry is somewhere inside the list
int idx = 0;
// Iterate until tmp points to the n-1:th entry
while (idx < n - 1) {
tmp = tmp->next;
idx++;
}
entry *to_be_freed = tmp->next; // n:th entry
tmp->next = tmp->next->next;
remaining_list = tmp->next;
free(to_be_freed);
}
// Decrement the contact index on all the remaining entries
while (remaining_list) {
remaining_list->number--;
remaining_list = remaining_list->next;
}
// Decrement the global counter keeping track of the
// amount of list elements
count--;
return 0;
}
Tips
You'd be better served by creating a more expressive list interface, possibly one that isn't bound to the values stored inside it. That way you could create a
list_size()
function and remove the global counter.
Here is a little something to get you started:
typedef struct node {
void* value;
struct node* next;
} node;
typedef struct list {
node* head;
node* tail;
size_t len;
} list;
Reference material
Linked list basics
Linked list exercises
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;
}