How to delete a node from the middle of a linked list

Question 2.3 of Cracking the Coding Interview:

Implement an algorithm to delete a node in the middle of a single linked list, given only access to that node. Example:

Here’s a diagram of the memory layout that we’re given:

            node
              |
              v
a ---> b ---> c ---> d ---> e

Because we don’t have access to b, we can’t free c’s memory, as this would cause b->next to be a dangling pointer:

            node
              |
              v
a ---> b ~~~>        d ---> e

Therefore, this question is a bit contrived: a sensible API for deleting node c would give you access to b. But let’s press on.

Instead of freeing c’s memory, we’ll have to free a different node’s memory. We have access to d via c->next ... and we know that d exists, because the question tells us c is somewhere in the middle of the linked list. So, what if we deleted d instead?!:

            node
              |
              v
a ---> b ---> c ----------> e

This is wrong, but it would be right if only the value at the third node was d instead of c! So here’s the idea: overwrite c’s contents with d’s contents, then remove the node that contained d. So we copy the value d over:

            node   next
              |      |
              v      v
a ---> b ---> d ---> d ---> e

Then copy d’s next pointer over:

            node   next
              |      |
              v      v
a ---> b ---> d      d ---> e
              |             ^
              |             |
              +-------------+

Then finally free d:

            node   next
              |      |
              v      v
a ---> b ---> d             e
              |             ^
              |             |
              +-------------+

Here’s an implementation in C:

#include <stdlib.h>
#include <assert.h>

typedef struct Node {
  int val;
  struct Node * next;
} Node;

// Precondition: node != NULL && node->next != NULL
void delete_node_middle(Node* node) {
  Node* next = node->next;
  node->val = next->val;
  node->next = next->next;
  free(next);
}

Node* mk_node(int val, Node* next) {
  Node* node = malloc(sizeof(Node));
  node->val = val;
  node->next = next;
  return node;
}

Node* mk_test_list(int length) {
  if (length <= 0) return NULL;
  return mk_node(length-1, mk_test_list(length-1));
}

int main(int argc, char** argv) {
  // List nodes contain their indexes: 4,3,2,1,0
  Node* test_list = mk_test_list(5);

  delete_node_middle(test_list->next->next);

  assert(test_list->val                   == 4);
  assert(test_list->next->val             == 3);
  assert(test_list->next->next->val       == 1);
  assert(test_list->next->next->next->val == 0);
  assert(test_list->next->next->next->next == NULL);

  return 0;
}
Tagged #ctci, #programming, #c.

Similar posts

More by Jim

👋 I'm Jim, a full-stack product engineer. Want to build an amazing product and a profitable business? Read more about me or Get in touch!

This page copyright James Fisher 2020. Content is not associated with my employer. Found an error? Edit this page.