Delete from Position (Doubly Linked List)
Index pos is 0-based. Use delete from beginning for pos == 0, delete from end for pos == n - 1. In the middle, walk to the predecessor, then cur->next = rm->next and rm->next->prev = cur before free(rm).
C program
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *prev;
struct Node *next;
};
static int count_nodes(struct Node *h)
{
int c = 0;
while (h != NULL) {
c++;
h = h->next;
}
return c;
}
void insert_end(struct Node **head, struct Node **tail, int data)
{
struct Node *n = malloc(sizeof(struct Node));
if (n == NULL)
return;
n->data = data;
n->next = NULL;
if (*head == NULL) {
n->prev = NULL;
*head = *tail = n;
return;
}
n->prev = *tail;
(*tail)->next = n;
*tail = n;
}
void delete_begin(struct Node **head, struct Node **tail)
{
if (*head == NULL)
return;
struct Node *h = *head;
if (*head == *tail) {
free(h);
*head = *tail = NULL;
return;
}
*head = h->next;
(*head)->prev = NULL;
free(h);
}
void delete_end(struct Node **head, struct Node **tail)
{
if (*head == NULL)
return;
if (*head == *tail) {
free(*head);
*head = *tail = NULL;
return;
}
struct Node *t = *tail;
*tail = t->prev;
(*tail)->next = NULL;
free(t);
}
void delete_at(struct Node **head, struct Node **tail, int pos)
{
if (*head == NULL)
return;
int n = count_nodes(*head);
if (pos < 0 || pos >= n)
return;
if (pos == 0) {
delete_begin(head, tail);
return;
}
if (pos == n - 1) {
delete_end(head, tail);
return;
}
struct Node *cur = *head;
for (int i = 0; i < pos - 1; i++)
cur = cur->next;
struct Node *rm = cur->next;
cur->next = rm->next;
rm->next->prev = cur;
free(rm);
}
void print_list(struct Node *head)
{
while (head != NULL) {
printf("%d ", head->data);
head = head->next;
}
printf("\n");
}
int main(void)
{
struct Node *head = NULL;
struct Node *tail = NULL;
insert_end(&head, &tail, 10);
insert_end(&head, &tail, 20);
insert_end(&head, &tail, 30);
print_list(head); /* 10 20 30 */
delete_at(&head, &tail, 1); /* remove 20 */
delete_at(&head, &tail, 1); /* remove 30 */
delete_at(&head, &tail, 0); /* remove 10 */
print_list(head); /* empty */
return 0;
}
Output
First print_list(head) after three insert_end calls:
10 20 30
After delete_at at indices 1, 1, and 0, the second print_list prints only a newline (empty list).
Step-by-step execution table
| Step | Operation | Branch | List state (forward) | List state (backward) | head |
tail |
|---|---|---|---|---|---|---|
| 0 | (after insert_end ×3) |
— | 10 → 20 → 30 |
30 → 20 → 10 |
Node 10 |
Node 30 |
| 1 | delete_at(1) |
Middle (unlink node 20) |
10 → 30 |
30 → 10 |
Node 10 |
Node 30 |
| 2 | delete_at(1) |
pos == n-1 → delete_end |
10 |
10 |
Node 10 |
Node 10 |
| 3 | delete_at(0) |
pos == 0 → delete_begin |
empty | empty | NULL |
NULL |
Memory layout table (initial list 10 20 30)
| Address | Node | data |
prev |
next |
Points to (prev / next) |
|---|---|---|---|---|---|
0x1000 |
Node A | 10 | NULL |
0x1008 |
prev: NULL, next: Node B |
0x1008 |
Node B | 20 | 0x1000 |
0x1010 |
prev: Node A, next: Node C |
0x1010 |
Node C | 30 | 0x1008 |
NULL |
prev: Node B, next: NULL |
After first delete_at(1) (middle remove)
Node B is freed; A and C link to each other:
| Address | Node | data |
prev |
next |
|---|---|---|---|---|
0x1000 |
Node A | 10 | NULL |
0x1010 |
0x1010 |
Node C | 30 | 0x1000 |
NULL |
Pointer variables
- Initial list:
head = 0x1000(Node A),tail = 0x1010(Node C). - After first delete: same
head/tailaddresses; list is10 → 30. - After all deletes:
head = tail = NULL.
Traversal path for print_list(head) (before any delete)
Start at head (0x1000) → Node A [10]
↓ (next)
Node B [20]
↓ (next)
Node C [30]
↓ (next)
NULL → Stop
Output: 10 20 30
Comparison: delete_at vs delete_begin / delete_end
| Feature | delete_at |
Direct delete_begin / delete_end |
|---|---|---|
| API | One function + index pos |
Call the helper for front vs back only |
This main sequence |
Middle unlink, then delete_end, then delete_begin |
Would match explicit calls in that order |
| Middle delete | Walk + cur->next / rm->next->prev |
Not used when only deleting ends |
Key branches inside delete_at
| Condition | Delegates to |
|---|---|
pos == 0 |
delete_begin |
pos == n - 1 |
delete_end |
| Otherwise (middle) | Unlink cur->next, fix prev on the node after the removed one |
Delete from Position (SLL) — same index idea, fewer pointer fields. · Delete from Beginning (DLL) · Delete from End (DLL)