In advanced C programming, two important concepts often discussed are self-referential structures and linked lists. These are fundamental topics in data structure design, offering powerful ways to organize and manage data in a dynamic and flexible manner.
A self-referential structure in C is a structure that contains a pointer to an instance of the same structure type. This allows for the creation of recursive data structures, like linked lists, trees, and graphs. The key feature of a self-referential structure is that it "refers to itself" through pointers.
In C, a structure is defined using the struct keyword, and a self-referential structure typically has a pointer to itself (or another instance of the same structure).
#include <stdio.h>
#include <stdlib.h>
// Definition of a self-referential structure
struct Node {
int data;
struct Node* next; // Pointer to the next Node, making it self-referential
};
int main() {
// Create a self-referential structure (linked list node)
struct Node* head = (struct Node*)malloc(sizeof(struct Node));
head->data = 10;
head->next = NULL;
printf("Data: %d\n", head->data); // Output: Data: 10
free(head); // Free the allocated memory
return 0;
}
Node structure has an int field (data) and a pointer (next) to another Node. This makes it self-referential because the next pointer points to another instance of the same structure.A linked list is a linear data structure where each element (called a node) contains two parts:
NULL if it’s the last node).Linked lists are dynamic in nature, meaning that their size can grow or shrink at runtime, unlike arrays that have a fixed size.
A singly linked list is a simple form of linked list where each node contains data and a pointer to the next node in the list.
struct Node {
int data; // Data of the node
struct Node* next; // Pointer to the next node
};
#include <stdio.h>
#include <stdlib.h>
// Definition of the Node structure (self-referential structure)
struct Node {
int data;
struct Node* next;
};
// Function to print the linked list
void printList(struct Node* head) {
struct Node* temp = head;
while (temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}
int main() {
// Allocate memory for 3 nodes
struct Node* head = (struct Node*)malloc(sizeof(struct Node));
struct Node* second = (struct Node*)malloc(sizeof(struct Node));
struct Node* third = (struct Node*)malloc(sizeof(struct Node));
// Initialize data
head->data = 10;
head->next = second;
second->data = 20;
second->next = third;
third->data = 30;
third->next = NULL; // Last node's next is NULL
// Print the linked list
printList(head);
// Free the memory
free(head);
free(second);
free(third);
return 0;
}
malloc(), with each node containing an integer (data) and a pointer (next).head) points to the second node, and the second node points to the third. The last node points to NULL, indicating the end of the list.printList() function traverses the list, printing each node’s data until it reaches NULL.10 -> 20 -> 30 -> NULL
void insertAtBeginning(struct Node** head, int new_data) {
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = *head; // Make next of new node point to the old head
*head = new_node; // Move the head pointer to the new node
}
int main() {
struct Node* head = NULL;
insertAtBeginning(&head, 10);
insertAtBeginning(&head, 20);
insertAtBeginning(&head, 30);
printList(head); // Output: 30 -> 20 -> 10 -> NULL
// Free the memory
free(head);
return 0;
}
In a doubly linked list, each node has two pointers:
next: A pointer to the next node.prev: A pointer to the previous node.This structure allows for traversal in both directions: forward and backward.
struct Node {
int data;
struct Node* next;
struct Node* prev;
};
In a circular linked list, the last node points back to the first node, forming a loop. It can be either singly or doubly circular.
next pointer of the last node points to the first node.next and prev pointers form a circle.NULL at the end.| Concept | Description | Advantages/Use Cases |
|---|---|---|
| Self-Referential Structure | A structure that contains a pointer to itself, enabling recursive data structures (like linked lists). | Used to create dynamic data structures like linked lists, trees, etc. |
| Singly Linked List | A linked list where each node points to the next node. | Dynamic memory allocation, simple to implement. |
| Doubly Linked List | A linked list where each node points to both the next and previous nodes. | Bidirectional traversal, efficient insertions and deletions from both ends. |
| Circular Linked List | A linked list where the last node points back to the first node. | Continuous traversal, used for circular buffers or queues. |
Self-referential structures, like linked lists, are essential in dynamic memory management and allow you to create complex data structures in C. Linked lists, whether singly, doubly, or circular, provide flexibility in how data can be organized, accessed, and manipulated. These structures are foundational in understanding more advanced algorithms and data structures, such as trees, graphs, and dynamic memory management techniques.
Open this section to load past papers