Why do I get a segmentation fault here? - c++

void LinkedList<T>::mergeSort(Node*& curr) {
if (curr->next != nullptr) { //Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffeef3ffff8)
Node *ptr1 = nullptr;
Node *ptr2 = curr;
//splits linked list
for (int i = 0; i < getLength() / 2; i++) {
ptr1 = ptr2;
ptr2 = ptr2->next;
}
ptr1->next = nullptr;
ptr1 = curr;
//recursive call for sorting
mergeSort(ptr1); //Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffeef3ffff8)
mergeSort(ptr2);
//merge lists back together
if (ptr1 == nullptr)
curr = ptr2
else if (ptr2 == nullptr)
curr = ptr1
Node *reff = ptr1;
while (reff->next != nullptr) {
reff = reff->next;
}
reff->next = ptr2;
curr = reff;
}
}
Everything seems to be working, expect this function. I always get a segmentation error and I'm confused why it happens.
Also, I'm in college so there might be a more efficient way but this is the way I can do it, without looking ahead into the course.
I have a variable called length that holds the length. That part was implemented by the teacher.
So it gives me this error: Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffeef3ffff8). How can I figure out what the error means by code=2 and other numbers?

There are prob. numerous things wrong. This shows how it can be done with std::list. I don't know whether the API was given, but lets make it separate function that takes a list.
template<typename T>
void mergesort( std::list<T>& list ){
There is only work to do if we have more than one element
auto const size = list.size();
if( size > 1) {
The list is then split into two lists.
auto mid = list.begin();
std::advance( mid, size/2 );
std::list<T> other;
other.splice( other.begin(), list, list.begin(), mid );
Now that we have two sub-lists, mergesort can be called recursively on them.
mergesort( list );
mergesort( other );
The partial results then need to be merged.
list.merge( other );
And we are done. See working version here

for(int i=0;i<getLength()/2;i++)
I have a variable called length that holds the length. That part was implemented by the teacher.
So, getLength() is a member function of the LinkedList. When we make the recursive calls, it will always tell us the stored length of the entire LinkedList. But that's not what we want - we want the number of nodes in the chain of Nodes that we passed in. Instead, the first time we make a recursive call, we try to split it into the same number of nodes as it already has (in the first half, and zero nodes in the second half). Since this makes no progress, we will eventually blow up the stack with recursive calls.

Related

Deleting elements from doubly bounded pointer list

I am working on a project where I create a double bounded pointer list, delete several elements, and still be able to read off the list. I have a double bounded pointer list, but am having trouble deleting elements and keeping the list double bounded. This then causes issues when trying to print the list.
Below is the IF statement I've placed in a while loop to help delete unwanted elements. I keep getting a segmentation fault (core dumped).
if ((black2 != black)||(white2 != white)) {
dump = help;
help = help ->next;
dump -> before = temp;
temp -> next = help;
help ->before = temp;
delete dump;
}//if
else { temp = help;
help = help->next;
help ->before = temp; }//else
To maintain properly the doubly linked list you should do something like :
void remove(X *elt) {
X* before = elt->before;
X* after = elt->next;
if (before != NULL) { // assuming first element points to NULL
before->next = after;
}
else {
first = after; // assuming first is a pointer to first element of list
}
if (after != NULL) { // assuming last element points to NULL
after->before = before;
}
else {
last = before; // assuming last is a pointer to last element
}
delete elt;
}
That way, you ensure that elements around current correctly point to each other dealing with special cases of removing first or last element.
But you already have a std::list template in Standard Template Library
One logical issue in your code is the line dump->before = temp.
What this does is that it sets the previous node pointer of dump to temp, as opposed to defining temp as the previous node.
The correct line should read temp = dump->before
PS: Your code is correct assuming that the node you are deleting isn't the first or last node (and you haven't padded with dummy nodes). You should introduce checks for these cases if required.

Splitting Doubly linked list C++

I was wondering if I could get any insight as to why I get the error: terminating with uncaught exception of type std::out_of_range: coordinates (400,0) outside valid range of [0, 399] X [0, 239] when I run the following code.
The method is suppose to split the DLL at the index passed to it. So split(2) would leave the list it was called on with 2 nodes, while the rest of the old list would be returned as new list. I've tried many different ways to write this and none of them work (we must use unique_ptrs for the assignment).
template <class T>
auto dl_list<T>::split(node* start, unsigned split_point)
-> std::unique_ptr<node>
{
assert(split_point > 0);
if(start == nullptr)
return nullptr;
node* curr = start;
uint64_t i = 0;
while(i < split_point)
{
curr = (curr->next).get();
i++;
}
std::unique_ptr<node> temp{nullptr};
temp = std::move(curr->prev->next);
(temp)->prev = nullptr;
return temp;
}
Here is the wrapper method, if that helps:
template <class T>
auto dl_list<T>::split(unsigned split_point) -> dl_list
{
if (split_point >= size_)
return {};
if (split_point == 0)
{
dl_list lst;
swap(*this);
return lst;
}
auto old_size = size_;
auto new_head = split(head_.get(), split_point);
// set up current list
size_ = split_point;
for (tail_ = head_.get(); tail_->next; tail_ = tail_->next.get())
;
// set up returned list
dl_list ret;
ret.head_ = std::move(new_head);
for (ret.tail_ = ret.head_.get(); ret.tail_->next;
ret.tail_ = ret.tail_->next.get())
;
ret.size_ = old_size - split_point;
return ret;
}
Here’s code to unlink a specified node plus rest of list, on the node’s left (prev) side, assuming that there always is a previous node (i.e. a list with header node):
auto unlinked_list_from( Node* p )
-> Node*
{
p->prev->next = nullptr;
p->prev = nullptr;
return p;
}
Finding the n’th node is a separate problem.
Combining the two, in finding the n’th node and unlinking it and the rest of the list, is a higher level problem where you use the two lower level solutions.
It’s generally not a good idea to user ownership smart-pointers such as std::unique_ptr or std::shared_ptr in the internal pointers of linked list or tree. It’s simply not the case that each node owns the previous and next node, in the sense of having responsibility for destruction. This is one situation where raw pointers rule.
But instead, except for learning and for advanced programming, use standard library containers such as std::vector.

Randomly shuffling a linked list

I'm currently working on a project and the last piece of functionality I have to write is to shuffle a linked list using the rand function.
I'm very confused on how it works.
Could someone clarify on how exactly I could implement this?
I've looked at my past code examples and what I did to shuffle an array but the arrays and linked lists are pretty different.
Edit:
For further clarifications my Professor is making us shuffle using a linked list because he is 'awesome' like that.
You can always add another level of indirection... ;)
(see Fundamental theorem of software engineering in Wikipedia)
Just create an array of pointers, sized to the list's length, unlink items from the list and put their pointers to the array, then shuffle the array and re-construct the list.
EDIT
If you must use lists you might use an approach similar to merge-sort:
split the list into halves,
shuffle both sublists recursively,
merge them, picking randomly next item from one or the other sublist.
I don't know if it gives a reasonable random distribution :D
bool randcomp(int, int)
{
return (rand()%2) != 0;
}
mylist.sort(randcomp);
You can try iterate over list several times and swap adjacent nodes with certain probablity. Something like this:
const float swapchance = 0.25;
const int itercount = 100;
struct node
{
int val;
node *next;
};
node *fisrt;
{ // Creating example list
node *ptr = 0;
for (int i = 0; i < 20; i++)
{
node *tmp = new node;
tmp.val = i;
tmp.next = ptr;
ptr = tmp;
}
}
// Shuffling
for (int i = 0; i < itercount; i++)
{
node *ptr = first;
node *prev = 0;
while (ptr && ptr->next)
{
if (std::rand() % 1000 / 1000.0 < swapchance)
{
prev->next = ptr->next;
node *t = ptr->next->next;
ptr->next->next = ptr;
ptr->next = t;
}
prev = ptr;
ptr = ptr->next;
}
}
The big difference between an array and a linked list is that when you use an array you can directly access a given element using pointer arithmetic which is how the operator[] works.
That however does not preclude you writing your own operator[] or similar where you walk the list and count out the nth element of the list. Once you got this far, removing the element and placing it into a new list is quite simple.
The big difference is where the complexity is O(n) for an array it becomes O(n^2) for a linked list.

Circular Singly Linked List: Remove a particular Node from List

I wrote the code to remove a particular node from list according to user
choice, code works perfectly fine for a particular value but if i make
several calls to it meaning if I call it 2 times continuously then one of my
another function pointer_to_node(index) gives an out of bounds error which
was also implemented by me to record such conditions,
Actually, why I need several calls is that I have to write a separate function
to remove all the nodes. I am trying to accomplish that task using this
function by using a for loop up to the size of my Circular Singly Linked list.
But in that case it also returns me a NULL pointer and gives me out of bounds
message (implemented by me in code). I have included both my functions down
here
void remove_from_index(int index){
Node*temptr;
temptr = new Node;
int tempdata;
if (index==1)//means remove from first
{
temptr = firstptr;
tempdata= temptr->data;
firstptr = firstptr->nextptr;
lastptr->nextptr=firstptr;
delete(temptr);
} else if(index==size_of_list()) //means last node
{
temptr = pointer_to_node(index);
index--; //get pointer of 2nd last position
lastptr = pointer_to_node(index);//setting 2nd last as last postion
temptr->nextptr=NULL;
temptr=NULL;
lastptr->nextptr=firstptr;
delete (temptr);
} else // any position of node
{
temptr = pointer_to_node(index);
tempdata = temptr->data;
index--; // to get address of back
Node* temp2ptr;
temp2ptr = new Node;
temp2ptr = pointer_to_node(index);
index = index+2;
Node* temp3ptr;
temp3ptr = new Node;
temp3ptr = pointer_to_node(index);
temp2ptr->nextptr = temp3ptr;
temptr->nextptr=NULL;
delete (temptr);
}
}
Node* pointer_to_node(int index){
Node*temptr;
temptr = new Node;
temptr = firstptr;
Node*temptr2;
temptr2 = new Node;
temptr2 = NULL;
int count = 1;
while (temptr!=temptr2){
if (count==index)
{
return temptr;
}
count++;
temptr2=firstptr;
temptr=temptr->nextptr;
}
if (index>size_of_list())
{
temptr=NULL;
cout<< "Can't You think in bounds. Take your NULL Pointer ";
return temptr;
delete temptr;
delete temptr2;
}
}
You have several memory leaks:
temptr->nextptr=NULL;
temptr=NULL; // BAD!! BAD!! Remove it otherwise you will not actually free
lastptr->nextptr=firstptr;
delete (temptr);
And here too (actually you have this in four places of the code):
Node* temp2ptr;
temp2ptr = new Node; // BADD!! Why do you allocate if you are going to reassign?
temp2ptr = pointer_to_node(index);
Remove the bads and you will avoid the memory leaks.
Still, this is not going to fix your problem.
Also you have operations after return here:
return temptr;
delete temptr;
delete temptr2;
These are never going to be executed.
EDIT Your pointer_to_node function is too complex please change it with
Node* pointer_to_node(int index) {
Node* tempPtr = firstptr;
for (int i = 0; i < index; i++) {
tempPtr = tempPtr->nextptr;
}
return tempPtr;
}
And see if this will fix your problem. More lines of code very rarely means better programming skills, do not artificially try to increase their count.
I think another possible issue here, aside from all the memory leaks and style issues which are already well documented, is that your code does not seem to handle the case of there only being one thing in the list.
If that happens, it will delete that node, but leave firstptr and lastptr pointing at random memory.
If your size_of_list() function is just counting nodes in the list, it will probably still think there are non-zero nodes remaining, and you might then attempt to remove or otherwise access another node.

Deep Copy Linked List - O(n)

I'm trying to deep copy a linked list . I need an algorithm that executes in Linear Time O(n). This is what i have for now , but i'm not able to figure out what's going wrong with it. My application crashes and i'm suspecting a memory leak that i've not been able to figure out yet. This is what i have right now
struct node {
struct node *next;
struct node *ref;
};
struct node *copy(struct node *root) {
struct node *i, *j, *new_root = NULL;
for (i = root, j = NULL; i; j = i, i = i->next) {
struct node *new_node;
if (!new_node)
{
abort();
}
if (j)
{
j->next = new_node;
}
else
{
new_root = new_node;
}
new_node->ref = i->ref;
i->ref = new_node;
}
if (j)
{
j->next = NULL;
}
for (i = root, j = new_root; i; i = i->next, j = j->next)
j->ref =i->next->ref;
return new_root;
}
Can anyone point out where i'm going wrong with this ??
This piece alone:
struct node *new_node;
if (!new_node)
{
abort();
}
Seems good for a random abort() happening. new_node is not assigned and will contain a random value. The !new_node expression could already be fatal (on some systems).
As a general hint, you should only require 1 for-loop. Some code upfront to establish the new_root.
But atruly deep copy would also require cloning whatever ref is pointing to. It seems to me the second loop assigns something from the original into the copy. But I'm not sure, what is ref ?
One thing I immediately noticed was that you never allocate space for new_node. Since auto variables are not guaranteed to be initialized, new_node will be set to whatever value was in that memory before. You should probably start with something like:
struct node *new_node = (new_node *) malloc(sizeof(struct node));
in C, or if you're using C++:
node* new_node = new node;
Copying the list is simple enough to do. However, the requirement that the ref pointers point to the same nodes in the new list relative to the source list is going to be difficult to do in any sort of efficient manner. First, you need some way to identify which node relative to the source list they point to. You could put some kind of identifier in each node, say an int which is set to 0 in the first node, 1 in the second, etc. Then after you've copied the list you could make another pass over the list to set up the ref pointers. The problem with this approach (other that adding another variable to each node) is that it will make the time complexity of the algorithm jump from O(n) to O(n^2).
This is possible, but it takes some work. I'll assume C++, and omit the struct keyword in struct node.
You will need to do some bookkeeping to keep track of the "ref" pointers. Here, I'm converting them to numerical indices into the original list and then back to pointers into the new list.
node *copy_list(node const *head)
{
// maps "ref" pointers in old list to indices
std::map<node const *, size_t> ptr_index;
// maps indices into new list to pointers
std::map<size_t, node *> index_ptr;
size_t length = 0;
node *curn; // ptr into new list
node const *curo; // ptr into old list
node *copy = NULL;
for (curo = head; curo != NULL; curo = curo->next) {
ptr_index[curo] = length;
length++;
// construct copy, disregarding ref for now
curn = new node;
curn->next = copy;
copy = curn;
}
curn = copy;
for (size_t i=0; i < length; i++, curn = curn->next)
index_ptr[i] = curn;
// set ref pointers in copy
for (curo = head, curn = copy; curo != NULL; ) {
curn->ref = index_ptr[ptr_index[curo->ref]];
curo = curo->next;
curn = curn->next;
}
return copy;
}
This algorithm runs in O(n lg n) because it stores all n list elements in an std::map, which has O(lg n) insert and retrieval complexity. It can be made linear by using a hash table instead.
NOTE: not tested, may contain bugs.