Singly linked list, deleting an element, C++
Good afternoon. There is such a code for deleting an item from the list
void del(int n) // n - позиция удаляемого элемента
{
// Mass - объекты, которые хранятся в списке
Mass *temp = HEAD, *helping = temp;
if ((temp != NULL) && (n <= size) && (n >= 0)) // если по этому номеру что-то лежит и этот элемент внутри списка
{
for (int i = 0; i < n; i++)
{
helping = temp; // предыдущее значение temp
temp = temp->Next;
}
if (temp == HEAD) // если элемент который надо удалить первый
{
helping = temp;
temp = temp->Next;
HEAD = temp;
cout << "Удаляемый элемент: " << *helping;
free(helping);
size--; // уменьшаем размер списка
return;
}
else // иначе, если он в середине или конце
{
// 0 1 2 3 4
// вводится, к примеру, 2. т.е. helping = 1, temp = 2;
free(temp);
size--;
// 0 1 .. 3 4
helping->Next = helping->Next->Next;
// т.е. теперь 1 указывает не на 2, а на 3.
}
}
The beginning is worked out well, i.e. it removes the first element, but for some reason it does not work out the other elements. I think about it for the second day, my head is boiling. I imagine the algorithm like this:
- Deleting the{[9] element]}
- We shift the rest of the list items (from the left to the deleted item or from the right?)
Or even do so 1. Deleting the{[4] element]}
- We go through the entire list until we come across a remote one (NULL)
- We transfer the link from the element before the deleted one to the element after the deleted one (bypassing the deleted element itself)
- Repeat step 3 until there are no zero elements. Given that the end of the list we do not consider.
Thank you all so much for your help! I discovered a lot of new things in working with pointers. Special thanks
@MichaelPak for pointing out the direction in which to dig and pointing out a specific error and a detailed explanation,
@Mike for scolding me for using an irrational algorithm
@alexolut for suggesting the difference in between ned delete
and malloc free
@Vlad from Moscow for a detailed solution to the problem and a cool idea about using an unsigned variable (I did so in the end).
I am very grateful to you, thank you very much!
3 answers
In principle, you have written everything correctly except for two points.
The first is that the number of the element being deleted cannot be equal to size
. size
is always one more than the number of the last existing element, since the numbering of the elements starts from 0.
Therefore, instead of the condition
if ((temp != NULL) && (n <= size) && (n >= 0)) // если по этому номеру что-то лежит и этот элемент внутри списка
You should write
if ((temp != NULL) && (n < size) && (n >= 0)) // если по этому номеру что-то лежит и этот элемент внутри списка
^^^^^^^^
You would make your life easier if the variable size
had an unsigned integer type. In this case, there would be no there is no need to check that n >= 0
. You could declare size
as having the type unsigned int
or, as is usually the case, size_t
.
The second is that you are trying to refer to an already deleted element in the sentence
helping->Next = helping->Next->Next;
You should first set the value of the field Next
, and only then delete the element.
With that said, the function might look like this
void del(int n) // n - позиция удаляемого элемента
{
if ((HEAD != NULL) && (n < size) && (n >= 0)) // если по этому номеру что-то лежит и этот элемент внутри списка
{
// Mass - объекты, которые хранятся в списке
Mass *temp = HEAD, *helping = HEAD;
for (int i = 0; i < n; i++)
{
helping = temp; // предыдущее значение temp
temp = temp->Next;
}
if (temp == HEAD) // если элемент который надо удалить первый
{
HEAD = temp->Next;
}
else
{
helping->Next = temp->Next;
}
cout << "Удаляемый элемент: " << *temp;
free(temp);
size--; // уменьшаем размер списка
}
}
Lists are worse than arrays in that you can't access an element immediately in lists: to do this, you need to go through the previous elements. Therefore, the deletion process looks like this:
- You reach the element whose link
NEXT
points to the element being deleted; - Assign the link
NEXT
of the deleted element to the link of the previous element; - Deleting an element;
- Profit!
So from such a picture:
+------+ +------+ +------+
|данные| |данные| |данные|
\/\/\->+------+ +------+ +------+
| |--->| |--->| 0 |
+------+ +------+ +------+
It turns out such a:
+------+ +------+ +------+
|данные| |удален| |данные|
\/\/\->+------+ +------+ +------+
| | | 0 | .->| 0 |
+------+ +------+ | +------+
\______________|
Your problem is that you first delete the element, and then try to find a link to the next one, that is, helping->Next->Next
after deleting it no longer points to the 3rd element. Try to work with the pointers first, and then delete the element.
2 Times to run along the chain is too much. It is better to remember the previous element as you move along the chain.
Mass *temp=HEAD,*prev=NULL;
int i=0;
while(temp && i<n)
{
i++;
prev=temp; // Запоминаем предыдущий в цепочке
temp=temp->next;
}
if(!temp) // Элемент не найден
{
return;
}
if(HEAD==temp)
{
HEAD=temp->next;
} else
{
if(prev) prev->next=temp->next;
}
cout << "Удаляемый элемент: " << *temp;
size--;
free(temp);