How to convert linked list to circular linked list? - c++

This is my linked list constructor and insertion function:
template <class T>
List<T>::List() {
_first = nullptr;
}
template <class T>
bool List<T>::insert(const T& item, const int& position) {
Node* ptr = new Node();
// sets node data members
ptr->data = item;
ptr->next = nullptr;
if (position == 1) {
ptr->next = _first;
_first = ptr;
return true;
}
// iterates through list until reached position passed into function
Node* predptr = _first;
for (int i = 0; i < position - 2; i++) {
predptr = predptr->next;
}
// repoints pointer of previous node to it and its pointer to what previous pointer was pointing too
ptr->next = predptr->next;
predptr->next = ptr;
return true;
}
I tried this before but screwed my whole program up and got lost so I just reverted back to what I had working as a starting point.
In my notes it says to traverse the list do this:
(_first != 0) {
ptr = first;
do
{ // process ptr->data
ptr = ptr->next; }
while (ptr != _first);
}
but when I tried changing the code to add this, it just screwed everything up. If I could get pointed in the right direction, i'd appreciate it, thanks!

I do not have your code so it is not tested. But I think this would work. First to make clear, I use zero-based-indices.
For the first part:
Tipp You can pass position as copy because a reference to int has the same size as the int itself. For larger object though it would make sense.
I added a member size function which counts the number of elements. The two asserts are assuring that you do not pass a position which is greater than the number of elements in the list. The second one guarantees that the special case is correctly as it tests if _first == nullptr then position must be zero because no other element has been added before.
// create the node
Node* ptr = new Node();
// just to make sure position is not out of bounds
assert(position <= size);
size++;
// sets node data members
ptr->data = item;
// special case, list is empty
if (_first == nullptr)
{
// position must be 0 if you insert for the first time
assert(position == 0);
ptr->next = ptr;
_first = ptr;
return true;
}
Ok for the second part:
When you have already inserted one element you can loop over all elements. I used a special node which is pointing to _first and started the looping at position -1 this should ensure you get the previous element to reassign the pointers accordingly.
// create special-node pointing to first node
Node* predptr = new Node();
predptr->next = _first;
for (int i = -1; i < position; ++i)
{
if (i == position - 1)
{
ptr->next = predptr->next;
predptr->next = ptr;
}
predptr->next = predptr;
}
return true;
I hope that works for you.

Related

Inserting element into linked list while traversing C++

I'm new to C++ and having some difficultly with the use of shared ptrs. I've been able to construct a linked list. I want to traverse the linked list, and when the nodes (elements) have a valid to_add field, to add the element into the list, and continue.
class Element{
public:
char el = 'Z';
std::shared_ptr<Element> next;
char to_add = 'Z';
Element(char input){
el = input;
next = nullptr;
}
};
^ structure of node. I'm looking at the to_add field to see if there's an element to add in.
class Polymer{
public:
std::vector<Instruction> instruction;
std::shared_ptr<Element> extract_and_store_input(std::ifstream &file);
void prepare_insertion(std::shared_ptr<Element> head);
void insert_elements(std::shared_ptr<Element> head);
Polymer(std::ifstream &file){
std::shared_ptr<Element> head = extract_and_store_input(file);
prepare_insertion(head);
insert_elements(head);
}
};
^ calling code format
v problem is somewhere here
std::shared_ptr<Element> add_element(std::shared_ptr<Element> head_cpy){
auto tmp = head_cpy->next;
head_cpy->next = std::make_shared<Element>(head_cpy->to_add);
head_cpy->next = tmp;
return tmp;
}
void Polymer::insert_elements(std::shared_ptr<Element> head) {
auto trav = head;
auto tmp= head;
// for (int i = 0; i < num_steps; i ++)
while (trav->next != nullptr) {
std::cout<<trav->el<<std::endl;
if (trav->to_add != 'Z'){
std::cout<<"adding"<<trav->to_add<<std::endl;
trav=add_element(trav);
trav=trav->next; // progress forward twice
}
trav=trav->next;
}
// while (tmp->el != 'Z'){
// std::cout<<tmp->el<<std::endl;
// tmp=tmp->next;
// }
}
I think that the issue may be that the pointer doing the traversal (trav) is updating the list itself, rather than progressing through the list? I would really appreciate any insights!
If anyone recognises the q, it's from AoC day 14 :) I'm sure there are better ways to do it, but I'd like to understand the problem here first!

unsorted linked list implementation check full

I am working on unsorted linked list check full currently, below is my specification and implementation.
Specification:
#ifndef UNSORTEDLIST_H
#define UNSORTEDLIST_H
#include <iostream>
using namespace std;
struct Node {
float element;
Node* next;
};
class UnsortedList
{
public:
UnsortedList();
bool IsEmpty();
bool IsFull();
void ResetList();
void MakeEmpty();
int LengthIs();
bool IsInTheList(float item);
void InsertItem(float item);
void DeleteItem(float item);
float GetNextItem();
private:
Node* data;
Node* currentPos;
int length;
};
#endif
And implemetation:
UnsortedList::UnsortedList()
{
length = 0;
data = NULL;
currentPos = NULL;
}
bool UnsortedList:: IsEmpty(){
if(length == 0)
{
return true;
}
else
{
return false;
}
}
bool UnsortedList::IsFull(){
Node* ptr = new Node();
if(ptr == NULL)
return true;
else
{
delete ptr;
return false;
}
}
void UnsortedList::ResetList(){
currentPos = NULL;
}
void UnsortedList::MakeEmpty()
{
Node* tempPtr = new Node();
while(data != NULL)
{
tempPtr = data;
data = data->next;
delete tempPtr;
}
length = 0;
}
int UnsortedList::LengthIs(){
return length;
}
bool UnsortedList:: IsInTheList(float item){
Node* location = new Node();
location = data;
bool found = false;
while(location != NULL && !found)
{
if(item == location->element)
found = true;
else
location = location->next;
}
return found;
}
void UnsortedList:: InsertItem(float item){
Node* location = new Node();
location->element = item;
location->next=data;
data = location;
length++;
}
void UnsortedList:: DeleteItem(float item){
Node* location = data;
Node* tempPtr;
if(item == data->element){
tempPtr = location;
data = data->next;
}
else{
while(!(item == (location->next) ->element) )
location = location->next;
tempPtr = location->next;
location->next = (location->next)->next;
}
delete tempPtr;
length--;
}
float UnsortedList::GetNextItem(){
if(currentPos == NULL)
currentPos = data;
else
currentPos = currentPos->next;
return currentPos->element;
}
1.In the constructor, why don't assign currentPos as null?
2.In the IsInTheList function, Why points to pointer "next" ? Isn't next is a null pointer since it has been declared in struct as Node* next?
The pointer value is not set to NULL value by default, you should set to to null explicitly. Also instead of using NULL, choose using nullptr.
This code is rather incomplete, so it is difficult to answer your questions.
This does not contain the code to insert an item in the list, which is where I would expect both the next and currentPos pointers to be set. However, that's based on a number of assumptions.
However, I don't see where next is used in the "check full function" at all, so that question is a bit confusing.
I'll also point out that this code has a glaring memory leak. The first line in IsInTheList allocates memory for a new Node, which is immediately lost with location = data.
Pointers (like any other basic type) need to be initialized before use. A value of NULL is still a value.
The code you provided seems to be very incomplete. Is data supposed to be the head of your list? I am not sure how you define "fullness". If you want to test if the list is empty, you can see if your "head" of the list is null:
bool UnsortedList::IsEmpty() {
if (data == NULL) {return true;} // if there is no first element, empty
else {return false;} // if there is ANY element, not empty
}
Or more compactly:
bool UnsortedList::Empty() {
return (data == NULL);
}
When a node is added to a linked list, we usually add the node as a whole and modify the element that came before it. For example, we might create a new node and add it using code like the following:
// implementation file
void UnsortedList::InsertItem(const float& item) {
if (data == NULL) { // no elements in list, so new node becomes the head
data = new Node; // allocate memory for new node
data->element = item; // fill with requested data
data->next = NULL; // there is no element after the tail
}
else {
new_node = new Node; // allocate memory
new_node->element = item // set data
new_node->next = NULL; // new end of the list, so it points to nothing
tail->next = new_node; // have the OLD end node point to the NEW end
tail = new_node; // have the tail member variable move up
}
}
// driver file
int main() {
UnsortedList my_list;
float pie = 3.14159;
my_list.AddNode(pie);
return 0;
}
Please note that I made use of a Node* member variable called tail. It is a good idea to keep track of both where the list begins and ends.
In your IsFull function, it will always return false since it can always create a new Node*. Except perhaps if you run out of memory, which is probably more problematic.
Your functions are rather confusing and your pointer work leaves many memory leaks. You might want to review the STL list object design here.

Deep copy and deconstructor sentinel linked list using Nodes

I am currently making a linked List program using Nodes(not that i know of any other way) and I have come upon a problem about creating a deep copy and getting rid of all my Nodes and Sentinels with my ~List(). Deleting the Nodes is not a problem, but the sentinels are since the first one is not assigned a index value.
List::~List()
{
for(size_t i=0; i<size; i++)
{
_setCurrentIndex(i);
if(current && curent->next == NULL)
{
Node *temp = current->next;
delete temp;
delete current;
}
else
{
Node *old = current;
current = current->next;
delete old;
}
}
}
List::List(const List & orig)
{
for(size_t i=0; i<size; i++)
{
if(i==0)
{
Node *copyFront = new Node; //the first sentinel
copyFront->data = orig.front->data; //front is defined in private in list.h
copyFront->prev = NULL; // it is defined as a Node (same for rear)
}
else if(0<=i && i<size) //put in i<size b/c 0<=i would always be true
{
_setCurrentIndex(i) //sets what current is and currentIndex which pts to diff Nodes
Node *copy = new Node;
copy->data = current->data;
copy->next = current->next;
current = current->next;
}
else if(i+1 == size)
{
Node *copyRear = new Node; //making the last sentinel, but it has to be
copyRear->data = orig.rear->data; //after data Node
copyRear->next = NULL;
}
}
}
I am seeking advice and comments on this code on how to proceed next or what to change if something is dreadfully wrong!
Linked lists are templates allowing any type of variable to sit in them. In my honest opinion, you'd be best off using the std::list which requires the #include <list> header file.
Of course, if you really want the experience of writing a linked list class yourself then the following code makes a deep copy of a list:
List::List( const List& other) {
if( other.head_ != nullptr) {
head_ = new Node( other.head_->item_); // copy first node
assert( head_ != nullptr); // ensure that the memory was allocated correctly
// copy the rest of the list
Node* pnew = head_;
// loop through the list until you reach the end (i.e. a node that's nullptr)
for( Node* porig( other.head_->next_); porig != nullptr; porig = porig->next_) {
// assign the next node in the destination list to the next node in the paramter's list
pnew->next_ = new Node( porig->item_);
assert( pnew->next_ != nullptr); // ensure that the memory was allocated correctly
pnew = pnew->next_; // move onto the newly created node in the destination list
}
}
else
// if the parameter is empty then the destination list will be empty as well
head_ = nullptr;
}
As for the destructor, you just need to run through the list deleting the nodes as you go:
List::~List() {
while( head_ != nullptr) { // keep looping until the list gets to the end
// make a second pointer to the node you are about to delete (so you don't lose track of it)
Node* pn( head_);
// move the head_ onto the next node essentially "removing" the first node from your list
head_ = head_->next_;
// delete the node that you've just "removed" from your list
delete pn;
}
}
I've tried to make the comments clear up anything that might be unclear.

Trouble with insertion function for ordered linked list class in C++

I have a template class OList that is an ordered linked list (elements are ordered in ascending order). It has a function called void insert(const T & val) that inserts an element into the correct place in the list. For example, If I had an OList of ints with the values { 1,3,5 } and called insert(4), the 4 would be inserted between the 3 and the 5, making OList { 1,3,4,5 }.
Now, what I have works fine when inserting elements into EMPTY OLists. However, when I use the following code:
OList<char> list;
for (int i = 0; i < 3; i++) {
list.insert('C');
list.insert('A');
}
printInfo(list);
printList(list) should output:
List = { A,A,A,C,C,C } Size = 6 Range = A...C
Instead, it outputs:
List = { A,C,C,C,
followed by a runtime error.
I have been messing with this for about 5 hours now, but I don't seem to be making any progress (aside from getting DIFFERENT wrong outputs and errors).
There are three relevant pieces of code: OList's default constructor, operator<<, printInfo(), insert(), and a helper function for insert that finds the node to insert the element. I don't see any reason to provide operator<< nor printInfo() since these seem to work fine elsewhere.
// default constructor
OList() {
size = 0;
headNode = new Node<T>;
lastNode = new Node<T>;
headNode->next = lastNode;
lastNode->next = NULL;
}
void insert(const T & val) {
if ( isEmpty() ) {
lastNode->data = val;
}
else {
Node<T> * pre = headNode;
Node<T> * insertPoint = findInsertPoint(pre, val);
Node<T> * insertNode = new Node<T>;
insertNode->data = val;
insertNode->next = insertPoint;
pre->next = insertNode;
// why is pre equal to headNode?
// I thought I changed that when using it
// with findInsertPoint()
cout << (pre == headNode) << endl;
}
size++;
}
// returns the node AFTER the insertion point
// pre is the node BEFORE the insertion point
Node<T> * findInsertPoint(Node<T> * pre, const T & val) {
Node<T> * current = pre->next;
for (int i = 0; (i < getSize()) && (val > current->data); i++) {
pre = current;
current = current->next;
}
return current;
}
lastNode is simply the last node in the list.
headNode is a "dummy node" that contains no data and is only used as a starting place for the list.
Thanks in advanced. I'm really embarrassed to be asking for homework help on the internet, especially since I'm sure the main problem is my lack of a thorough understanding of pointers.
You are passing the pointer to pre by value into findInsertPoint, so it is copied, and the function changes the copy of pointer, and when the function returns, it is still the old pre, not the pre from inside the function.
If you want to change the pointer, you must pass pointer to the pointer to the function (or reference to pointer).

Simple Linked List Implementation in C++

I'm a programming student in my first C++ class, and recently we covered linked lists, and we were given an assignment to implement a simple one. I have coded everything but my pop_back() function, which is supossed to return a pointer to the Node that needs to be deleted in Main(). No Node deletion is to be done in the actual function. So my question is:
Would you be willing to help point me in the right direction for my pop_back() function? Also, if you notice anything else that I'm doing wrong, let me know.
Also, this linked list is just to work with strings. In this case, a grocery list, so one string for the quantity of the item(1,2), and one string for the item type. (Milk, Eggs, etc.)
Below I've included my List & Node class implementations, so you can get an idea of what I've done so far.
Node.cpp
Node::Node(void)
{
descrip = " ";
quantity = " ";
previous = NULL;
next = NULL;
}
Node::Node(string q, string d)
{
descrip = d;
quantity = q;
previous = NULL;
next = NULL;
}
Node* Node::GetNext()
{
return next;
}
Node* Node::GetPrevious()
{
return previous;
}
void Node::SetNext(Node * setter)
{
next = setter;
}
void Node::SetPrevious(Node * setter)
{
previous = setter;
}
List.cpp
List::List(void)
{
first = NULL;
last = NULL;
numNodes = 0;
}
Node* List::GetFirst()
{
return first;
}
Node* List::GetLast()
{
return last;
}
void List::SetFirst(Node* setter)
{
first = setter;
}
void List::SetLast(Node* setter)
{
last = setter;
}
int List::GetNumNodes()
{
return numNodes;
}
void List::push_front(Node* item)
{
if (first == NULL)
{
first = item;
last = item;
}
else
{
Node* pFirst = first;
item->SetNext(pFirst);
first = item;
numNodes++;
}
}
void List::push_back(Node * item)
{
if (last == NULL)
{
first = item;
last = item;
}
else
{
last->SetNext(item);
last = item;
numNodes++;
}
}
Node* List::pop_front()
{
Node* temp = first;
first = first->GetNext();
if (first == NULL)
{
temp = first->GetNext();
first = p;
}
if (first == NULL)
{
last = NULL;
}
if (numNodes > 0)
{
numNodes--;
}
return temp;
}
Node* List::pop_back() // this whole function may be wrong, this is just my attempt at it
{
Node* temp;
temp = first;
while((temp->GetNext()) != NULL)
// im stuck here
}
Some pointers:
0x1243bfa3
0x45afc56e
0xdeadbeef
Some more pointers:
You should prefer to initialize your class members in the initialization list, not in the constructor's body.
In C++, unlike C89, we declare and define a function with no parameters as void f();, not void f(void);.
In C++ we commonly reset pointers with 0, not NULL.
See below for what I mean in code.
Good C++ code will try to take advantage of RAII. This implies avoiding primitive pointers for the most part. In this case plain old std::auto_ptr<> would make a perfectly sufficient substitute for the primitve Node* pointers. However, I do reckon part of the exercise here is pointer arithmetics, and so I just leave this as a side-note.
It would be useful for us if you'd attach the class declarations. I assumes all those accessors and mutators, GetFirst() and SetFirst() etc., are there because they are public. That's a bad idea. First, they expose the private pointers, which defeats the whole point of accessor. Second, they don't do anything special so they're just extra code -- which means extra room for bugs. This brings me to the next point.
Your mutators are incorrect. You blindly assign a new value to the private member pointer, without deleting what you had before. That's a memory leak.
Ever tried to pop_front() when the list is empty?
Finally, 8 being a round number it's time we get to the question at hand. pop_back(). My question to you is, why are you traversing the list all the way to the end if you so meticulously maintain a pointer to the last node of your list? Indeed, if you wouldn't bother with maintaining a pointer to the end of the list then you'd have to traverse all the way to the last node in order to pop it. And for that you were in the right direction. Except that ...
When you access members through pointers, as in first->GetNext(), always make sure first isn't a null pointer -- or else state in the function's documentation comment that you assume the pointer is not null.
These should get you started.
Points 1, 2 and 3 in code:
Node::Node()
: descrip(" "), quantity(" "), previous(0), next(0)
{
}
So if I understand this right you just want to run through your linked list until you get to the last node in the linked list and return the pointer to it?
I'm pretty sure what you have there will do it except
Node* List::pop_back() // this whole function may be wrong, this is just my attempt at it
{
Node* temp;
temp = first;
while(temp->GetNext() != NULL)
{
temp = temp->GetNext();
}
return temp;
}
So if I read it right, there it will continually loop around until it gets to the node with none in the line behind it, then return it.
I like the previous posters answer, but one thing you might want to keep in mind is if you have an empty list. Then your first pointer will equal NULL and you would be trying to call NULL->GetNext() basically and Seg Fault. I think you can edit the above code slightly and still get have it work like this:
Node* List::pop_back()
{
Node* temp;
temp = first;
while(temp != NULL && temp->GetNext() != NULL)
{
temp = temp->GetNext();
}
return temp;
}
This will have the function return NULL if there is nothing in the list and still work properly.
It would definitely have helped me if you also had posted your class declaration. I cannot guarantee that the below is correct but it makes sense to me
Node* List::pop_back()
{
Node *temp = NULL;
if(numNodes == 1)
{
temp = first;
// setting the list pointers to NULL
first = NULL;
// setting the list pointers to NULL
last = NULL;
//You should also probably remove the links from your node
//to the next and previous nodes but since you didn't specify
//this it is up to you
numNodes--;
}
else if(numNodes > 1) //more than one element
{
//the pointer you want to return
temp = last;
//For clarity I am creating another variable here
Node *newLast = temp->GetPrevious();
//Setting the new last node to point at nothing so now temp
//is "disconnected from the list"
newLast->next = NULL;
//the last pointer of the list is now pointing at the new last node
last = newLast;
//You should also probably remove the links from your node
//to the next and previous nodes but since you didn't specify this it is up to you
numNodes--; //decrement the counter
}
return temp;
}