Doubly Linked list, insert_after issue - c++

I'm having trouble with an assignment of mine. I've been going over the code for over a day, yet still can't seem to fix the issue. I've tried gdb, identified where the problem was and everything, so i'd really appreciate some fresh, more experienced eyes on this.
I don't know if I need to include the entire program so i'll just start with the issue at hand.
template <class TL>
void dlist<TL>::insert_after(iterate iter, TL &item){
Dnode<TL> *inserta = new Dnode<TL>;
if(iter.current -> next() == NULL){
iter.current -> set_next(inserta);
inserta -> set_previous(iter.current);
//inserta -> set_next(NULL);
inserta -> set_data(item);
tail = inserta;
}
//else if(iter.current == head || iter.current == tail)
// rear_insert(item);
else {
inserta ->set_next(iter.current -> next());
inserta -> set_previous(iter.current);
inserta -> set_data(item);
iter.current -> next() -> set_previous(inserta);
iter.current -> set_next(inserta);
}
++used;
}
This function uses an iterator to get the current node position, and inserts a new node and data in the position after. When I compile my project I get a Seg Fault 11, and using the GDB run command, my code stops here
Program received signal SIGSEGV, Segmentation fault.
Dnode<Swatch>::next (this=0x0) at ./dnode.h:14
14 Dnode *next(){return nextptr;}
Stepping through it leads me here,
(gdb) s
main () at main2.cc:56
56 for(int i = 0;i < swatches.size()/2;i++)
(gdb) s
58 if(swatches.size()%2 == 1){
(gdb) s
62 swatches.insert_after(it,tmp);
(gdb) s
which leads me to believe the insert_after function is my problem. Also, here is my dnode class:
#ifndef DNODE_H
#define DNODE_H
template <class TL>
class Dnode{
public:
typedef TL value;
Dnode(const TL &item = TL(), Dnode *init_next = NULL, Dnode *init_prev = NULL)
{data1 = item; nextptr = init_next; previousptr = init_prev;}
TL &data(){return data1;}
Dnode *previous(){return previousptr;}
Dnode *next(){return nextptr;}
const Dnode *previous()const{return previousptr;}
const Dnode * next()const {return nextptr;}
void set_data(const TL &newData){data1 = newData;}
void set_previous(Dnode *newPrev){previousptr = newPrev;}
void set_next(Dnode *newNext){nextptr = newNext;}
private:
TL data1;
Dnode *nextptr, *previousptr;
};
#endif
So, if anybody can help me out i'd appreciate it. And if I need to include more, I will.
Thanks

Related

Adding a node to the beginning of a double-linked list

I am trying to create a function that adds a node to the beginning of a double-linked list in C++, and I'm getting this error in Xcode. I know it must be because I lost the address of one of my temp nodes, but I cannot figure out how to fix it.
template<typename Item>
void DLList<Item>::push_front(const Item &item) {
/* Adds item to a new Node at the front of the list. Updates head,
tail, and size accordingly. Must appropriately handle cases in which the list is empty */
Node*p = new Node;
p -> item = item;
Node*oldHead = head;
p -> next = oldHead;
oldHead -> prev = p; /*error message: Thread 1: EXC_BAD_ACCESS (code=1, address=0x10)*/
head = p;
size ++;
}
The error will happen when oldHead is nullptr, and then oldHead->prev is an invalid access. This happens when the list is empty (head is nullptr).
It is easy to fix: just make sure you only execute that statement when the list is not empty. NB: you don't actually need oldHead. Just keep working with head.
And as the comment in your code seems to suggest your list has a tail member, you should set it when the first node is added to the list:
Node* p = new Node;
p -> item = item;
p -> next = head;
if (head != nullptr) {
head -> prev = p;
} else {
tail = p;
}
head = p;
size ++;

C++ declaring double-linked list, traverse list both ways with two for-loops and print

Just beginning with C++ (be gentle, please). I have some code and I have to:
Add Element* to make doubly-linked list
Add insert_before() and insert_after() methods to Element
Traverse list both ways with two separate for-loops
Print operating number inside each loop
Code
I tried the following:
#include <cstdio>
struct Element {
Element* next{};
Element* previous{};
void insert_after(Element* new_element) {
new_element -> previous = this;
new_element -> next = this -> next;
this -> next = new_element;
}
void insert_before(Element* new_element) {
new_element -> previous = this -> previous;
new_element -> next = this;
this -> previous = new_element;
}
char prefix[2];
short operating_number;
};
int main() {
Element trooper1, trooper2, trooper3, trooper4;
trooper1.prefix[0] = 'T';
trooper1.prefix[1] = 'K';
trooper1.operating_number = 421;
trooper1.insert_after(&trooper2);
trooper2.prefix[0] = 'F';
trooper2.prefix[1] = 'N';
trooper2.operating_number = 2187;
trooper2.insert_before(&trooper3);
trooper3.prefix[0] = 'L';
trooper3.prefix[1] = 'S';
trooper3.operating_number = 005;
trooper3.insert_before(&trooper4);
trooper4.prefix[0] = 'F';
trooper4.prefix[1] = 'K';
trooper4.operating_number = 2602;
for (Element *cursor = &trooper1; cursor; cursor = cursor -> next) {
printf("stormtrooper %c%c-%d\n",
cursor->prefix[0],
cursor->prefix[1],
cursor->operating_number);
}
for (Element *cursor = &trooper3; cursor; cursor = cursor -> previous) {
printf("stormtrooper %c%c-%d\n",
cursor->prefix[0],
cursor->prefix[1],
cursor->operating_number);
}
}
It's very basic, I know. But I'm starting to learn.
The code compiles correctly but I get this output:
/home/facundo/Escritorio/C++Projects/cmake-build-debug/C__Projects
stormtrooper TK-421
stormtrooper FN-2187
stormtrooper LS-5
stormtrooper FK-2602
stormtrooper TK-421
Process finished with exit code 0
I really don't understand why it prints only that (I guess there should be 8 lines of output).
I was expecting an output that would print the elements like this:
trooper1
trooper4
trooper3
trooper2
trooper2
trooper3
trooper4
trooper1
Some help would be really appreciated. Thanks for taking your time.
In your insert functions, you are not linking up all the pointers correctly:
void insert_after(Element* new_element) {
new_element -> previous = this;
new_element -> next = this -> next;
this -> next = new_element;
if (new_element -> next) // this check needed
// to correctly link the next -> previous
new_element -> next -> previous = new_element;
}
and
void insert_before(Element* new_element) {
new_element -> previous = this -> previous;
new_element -> next = this;
this -> previous = new_element;
if (new_element -> previous) // this check needed
// to correctly link the previous -> next
new_element -> previous -> next = new_element;
}
Also, in the second for loop, note that trooper2 is the last Element in the list, not trooper3, so you need to start from there to see all the Elements in reverse.
Here's a demo.

How to compare 2 linked lists in c++ and put matching data into another linked list

I want to compare two linked lists that contain book titles and then create a new linked list that only has the matching titles from the original lists. Currently I have already created both linked lists and can output both in alphabetical order. The problem comes when I try to compare and create the updated list with the matching titles.
I have tried to create a recursive function that takes in both lists as parameters and will call itself and move the second list to the next node if the titles don't match.
If they both match, then it again calls itself, but moves both lists up a node.
I'm still pretty new on using linked lists and recursion, but I feel like I'm on the right track. All of my other functions are working, I'm just not sure how to make this work and also how to call it in my main function.
Node *compare(Node *h, Node *j) {
Node* h_curr = h;
Node* j_curr = j;
Node* new_node;
Node* updated_list = NULL;
while ((h_curr->next != NULL) || (j_curr->next != NULL)) {
if (h_curr->data != j_curr->data) { // if not equal, then move j_head to the next link
compare(h_curr, j_curr->next);
//j_curr = j_curr->next;
}
else {
updated_list->data = h_curr->data;
new_node = newNode(updated_list->data);
return updated_list;
updated_list = updated_list->next;
compare(h->next, j->next);
}
}
return NULL;
}
#include<string>
#include<iostream>
//assumed node structure
struct Node{
Node(std::string str, Node* ptr = nullptr):data(str), next(ptr){}
std::string data{};
Node* next{};
};
//The following is your rucresive function
void compare(Node* & first, Node* & second, Node* & match) {
if(!first || !second ) return;//base case
if ( first -> data < second -> data) compare(first -> next, second, match );
else if ( first -> data > second -> data) compare(first , second -> next, match);
else{//match found
match = new Node{ first -> data};
compare(first , second -> next, match -> next);
}
}
//To disply the result (recursive function)
void display(Node* & root){
if(!root) return;
std::cout<<root->data<<" ";
display( root-> next);
}
//To test
int main(){
Node* first = new Node{"aaa"};
first->next=new Node{"ccc"};
first->next->next=new Node{"ccc1"};
first->next->next->next=new Node{"ccc3"};
first->next->next->next->next=new Node{"ccc4"};
first->next->next->next->next->next=new Node{"ddd"};
Node* second = new Node{"baaa"};
second->next=new Node{"ccc"};
second->next->next=new Node{"ccc1"};
second->next->next->next=new Node{"ccc2"};
second->next->next->next->next=new Node{"ccc4"};
Node* res;
compare(first, second, res);
display(res);
}

Vector push back error

I'm using C++ to implement FP-growth algorithm, but I get some errors when using vector. Here is my code:
typedef struct Node
{
FPData *fpData;
int childCount;
struct Node *parent;
vector<Node*> childs;
}FPNode;
FPNode* FPTree::NewNode(string data, int support)
{
FPNode *node = (FPNode*) malloc(sizeof(FPNode));
FPData *fpData = (FPData*) malloc(sizeof(FPData));
fpData -> data = data;
fpData -> support = support;
node -> fpData = fpData;
node -> childCount = 0;
node -> parent = NULL;
return node;
}
void FPTree::InsertFPPath(FPNode* root, list<FPData*> fpDatas)
{
if(fpDatas.size() <= 0)
{
return;
}
bool flag = true;
for(int i = 0; i < root -> childCount; i++)
{
FPNode* child = root -> childs[i];
if(child -> fpData -> data == fpDatas.front() -> data)
{
flag = false;
child -> fpData -> support ++;
fpDatas.pop_front();
InsertFPPath(child, fpDatas);
break;
}
}
if(flag)
{
FPData* firstData = fpDatas.front();
FPNode* newChild = NewNode(firstData -> data, firstData -> support);
root -> childs.push_back(newChild); // error at here
root -> childCount ++;
fpDatas.pop_front();
for(int i = 0; i < fpDatas.size(); i++)
{
InsertFPPath(newChild, fpDatas);
}
}
}
The InsertFPPath() is a recursive method, I get error when second iterate:
root -> childs.push_back(newChild)
The error comes at:
construct(_Up* __p, _Args&&... __args) // here the __p is null, and __args is right
{
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
}
And the thread Queue stop at:
#0 0x00000001000050cf in void std::__1::allocator::construct(Node**, Node* const&&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1673
the backtrace is :
#0 0x00000001000050cf in void std::__1::allocator::construct(Node**, Node* const&&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1673
#1 0x00000001000050bc in void std::__1::allocator_traits >::__construct(std::__1::integral_constant, std::__1::allocator&, Node**, Node* const&&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1600
#2 0x000000010000509c in void std::__1::allocator_traits >::construct(std::__1::allocator&, Node**, Node* const&&&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:1453
#3 0x0000000100005079 in std::__1::vector >::push_back(Node* const&) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:1590
#4 0x0000000100004fa9 in FPTree::InsertFPPath(Node*, std::__1::list >) at /Users/dorothy/ME/USTC/作业/数据挖掘/experiment/FPTree/FPTree/FPTree.cpp:129
#5 0x00000001000051b4 in FPTree::InsertFPPath(Node*, std::__1::list >) at /Users/dorothy/ME/USTC/作业/数据挖掘/experiment/FPTree/FPTree/FPTree.cpp:135**
When you allocate memory for structures (struct or class) containing constructors, or for structures containing objects that have constructors, then you can't allocate the memory using malloc. The malloc function only allocates memory, but it doesn't call the constructors, and in your case that means that the childs member object will not be constructed and using the vector will lead to undefined behavior.
When allocating memory dynamically in C++ you need to use the new operator:
FPNode *node = new FPNode;
FPData *fpData = new FPData;

Problems replacing head of a linked list

Writing a function to do a head insert on a linked-list. It's half working as in it's inserting the object into head and reattaching the list but I'm losing my original head node in the list somehow.
If list is [green, red, blue] and I try to insert yellow, it will work but the new list will be [yellow, red, blue].
Node class is:
template<class T>
class Node
{
public:
Node(T theData, Node<T>* theLink) : data(theData), link(theLink){}
Node<T>* getLink( ) const { return link; }
const T& getData( ) const { return data; }
void setData(const T& theData) { data = theData; }
void setLink(Node<T>* pointer) { link = pointer; }
private:
T data;
Node<T> *link;
};
List is stored into a queue, so the head insert is a method of that class. Queue has private variables front and back that point to the corresponding positions of the list.
template<class T>
void Queue<T>::headInsert(T& theData)
{
Node<T> *temp;
temp = front->getLink();
front->setLink(new Node<T>(theData, temp->getLink() ));
front = front->getLink();
}
Your problem is in your setLink call:
template<class T>
void Queue<T>::headInsert(T& theData)
{
Node<T> *temp;
temp = front->getLink();
front->setLink(new Node<T>(theData, temp->getLink() )); // Right here
front = front->getLink();
}
You actually have a number of problems. First off, let's suppose we have the following test list:
front = Red -> Green -> Blue -> NULL
The call temp = front->getLink() yields the following output:
temp = Green -> Blue -> NULL.
The new Node<T>(theData, temp->getLink()) call, where theData = Yellow, then yields:
new Node<T>(theData, temp->getLink()) = Yellow -> Blue -> NULL.
Calling front->setLink(new(...) then gives you:
front = Red -> Yellow -> Blue -> NULL
Lastly, front = front->getLink():
front = Yellow -> Blue -> NULL.
This is not what you want. You simply want to take yellow and pop it on the front of the list:
template<class T>
void Queue<T>::headInsert(T& theData)
{
front = new Node<T>(theData, front);
}
No need to modify internal pointers. Just point front to be the new node containing your data, with it's next pointer pointing to the old data.