Insert Function on Doubly Linked List - c++

So I've got this insert function for a doubly linked list that is working for the most part just up until I try to insert a new node at a given index. I'm having trouble with linking it correctly to the nodes before and after it, if anyone could see why, I keep getting errors when I try to assign one of the points I'll point out in the code:
void insert(int index, ItemType& item)
{
int pos = 0;
Node* current = new Node;
Node* n = new Node;
n->info = item;
if (index >= 0 && index <= size)
{
if (size == 0)
{
head = n;
tail = n;
n->next = NULL;
n->prev = NULL;
size++;
return;
}
else if (index == 0)
{
n->prev = NULL;
n->next = head;
head->prev = n;
head = n;
size++;
return;
}
else if (index == size)
{
n->next = NULL;
n->prev = tail;
tail->next = n;
tail = n;
size++;
return;
}
else if (index < size/2)
{
current = head;
while(pos != index)
{
current = current->next;
pos++;
}
}
else if (index > size/2)
{
int endpos = size - 1;
current = tail;
while(endpos != index)
{
current = current->prev;
endpos--;
}
}
n->next = current;
current->prev->next = n; // HERE is where the code breaks, don't know why.
n->prev = current->prev;
current->prev = n;
size++;
}
}
So the code breaks at the current->prev->next = n statement stating there is an access violation writing location. So I'm not sure if that is coded right or if I've messed up in pointing assignments in earlier code. If anyone knows why its doing that and can point me in the right direction that would be awesome. Thanks.

From my observation,
Your code fails when index = size/2.
When there are two elements(size == 2) and when you try to insert at position 1, then current->prev->next = n; is meaningless
Do one of these changes else if (index <= size/2) or else if (index >= size/2)

If current is the first node in the list, then current->prev will be NULL, so current->prev->next will cause problems. You should check if current is the first item in the list before this line.
Also, your code leaks memory because you are allocating a new Node for current and you do not delete it. Since you are using current to move through the list rather than to create a new node, you should declare it as just
Node* current;
rather than
Node* current = new Node;

Related

Traverse a doubly Linked List to a given index

I'm working on a doubly linked list and want to implement an insert() function at a given index. Right now I am able to traverse through the linked list with a for loop. However, I want execute the traversing with a while loop but I cant figure it out.
The for loop I am running is
for (int i = 0; i < index - 1; i++) {
//move the temp pointer down the list
temp = temp->next;
}
The full insert() function:
template<typename Data>
void Link<Data>::insert(int index, Data value) {
if (head == nullptr) {
Link<Data>::push2Front(value);
}
else if (index >= size) {
Link<Data>::add2Rear(value);
}
else {
Node* temp = head;
for (int i = 0; i < index - 1; i++) {
temp = temp->next;
}
Node* nn = new Node;
nn->value = value;
nn->next = temp->next;
nn->prev = temp->prev;
temp->next->prev = nn;
temp->next = nn;
size++;
}
}
Suggestions are much appreciated.
You can do it like this
int i=0;
while(i<index-1){
temp=temp->next;
++i;
}
Using a while loop instead is very easy, just decrement index until it reaches 0, eg:
template<typename Data>
void Link<Data>::insert(int index, Data value) {
if (index <= 0) {
Link<Data>::push2Front(value);
}
else if (index >= count) {
Link<Data>::add2Rear(value);
}
else {
Node* temp = head;
while (--index > 0) {
temp = temp->next;
}
Node* nn = new Node;
nn->value = value;
nn->next = temp->next;
nn->prev = temp;
if (temp->next) temp->next->prev = nn;
temp->next = nn;
++size;
}
}
That being said, the insert() code can be simplified a bit further:
template<typename Data>
void Link<Data>::insert(int index, Data value) {
if (index < 0 || index > size) {
throw std::out_of_range("");
}
Node** temp = &head;
Node* prev = nullptr;
while (index-- > 0) {
prev = *temp;
temp = &(prev->next);
}
Node* nn = new Node;
nn->value = value;
nn->next = *temp;
nn->prev = prev;
if (*temp) (*temp)->prev = nn;
*temp = nn;
++size;
}

Create a function to insert element into List at given position

Not sure if there is a simple and better way to implement this function?
void insert(Node* &head, int element, int position) {
Node* current = new Node;
current->data = element;
current->next = NULL;
if (position == 1) {
current->next = head;
head = current;
return;
}
else {
Node * current2 = head;
for (int i = 0; i < position - 2; i++) {
current2 = current2->next;
}
current2->next = current2->next;
current2->next = current;
}
}
A better way would be to make this function without null pointer access. You are missing all the necessary error checking.
But if you have to use this function you are already doing something wrong. The operation takes O(n) time. And if you build your list using only this function then you already have O(n^2) time. Using a balanced tree or heap would give you O(n * log n) time which makes a huge difference even for relatively small n. So think again why you need to insert at a given position and think about more suitable data structures.
A simpler implementation, and actually used in real code a lot, is to implement insert_before(before, data) or insert_after(after, data) with a doubly linked list. Both of which would get an item in the list and a new item to insert and place the new item before or after the old one on O(1) time.
Some boundary check is needed (please find the comments inline):
int listLen(Node *head)
{
int len = 0;
while (head != nullptr)
{
len++;
head = head->next;
}
return len;
}
void insert(Node* &head, int element, int position)
{
if (head == nullptr) // do nothing if head is nullptr
return;
if (position < 0) // insert to the begin if position is negative
position = 0;
else
{
int len = listLen(head);
if (len < position) // position is out of range, insert to the end
{
position = len;
}
}
if (position == 0)
{
Node *next = head;
head = new Node(element);
head->next = next;
}
else
{
int curPos = 0;
Node *curNode = head;
while (curPos < position - 1) // move to position
{
curNode = curNode->next;
curPos++;
}
Node *next = curNode->next; // do insertion
curNode->next = new Node(element);
curNode->next->next = next;
}
}

calling a function within another function

I am making a simple linked list with an insert function that has 4 conditions:
add in the middle of the list
add to the head if the list is not empty
add to an empty list
add to the end of a list
I have made an addNode function that takes care of the last two conditions and im trying to implement it inside of the insertNode but it keeps crashing? is there any specific reason or am I just missing something simple?
addNode:
void linkList::addNode(int dataAdd) // this only adds a node to the end
{
nodePtr n = new node; // what this does is make the node pointer 'n' point to this new node
n->next = NULL;
n->data = dataAdd;
if (head != NULL)
{
follow = head;
while (follow->next != NULL)
{
follow = follow->next;
}
follow->next = n;
}
else
{
head = n;
}
}
insertNode:
void linkList::insertNode(int dataInsert)
{
nodePtr n = new node;
n->next = NULL;
n->data = dataInsert;
follow = head;
while (follow != NULL)
{
trail = follow;
follow = follow->next;
if (head->data < dataInsert){
n->next = head; //n's next will become the current head (n is now the first item in the linkList)
head = n; //n the head structure will now be n (n is the new head)
}
else if (follow->data < dataInsert)
{
trail->next = n;
n->next = follow;
break;
}
else
{
addNode(dataInsert);
}
}
}
I want to call addNode in the else statement in insertNode

Removing a node in a circular doubly linked list

I'm trying to write some code to remove a node from a circular doubly linked list. I've written the following function, which mostly works:
bool Circular::remove(int index)
{
if (head == NULL)
return false;
Node* current;
current = head;
if (index > 0)
{
for (int i = 0; i < index; i++)
{
current = current->next;
}
}
else if (index < 0)
{
for (int i = 0; i < abs(index); i++)
{
current = current->prev;
}
}
if (current == head)
{
head = current->next;
}
else if (current == tail)
{
tail = current->prev;
}
current->prev->next = current->next;
current->next->prev = current->prev;
return true;
}
The only problem I have is that it won't remove the correct value when I pass the number 1 into the index number. Instead it always deletes the tail. If you think there's something wrong with my code somewhere else then I'll also look into it.
I think I've figured it out. Mostly I used functions to remove the head...
Node* temp = head;
head = head->next;
head->prev = tail;
tail->next = head;
delete temp;
return true;
...and to remove the tail:
Node* temp = tail;
tail = tail->prev;
tail->next = head;
head->prev = tail;
delete temp;
return true;
Apparently just moving around the head and tail wasn't enough to actually delete those nodes.

C++ linked lists deleting nodes

I am trying to go through a singly linked list and delete all nodes that contain a certain char. I have been trying to fix a pointer error (it said glibc detected: double free or corruption) by looking up online and trying those suggestions but now I seem to be stuck in a loop after rewriting my original code. I think the I am at least stuck in the 3rd while loop, I have tried using and if/else statement but the same thing happens. I also get a segmentation fault sometimes.
Code:
int MonsterList::removeMonsterType(char monster){
if(!isalpha(monster)) return 0;
if(first == 0) return 0;
int count = 0;
char key = toupper(monster);
MonsterNode *prev = first; //first is the ptr in the list this function is called on
if(prev->next == 0){
while(prev->id == key || prev->id == key+32){
first = 0;
delete prev; prev = 0;
count++;
return count;
}
return count;
}
MonsterNode *temp = prev->next;
while(temp != NULL){
while(prev->id == key || prev->id == key+32){
first = temp;
delete prev;
prev = temp;
temp = temp->next;
}
while(temp->id == key || temp->id == key+32){
prev->next = temp->next;
delete temp;
temp = prev->next;
count++;
}
prev = temp;
temp = temp->next;
}
return count;
}
Thanks in advance for your help.
No wonder you're having such trouble. You only need a single for loop. Allow me to simplify your code [please pardon some gratuitous style edits]. Note this is untested and may not be perfect:
int
MonsterList::removeMonsterType(char monster)
{
if (!isalpha(monster))
return 0;
// first is the ptr in the list this function is called on
if (first == 0)
return 0;
int count = 0;
char key = toupper(monster);
MonsterNode *prev;
MonsterNode *cur;
MonsterNode *next;
prev = NULL;
for (cur = first; cur != NULL; cur = next) {
// grab this _first_ so we have it before cur may be deleted (e.g. if
// cur gets deleted cur->next is immediately invalid, but this will
// remain)
next = cur->next;
if ((cur->id == key) || (cur->id == (key + 32))) {
// link previous item to next item
if (prev != NULL)
prev->next = next;
// replace first item in list
else
first = next;
// delete the node and advance the count
delete cur
count++;
continue;
}
// remember previous item
prev = cur;
}
return count;
}