So I'm a beginner to C++ and I have a school project to create a linked list and I'm working on the merge method right now and I'm not sure why it's not working. I identified the problem to be in the second if in the while loop where instead of changing the head_ list node it's changing the list1 list and I don't know why it's doing that
template <typename T>
bool List342<T>::Merge(const List342<T>& list1) {
if (head_ == nullptr) {
head_ = list1.head_;
return true;
}
if (list1.head_ == nullptr) {
return false;
}
Node<T>* l1_ptr = list1.head_;
Node<T>* head_ptr = head_;
while (l1_ptr != nullptr && head_ptr != nullptr) {
if (*head_ptr->data == *l1_ptr->data) {
l1_ptr = l1_ptr->next;
head_ptr = head_ptr->next;
}
else if (*head_ptr->data <= *l1_ptr->data) {
Node<T>* temp = head_ptr->next;
head_ptr->next = l1_ptr;
l1_ptr->next = temp;
l1_ptr = l1_ptr->next;
head_ptr = head_ptr->next;
}
}
return true;
}
I find working with linked lists easier with references and recursion over the list iterators. This version makes sure the second linked list is left in a valid state (though maybe changed), and no new memory is allocated.
template <class T>
bool List342<T>::Merge(List342<T>& list1) {
merge(head_, list1.head_);
}
template <class T>
void merge(List342<T>::Node*& head, List342<T>::Node*& head_o) {
if (head_o == nullptr)
return;
if (head == nullptr) {
head = head_o;
head_o = nullptr;
return;
}
if (*head->data <= *head_o->data) {
merge(head->next, head_o);
} else {
// steal Node from right list1
auto* next = head->next;
auto* next_o = head_o->next;
head->next = head_o;
head_o->next = next;
head_o = next_o; // this works because head_o is a reference
merge(head->next, head_o);
}
}
I think this kind of code makes it much easier to argue about what happens in each case. Let me know if you have questions.
Related
I am trying to finish up an assignment regarding linked lists in c++ but my remove function seems to be crashing the app every time I try to use it. I've tried a few different things but I seriously don't know what's wrong. For example if I only have one item in the list and try to remove it it crushes same goes for any other case. If anyone knows what's wrong please help :)
template <class T>
Error_code List<T>::retrieve(string fn, T& item)
{
if (empty()) return underflow;
Node<T>* temp = head;
while (temp->entry.FlightNO.compare(fn) != 0) {
if (temp->next == NULL)
return not_found;
temp = temp->next;
}
item = temp->entry;
return success;
}
template <class T>
Error_code List<T>::remove(T& item)
{
Node<T>* current = head;
Node<T>* search = new Node<T>(item);
if (head == search) {
head = head->next;
return success;
}
else {
Node<T>* previous = current;
current = current->next;
if (current->next == NULL) {
delete current;
return success;
}
while (current != search)
{
previous = current;
current = current->next;
}
previous->next = current->next;
return success;
}
}
This is my code, the first function is to retrieve the item and check if it actually exists, then the second is the remove which doesn't work
Everything what was mentioned in the comments is on point. However you came here looking for an answer, so here you go:
template <class T>
Error_code List<T>::remove(T& item)
{
Node<T>* current = head;
Node<T>* search = new Node<T>(item); // <--- why?
//if (head == search) { //<-- always false
// head = head->next;
// return success;
//}
Node<T>* previous = current;
current = current->next;
if (current->next == NULL) {
delete current;
return success;
}
while (current != search) // <--- fails here, this is always true (you are comparing pointers, not objects)
{
previous = current;
current = current->next; // <--- because this loop is always true and you have a nullptr terminated list then this will segfault with RAV
}
previous->next = current->next;
return success;
}
}
EDIT: Just to clarify what causes the segfault, at the "end of the loop" you eventually call
nullptr->next;
I am writing a function to merge two sorted linked lists and return the sorted list. I keep getting this error. SIGABRT - Abort (abnormal termination) signal
template <typename T>
LinkedList<T> LinkedList<T>::merge(const LinkedList<T>& other) const {
LinkedList<T> L = *this;
LinkedList<T> R = other;
LinkedList<T> merged;
if (L.head_ == nullptr) {
return R;
} else if (R.head_ == nullptr) {
return L;
}
while(L.head_ && R.head_) {
if (L.head_->data < R.head_->data) {
merged.pushBack(L.head_->data);
L.head_ = L.head_->next;
++merged.size_;
} else {
merged.pushBack(R.head_->data);
R.head_ = R.head_->next;
++merged.size_;
}
}
while (L.head_ || R.head_) {
if (L.head_) {
merged.pushBack(L.head_->data);
L.head_ = L.head_->next;
++merged.size_;
} else {
merged.pushBack(R.head_->data);
R.head_ = R.head_->next;
++merged.size_;
}
}
return merged;
}
Does anyone know what's wrong with my code?
This is the error I am getting
due to a fatal error condition:
SIGABRT - Abort (abnormal termination) signal
This is the pushBack function I have for a doubly-linked list
// Push a copy of the new data item onto the back of the list.
template <typename T>
void LinkedList<T>::pushBack(const T& newData) {
// allocate a new node
Node* newNode = new Node(newData);
if (!head_) {
// If empty, insert as the only item as both head and tail.
// The Node already has next and prev set to nullptr by default.
head_ = newNode;
tail_ = newNode;
}
else {
// Otherwise, add the new item as the tail.
// (We could rewrite this without the temporary variable "oldTail",
// but perhaps this way is clearer.)
Node* oldTail = tail_;
oldTail->next = newNode;
newNode->prev = oldTail;
tail_ = newNode;
}
// update size
size_++;
}
I'm curious what's the difference in two functions below:
void Add(T x)
{
if (head == nullptr)
{
head = (new Node<T>());
head->set(x);
head->set_next(nullptr);
return;
}
Node<T> *temp = head;
while (temp->get_next() != nullptr)
{
temp = temp->get_next();
}
temp->set_next(new Node<T>());
(temp->get_next())->set(x);
(temp->get_next())->set_next(nullptr);
}
void Add(T x)
{
Node<T> *temp = head;
while (temp != nullptr)
{
temp = temp->get_next();
}
temp = new Node<T>();
temp->set(x);
temp->set_next(nullptr);
}
First one works properly, second one is making segm fault. Why is that? I thought outcome should be the same, just wanted to make code a little bit shorter but I'm clearly missing something
I have written a linked list(which is aimed for the data type int) implementation.
Seems to be working fine except when I try to sort the list in such a way that all the odd
elements should come after all the even elements with the original order of the even and odd numbers preserved.
Upon debugging in MS Visual Studio, I found out that in the oddevenSort() function, the for loop seems to be going on infinitely...as if somehow the tail->next was not being updated to nullptr.
I can't seem to grasp where the error lies in my logic.
#include<iostream>
template<class T>
class SLL_Node
{
public:
T info;
SLL_Node* next;
SLL_Node();
SLL_Node(T el, SLL_Node<T>* n = nullptr);
};
template<class T>
class SLL
{
private:
SLL_Node<T>* head, * tail;
size_t size;
public:
SLL();
~SLL();
bool isEmpty() const;
size_t get_size() const;
void add_to_head(T el);
void add_to_tail(T el);
void delete_at(size_t); //delete at a certain index. Index starting from 1. Throws an error //message if index out of bounds or list empty.
void display()const; //the logic is for mostly primitive data types and not user defined data //types (including classes)
void oddevenSort();
};
template<class T>
bool SLL<T>::isEmpty() const
{
if (tail == nullptr)
return true;
else
return false;
}
template<class T>
SLL_Node<T>::SLL_Node() : next{ nullptr }
{}
template<class T>
SLL_Node<T>::SLL_Node(T el, SLL_Node<T>* n) : info{ el }, next{ n }
{}
template<class T>
SLL<T>::SLL()
{
size = 0;
head = tail = nullptr;
}
template<class T>
void SLL<T>::add_to_tail(T el)
{
++size;
if (!isEmpty())
{
tail->next = new SLL_Node<T>(el);
tail = tail->next;
}
else
head = tail = new SLL_Node<T>(el);
}
template<class T>
void SLL<T>::add_to_head(T el)
{
head = new SLL_Node<T>(el, head);
if (tail == nullptr) //if empty
{
tail = head;
}
++size;
}
template<class T>
void SLL<T>::display()const
{
std::cout << '\n';
for (SLL_Node<T>* tmp{ head }; tmp != nullptr; tmp = tmp->next)
{
std::cout << tmp->info << "->";
}
std::cout << "NULL\n";
}
template<class T>
void SLL<T>::delete_at(size_t index)
{
if (index >= 1 && index <= size) //bound checking
{
if (!isEmpty()) //we dont need is empty since size takes care of that but still adding it for clarity
{
if (head == tail && index == 1) //if list only has one node and we delete head node
{
delete head;
head = tail = nullptr;
}
//otherwise if list more than one node
else if (index == 1) //if deleting head node
{
SLL_Node<T>* tmp{ head };
head = head->next;
delete tmp;
tmp = nullptr;
}
else //deleting other nodes
{
SLL_Node<T>* tmp{ head->next }, * pred{ head };
for (size_t i{ 2 }; i < index; ++i)
{
tmp = tmp->next;
pred = pred->next;
}
pred->next = tmp->next;
if (tmp == tail)
{
tail = pred;
}
delete tmp;
tmp = nullptr;
}
}
}
else
{
std::cout<<"\nError! Either the list is empty or the index entered is out of bounds!\n";
}
}
template<class T>
void SLL<T>::oddevenSort()
{
SLL_Node<T>* t=head;
size_t count{1};
for (; t != nullptr; t = t->next)
{
if (((t->info) % 2) != 0)
{
add_to_tail(t->info);
delete_at(count);
}
++count;
}
}
main:
int main()
{
SLL<int> a;
a.add_to_head(1);
a.add_to_head(2);
a.add_to_tail(3);
a.add_to_tail(4);
a.add_to_head(6);
a.add_to_tail(7);
a.add_to_head(5);
a.display();
//a.oddevenSort();
a.display();
return 0;
}
Consider an example input for oddevenSort a(1)->b(2) ->c(3)->null
on 1st iteration t is pointing to a(1) new node is created with
data 1 which is appended at the end of list like
b(2)->c(3)->d(1)->null.
On 2nd iteration t will point to node b(2) and no changes done
on list.
On 3rd iteration t will point to node c(3) new node is created
with data 3 which is appended at the end of list like
b(2)->d(1)->e(3)->null.
on 4th iteration t will point to d(1) which creates new node at the end of list. Iteration goes on and on recursively without breaking the loop.
Every time you need not to delete and create the new node. You can segregate even and odd nodes and make final list.
Here is the updated snippet
template<class T>
void SLL<T>::oddevenSort()
{
SLL_Node <T>tempOddHeader;
SLL_Node <T> *tempOddPtr = &tempOddHeader;
SLL_Node <T> tempEvenHeader;
SLL_Node <T> *tempEvenPtr = &tempEvenHeader;
SLL_Node<T>* t = head;
tempOddHeader.next = nullptr;
tempEvenHeader.next = nullptr;
while(t)
{
if (((t->info) % 2) != 0) {
//append to the odd list
tempOddPtr->next = t;
tempOddPtr = tempOddPtr->next;
t = t->next;
tempOddPtr->next = nullptr;
}
else {
//append to the even list
tempEvenPtr->next = t;
tempEvenPtr = tempEvenPtr->next;
t = t->next;
tempEvenPtr->next = nullptr;
}
}
tempEvenPtr->next = tempOddHeader.next;
head = tempEvenHeader.next;
tail = tempOddPtr;
}
So, i'm trying to initialize a LinkedList class using an initializer_list.
template<typename T>
SortedList<T>::SortedList(initializer_list<T> e){
head_= new Node<T>(*e.begin());
long intcheck = 0;
T old;
for (auto x : e){
if(intcheck > 0){
Node<T>* curr = new Node<T>(old);
if(head_ == curr){
head_->next_ = new Node<T>(x);
}
curr->next_ = new Node<T>(x);
}
old = x;
intcheck = 1;
}
}
I get a seg fault when trying to print head_->next_ (nothing wrong with my print function)
I'm assuming that you actually want the SortedList to be sorted. If so, this will accomplish that goal. It bails out early if the initializer_list is empty, but still leaves the object in a rational state.
template<typename T>
SortedList<T>::SortedList(initializer_list<T> e) : head_{nullptr} {
if (e.size() == 0)
return;
auto it = e.begin();
for (head_ = new Node<T>(*it); it != e.end(); ++it) {
Node<T> *n = new Node<T>(*it);
Node<T> *curr;
for (curr = head_; curr->next_ && curr->next_->data_ < *it; curr = curr->next_)
continue;
if (*it < curr->data_) {
n->next_ = curr;
head_ = n;
} else {
n->next_ = curr->next_;
curr->next_ = n;
}
}
}
For completeness, here's the destructor I used to test:
template<typename T>
SortedList<T>::~SortedList() {
while (head_->next_) {
Node<T> *t = head_->next_;
head_->next_ = t->next_;
delete t;
}
delete head_;
}
Your code says that head_->next_ will always be it's default value (we can't see the Node constructor so I can't say what that is).
for (auto x : e){
if(intcheck > 0){
Node<T>* curr = new Node<T>(old);
if(head_ == curr){
head_->next_ = new Node<T>(x);
}
It's OK do send your initializer list into the for loop this way. If it's empty you will just exit the loop immediately.
However your curr pointer is allocated right there, while your head_ pointer was allocated above. They will therefore never be equal because you are comparing two pointers that you are allocating in the same function.