I'm trying to create a function which take in a Vector of Tokens, which is a type defined by my professor, and enter each element of the vector into the linked list, I return the head of the first element. The cout statement in the last part of new_list shows that I am indeed inserting the elements of the vector into the linked list. So when I type in:
new a 9 2 3
9 2 3 are being inserted
The print_list_cmd is defined by my professor and is supposed out the list that I created by calling new a,
so,
print a should return
9 2 3
but when I type print I only get the last element of the linked list which is 3.
I have two questions my code is not very elegant is there a better way to insert a vector of tokens into a linked list? Two why is the print command only returning the last element in the linked list? Also there is a lexer class that tokenizes the input but it's alot of code so I didn't insert it, if it's helpful or you need me to insert it I will.
struct Node {
int key;
Node* next;
Node(int k=0, Node* n=NULL) : key(k), next(n) {};
};
Node* new_list(const vector<Token>& tok_vec){
//int key;
Node *head;
Node *newHead;
Node *headPointer = NULL;
newHead = new Node;
newHead -> next = NULL;
head = NULL;
for(unsigned int i = 0 ; i < tok_vec.size() ; i++){
// newHead -> key = tok_vec.at(i).value;
string myStream = tok_vec.at(i).value;
istringstream buffer(myStream);
int value;
buffer >> value;
newHead -> key = value;
if(!head){
head = newHead;
}else{
headPointer = newHead;
while(headPointer -> next){
headPointer = headPointer -> next;
headPointer -> next = newHead;
}
}
cout << head->key << endl;
}
return head->key;
}
void print_list_cmd(Lexer lex){
Token tok = lex.next_token();
if (tok.type != IDENT || lex.has_more_token())
throw runtime_error("SYNTAX: print listname");
if (list_table.find(tok.value) == list_table.end())
throw runtime_error(tok.value + " not defined or already destroyed");
print_list(list_table[tok.value]);
}
Looking at your code, you don't return the head of the list, you return the value from the head Node:
return head->key;
instead of:
return head;
Also, most effective way to insert new items into the list would be inserting them at the head:
/// inserts node at the head of the list and returns the new head;
Node* insertNode(int key, Node* head) {
Node* newHead = new Node;
newHead->key = key;
newHead->next = head;
return newHead;
}
you could use that as:
Node* new_list(const vector<Token>& tok_vec){
Node* head = NULL;
for(unsigned int i = 0 ; i < tok_vec.size() ; i++){
string myStream = tok_vec.at(i).value;
istringstream buffer(myStream);
int value;
buffer >> value;
head = insertNode(value, head);
///
}
return head;
}
UPDATE. the resulting list will be backwards with regard to the input, so you would have to reverse it. One of the possibilities would be to create another list from the original one, so that at the end the last element of the old list will be the head of the new one:
Node* reverse(Node* list) {
Node* reversed = NULL;
while (list!=NULL) {
Node* nextNode = list;
list = list->next;
nextNode->next = reversed;
reversed = nextNode;
}
return reversed;
}
Related
I've been learning Data Structures and currently working with Linked List. I'm trying to add a node at the end of the linked list but not able to figure out the correct logic for it. I've tried inserting a node at the beginning and it works fine.
This is the code:
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
int data;
Node* next;
};
Node* head; // global
void Insert(int data) {
Node* temp = new Node();
temp -> data = data;
temp -> next = head;
head = temp;
} // insert an integer
void Print(){
Node* temp = head;
cout << "List is: ";
while (temp != NULL) {
cout << temp -> data << " ";
temp = temp -> next;
}
cout << endl;
} // print all elements in the list
void Delete(int n){
Node* temp1 = head;
if(n == 1) {
head = temp1 -> next; // head now points to second node
delete temp1;
return;
}
int i;
for(i = 0; i < n-2; i++)
temp1 = temp1 -> next;
// temp1 points to (n-1)th Node
Node* temp2 = temp1 -> next; // nth Node
temp1 -> next = temp2 -> next; // (n+1)th Node
delete temp2; // delete temp2
} // Delete node at position n
int main() {
head = NULL; // empty list
Insert(2);
Insert(4);
Insert(6);
Insert(5); // List: 2,4,6,5
Print();
int n;
cout << "Enter a postion: " << endl;
cin >> n;
Delete(n);
Print();
}
This code deletes a node at nth position. The node here is being adding from the beginning and I'm trying to figure out the logic to insert it from the end.
Any suggestions and advises on this will be very helpful.
Thanking you in advance.
Play with the code.
void insert_end(int data) {
Node* temp = new Node(); // 1
temp->data = data;
temp -> next = nullptr;
Node* n = head;
if (!n) { // 2
head = temp;
return;
}
while(n->next) { // 3
n = n->next;
}
n->next = temp;
}
Short explanation of the method:
1: You create a new Node and set the data.
2: Check if the list is empty. If it is, insert the new element at the head.
3: If the list is not empty, you read the next element of the list until you have the last Node in your list. If you would write while(n)... here, you would get to the end of the list, meaning a nullptr and the code would break.
I am trying to finish up a assignment for my data structures c++ class. I have to define a double linked list of functions(like insert() size() remove() ) that was provided by my instructor. The instructor also includes the main file which runs tests on my code to see if it works.
I'm receiving his error message:
* Starting dlist tests *
Checking empty list...
FAILED: size of empty list is != 0.
I tried to rewrite the definition of the size() and insert() function and Im not understanding why im getting his error.
my instructors test code:
bool test_empty() {
std::cout << "Checking empty list...\n";
dlist e;
if(!verify(e))
return false;
if(e.size() != 0) {
std::cout << "FAILED: size of empty list is != 0.\n";
return false;
}
if(!e.empty()) {
std::cout << "FAILED: empty list is not .empty().\n";
return false;
}
return true;
}
my code for implementations:
void insert(node *previous, int value){
if(previous == nullptr){
node* n = new node;
n->value = value;
n->prev = previous;
n->next = nullptr;
return;
}
node* n = _head; //made a pointer to start at the head
while( n!= previous )//make n go down the list until it hits previous
{n = n->next;}
node* store_next = n->next; //store the address of the prev pointer of the next node
node* a = new node;//create the node that will be inserted
a->value = value;
n->next = a;// the pointer n points to the new node
a->prev = n; //the prev in the new node points to the previous
a->next = store_next; //the next in the new node points to the next node
store_next->prev = a; //the next node's prev points to the new inserted node
}
int size() const{
node* n = _head;
int size = 0;
while(n != nullptr){
size++;
n = n -> next;
}
return size;
}
Heres my default constructor and double linked list struct that my professor requires I use
class dlist {
public:
dlist() {
}
struct node {
int value;
node* next;
node* prev;
};
I am trying to create sorted linked list = sorting it while creating it. Idea is simple , insert a node - and check if previous is smaller , if so check previous of previous and so on until it finds its spot. I have created this piece of code.
struct Node{
Node *prev;
Node *next;
int value;
};
struct List{
Node *head = nullptr;
Node *tail = nullptr;
};
Here i created a node , and a "holder" for the list = reference to first and last item of the list.
void insertNode(Node *&head,Node *&tail, int value ){
Node *tmp = new Node;
tmp -> prev = nullptr;
tmp -> next = nullptr;
tmp -> value = value;
head = tmp;
tail = tmp;
}
this function checks if list is empty , if yes , it inserts node to head and tail ( e.g head = tail = there is only one node in list );
What troubles me is function to insert a node
void insertIt(Node *&head , Node *&tail , int value){
if( head == nullptr){
insertNode(head,tail,value);
}
else{
Node *tmp = new Node;
tmp -> value = value;
if( value < tail -> value){
while(value < tail -> prev -> value){
tail = tail -> prev;
if( tail -> prev == nullptr){
tmp -> next = head;
tmp -> prev = nullptr;
head -> prev = tmp;
head = tmp;
return;
}
}
tail -> prev -> next = tmp;
tmp -> prev = tail -> prev;
tmp -> next = tail;
tail -> prev = tmp;
}else{
tmp -> next = nullptr;
tmp ->prev = tail;
tail -> next = tmp;
tail = tmp;
}
}
}
If list is empty , it invokes insertNode() , if value of the node is smaller than value of previous node , it crawls the list to find its spot.
This piece code works only if the first node inserted is also a smallest node there will be. e.g
insertIt(list.head , list.tail , -1);
insertIt(list.head , list.tail , 0);
insertIt(list.head , list.tail , 7);
insertIt(list.head , list.tail , 1);
insertIt(list.head , list.tail , 2);
insertIt(list head , list.tail , 2);
works and if i print the list it is nice sorted. but
insertIt(list.head , list.tail , -2);
insertIt(list.head , list.tail , -1);
insertIt(list.head , list.tail , 7);
insertIt(list.head , list.tail , 1);
insertIt(list.head , list.tail , 2);
insertIt(list.head , list.tail , 2);
the first node isnt the smallest node , it crashes the program. I thought it was i was comparing a value to nullptr so i added the piece of code which you can see in insertIt() function and that is
if( tail -> prev == nullptr){
tmp -> next = head;
tmp -> prev = nullptr;
head -> prev = tmp;
head = tmp;
return;
}
This checks if the node is a head , and swap head with new node , making new node new head.
Why does it crashes code? I failed to find a reasonable answer to this. Also , how could I improve my "algorithm" to make it more effective?
When iterating over the list to find the position to insert a new node, you do:
tail = tail -> prev;
But the tail variable is passed by a reference, that is you modify the tail member of yout List object, thus destroying its consistency.
Use another temporary variable, named, say current or position to walk along the list, and don't modify tail unless you're appending a new node at the end of the list.
EDIT example approach
struct Node {
Node(int val);
Node *prev;
Node *next;
int value;
};
struct List{
List() : head(nullptr), tail(nullptr) {}
void insert(int value);
Node *head;
Node *tail;
};
Node::Node(int val) :
value(val), next(nullptr), prev(nullptr)
{
}
void List::insert(int value) {
Node *tmp = new Node(value);
if(head == nullptr) {
head = tmp;
tail = tmp;
return;
}
Node *pos; // find the node greater or equal to 'value'
for(pos = head; pos && pos->value < value; pos = pos->next)
;
if(pos) { // appropriate pos found - insert before
tmp->next = pos;
tmp->prev = pos->prev;
tmp->next->prev = tmp;
if(tmp->prev) // there is some predecessor
tmp->prev->next = tmp;
else
head = tmp; // making a new first node
} else { // pos not found - append at the end
tmp->next = nullptr;
tmp->prev = tail;
tail->next = tmp;
tail = tmp;
}
}
You want to do two things: find position in list where new node belongs AND insert new node at a position. So, write two functions, one to do each task. Then you can test and debug them separately before integrating. This will be much more straight forward. Further reccomendation: write unit tests for each function, before implementing the functions.
/** Find node with largest value less than given
Assumes sorted list exist. If empty, throws exception
*/
Node & FindLessThan( int value );
/** Inset new node after given with value */
InsertAfter( Node& n, int value );
It will also be handy to have a function to insert the first node, if the list is empty,
/** Insert first node with value
#return true if list empty */
bool InsertFirstNode( int value );
The point is that you should hide all the pointer twiddling in functions that can be tested, so you can write a comprehensible mainline that will work first time:
if( ! InsertFirstNode( value ) )
InsertAfter( FindLessThan( value ), value );
Since you are using C++, make your list a class and the functions members.
Implementation details: You have to worry about special cases: new value goes before head or after tail. So I suggest using an enumeration to handle these.
/** Special cases for placing a new node */
enum class eFind
{
list_empty, // the list was empty
before_first, // the new node goes before the first node in list
before_node, // the new node goes before the specified node
after_last, // the new node goes after the last node in the list
};
/** Find node with smallest value greater than given
#param[out] place eFind enumeration, one of list_empty,before_first,before_node,after_last
#param[in] value being inserted
#return n node before which value should be placed
Assumes sorted list exist.
*/
Node * FindSmallestGreaterThan( eFind & place, int value )
It also turns out to be slightly easier ( less code ) to do an InsertBefore rather than InsertAfter. You can see the code running at cpp.sh/4xitp or the github gist
1. You can't initialize members inside a structure :
struct List
{
Node *head;
Node *tail;
};
2.(a) Prototypes of functions insertIt and insertNode are wrong.You are passing head and tail using pass by reference.It should be as follows :
void insertIt(Node * head ,Node * tail ,int value)
void insertNode(Node * head,Node * tail,int value)
2.(b) When you create a node in else part you should set the next and prev pointers of your new node to NULL :
tmp->prev=NULL;
tmp->next=NULL;
2.(c) As you have passed tail using pass by reference whatever changes you make inside while loop on tail are reflected in program.Hence use temporary pointer of type Node.
3. Also the design you are using is not good.Hence I would advice you to change it.This is my implementation of linked list :
main()
{
struct List Q;
Initialize_list(&Q);
Insert_it(&Q,12);
}
void Initialize_list(struct List *L)
{
L->head=NULL;
L->tail=NULL;
}
The problem is the check value < tail->prev->value in the while loop head. This does not check that tail->prev != nullptr is true. This is a problem for the case that head == tail and value < head->value. If head != tail, your code would indeed work, because the first time value < tail->prev->value is evaluated, tail->prev != nullptr is true and the case head->next == tail would be caught by the code in the loop body.
The correct check would be tail->prev != nullptr && value < tail->prev->value. This first checks that tail->prev can be derefenced.
Then you may end with tail->prev == nullptr after finishing the while loop (due to the new condition). The check for that can be moved out of the loop, leading to the following code:
while (tail->prev != nullptr && value < tail->prev->value) {
tail = tail->prev;
}
if (tail->prev == nullptr) {
// Prepend node to the list
return;
}
// Insert node in front of tail
EDIT: You can still check the condition tail->prev == nullptr within the loop; the check after the loop would then only be useful to catch the case head == tail && value < head->value. Not doing the check in the loop has the benefit of a shorter and (in my opinion) mode readable code.
This might be the code you're looking for ;-) You can run it as-is in VS2013. It simplifies your insert function to just a few if-statements. And that can be further simplified with use of terminal elements for head & tail.
I hope this helps :-)
struct Node
{
int value; Node *prev, *next;
};
struct DoublyLinkedSortedList
{
Node *head = nullptr, *tail = nullptr;
void insert(int value)
{
// Find first node bigger then the new element, or get to the end of the list
Node* node = head;
while (node && node->value <= value) { node = node->next; }
// Once found, insert your new element before the currently pointed node, or at the end of the list
node = new Node{ value, node?node->prev:tail, node };
if (node->prev) node->prev->next = node; else head = node;
if (node->next) node->next->prev = node; else tail = node;
}
};
#include <climits>
#include <iostream>
using namespace std;
int main()
{
cout << "This is a DoublyLinkedList test." << endl << endl;
// test the list
DoublyLinkedSortedList list;
list.insert(234);
list.insert(INT_MIN);
list.insert(17);
list.insert(1);
list.insert(INT_MAX);
list.insert(-34);
list.insert(3);
list.insert(INT_MAX);
list.insert(INT_MIN);
list.insert(9);
list.insert(7);
// print nodes in order;
cout << "This are the contents of the linked list front to back" << endl << endl;
for (Node* curr = list.head; curr != nullptr; curr = curr->next) { cout << curr->value << "; "; }
cout << endl << endl << "This are the contents of the linked list back to front" << endl << endl;
for (Node* curr = list.tail; curr != nullptr; curr = curr->prev) { cout << curr->value << "; "; }
cout << endl << endl;
system("pause");
}
struct Node{
string val;
Node* next;
};
Node* makeList ()
{
string current;
Node* n;
Node* head= NULL;
Node* temp = n;
while(cin>>current && !cin.fail())
{
n = new Node;
n->val = current;
temp ->next = n;
temp = temp -> next;
}
n->next = NULL;
return n;
}
I am trying to learn about linked lists, and this function makeList() is supposed to create and return a linked list using input from a list of strings. To be honest, I'm kind of lost. Any help would be greatly appreciated.
First of all, you are returning the last node of the linked list.. I think you should return the head and assign it to the first Node.
Secondly you are using cin.fail() for a string which I think should not be done. cin.fail() will work if there is a data mismatch and for string I think it is rare.
The function would look somewhat like:
Node* makeList ()
{
string current;
Node* n;
Node* head= NULL;
Node* temp = n;
while(cin>>current && !cin.fail())
{
if(current == "0")
break;
n = new Node;
n->val = current;
temp ->next = n;
temp = temp -> next;
if(!head)
head = n;
}
n->next = NULL;
return head;
}
First of all, since your temp represents the last element I would put it to NULL at the beginning (nullptr is more in the spirit of C++, so I'll use it in the text that comes).
After that in a while loop ,when you are adding a new element, you should write n->next=nullptr,since the pointer next of the new element(if you're always adding it to the back of the list) will always point to nullptr. In your implementation your new element n is always pointing to itself.Later on in your while loop you need to check if head==nullptr, if that's true than you should assign head to the new element that you made head=n. If head is not equal to nullptr then you need to add your element n to the back temp->next=n. An at the and of the loop you should assign the n element as last-temp=n (that has to be outside of the else block since it is done in both of the above mentioned cases).
I'm afraid answers above all got some bugs...
Node *make_link_list_from_input(){
string value;
Node *head = nullptr;
Node *current = nullptr;
Node *last = nullptr;
while (cin >> value){
current = new Node();
if(head== nullptr){
head = current;
}
if(last!= nullptr){
last->next=current;
}
last=current;
}
if(last != nullptr) {
last->next = nullptr;
}
return head;
}
I was writing a simple function to insert at the end of a linked list on C++, but finally it only shows the first data. I can't figure what's wrong. This is the function:
void InsertAtEnd (node* &firstNode, string name){
node* temp=firstNode;
while(temp!=NULL) temp=temp->next;
temp = new node;
temp->data=name;
temp->next=NULL;
if(firstNode==NULL) firstNode=temp;
}
What you wrote is:
if firstNode is null, it's replaced with the single node temp which
has no next node (and nobody's next is temp)
Else, if firstNode is not null, nothing happens, except that the temp
node is allocated and leaked.
Below is a more correct code:
void insertAtEnd(node* &first, string name) {
// create node
node* temp = new node;
temp->data = name;
temp->next = NULL;
if(!first) { // empty list becomes the new node
first = temp;
return;
} else { // find last and link the new node
node* last = first;
while(last->next) last=last->next;
last->next = temp;
}
}
Also, I would suggest adding a constructor to node:
struct node {
std::string data;
node* next;
node(const std::string & val, node* n = 0) : data(val), next(n) {}
node(node* n = 0) : next(n) {}
};
Which enables you to create the temp node like this:
node* temp = new node(name);
You've made two fundamental mistakes:
As you scroll through the list, you roll off the last element and start constructing in the void behind it. Finding the first NULL past the last element is useless. You must find the last element itself (one that has its 'next' equal NULL). Iterate over temp->next, not temp.
If you want to append the element at the end, you must overwrite the last pointer's NULL with its address. Instead, you write the new element at the beginning of the list.
void InsertAtEnd (node* &firstNode, string name)
{
node* newnode = new node;
newnode->data=name;
newnode->next=NULL;
if(firstNode == NULL)
{
firstNode=newnode;
}
else
{
node* last=firstNode;
while(last->next != NULL) last=last->next;
last->next = newnode;
}
}
Note, this gets a bit neater if you make sure never to feed NULL but have all lists always initialized with at least one element. Also, inserting at the beginning of list is much easier than appending at the end: newnode->next=firstNode; firstNode=newnode.
The last element in your list never has it's next pointer set to the new element in the list.
The problem is that you are replacing the head of the linked list with the new element, and in the process losing the reference to the actual list.
To insert at the end, you want to change the while condition to:
while(temp->next != null)
After the loop, temp will point to the last element in the list. Then create a new node:
node* newNode = new node;
newNode->data = name;
newNode->next = NULL;
Then change temps next to this new node:
temp->next = newNode;
You also do not need to pass firstNode as a reference, unless you want NULL to be treated as a linked list with length 0. In that case, you will need to significantly modify your method so it can handle the case where firstNode is NULL separately, as in that case you cannot evaluate firstNode->next without a segmentation fault.
If you don't want to use reference pointer, you could use pointer to pointer. My complete code goes like below:
void insertAtEnd(struct node **p,int new_data)
{
struct node *new_node=(struct node *)malloc(sizeof(struct node));
new_node->data=new_data;
new_node->next=NULL;
if((*p)==NULL)//if list is empty
{
*p=new_node;
return;
}
struct node* last=*p;//initailly points to the 1st node
while((last)->next != NULL)//traverse till the last node
last=last->next;
last->next=new_node;
}
void printlist(struct node *node)
{
while(node != NULL);
{
printf("%d->",node->data);
node=node->next;
}
}
int main()
{
struct node *root=NULL;
insertAtEnd(&root,1);
insertAtEnd(&root,2);
insertAtEnd(&root,3);
insertAtEnd(&root,4);
insertAtEnd(&root,5);
printlist(root);
return 0;
}
Understanding the need of the below two variables is key to understanding the problem:
struct node **p: Because we need to link it from the root node created in the main.
struct node* last: Because if not used, the original content will be changed with the contents of the next node inside the while loop. In the end only 2 elements will be printed, the last 2 nodes, which is not desired.
void addlast ( int a)
{
node* temp = new node;
temp->data = a;
temp->next = NULL;
temp->prev=NULL;
if(count == maxnum)
{
top = temp;
count++;
}
else
{
node* last = top;
while(last->next)
last=last->next;
last->next = temp;
}
}
#include <bits/stdc++.h>
using namespace std;
class Node
{
public:
int data;
Node *next;
};
void append(Node *first, int n)
{
Node *foo = new Node();
foo->data = n;
foo->next = NULL;
if (first == NULL)
{
first = foo;
}
else
{
Node *last = first;
while (last->next)
last = last->next;
last->next = foo;
}
}
void printList(Node *first)
{
while (first->next != NULL)
{
first = first->next;
cout << first->data << ' ';
}
}
int main()
{
Node *node = new Node();
append(node, 4);
append(node, 10);
append(node, 7);
printList(node);
return 0;
}
Output: 4 10 7
You can use this code:
void insertAtEnd(Node* firstNode, string name)
{
Node* newn = new Node; //create new node
while( firstNode->next != NULL ) //find the last element in yur list
firstNode = firstNode->next; //he is the one that points to NULL
firstNode->next = newn; //make it to point to the new element
newn->next = NULL; //make your new element to be the last (NULL)
newn->data = name; //assign data.
}
void InsertAtEnd (node* &firstNode, string name){
node* temp=firstNode;
while(temp && temp->next!=NULL) temp=temp->next;
node * temp1 = new node;
temp1->data=name;
temp1->next=NULL;
if(temp==NULL)
firstNode=temp1;
else
temp->next= temp1;
}
while loop will return at temp==null in your code instead you need to return last node pointer from while loop like this
while(temp && temp->next!=NULL) temp=temp->next;
and assign a new node to next pointer of the returned temp node will add the data to the tail of linked list.