0% found this document useful (0 votes)
4 views

Introduction to Data Structures

This document provides an introduction to data structures, detailing their importance in computer science for efficient data storage and management. It covers various types of data structures including arrays, linked lists, stacks, queues, trees, hash tables, and graphs, along with their operations and use cases. Additionally, it discusses pointers in C, their syntax, operations, and common pitfalls, as well as the basics of arrays in C programming.

Uploaded by

beled34468
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Introduction to Data Structures

This document provides an introduction to data structures, detailing their importance in computer science for efficient data storage and management. It covers various types of data structures including arrays, linked lists, stacks, queues, trees, hash tables, and graphs, along with their operations and use cases. Additionally, it discusses pointers in C, their syntax, operations, and common pitfalls, as well as the basics of arrays in C programming.

Uploaded by

beled34468
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 16

Introduction to Data Structures

Data structures are fundamental concepts in computer science that allow us to efficiently store,
organize, and manage data. They are essential for designing algorithms that operate on data,
optimizing time and space complexity, and solving various computational problems effectively.

Here’s an introduction to the main types of data structures:

1. Arrays

 Description: An array is a collection of elements identified by index or key. All elements


in an array are of the same type and stored in contiguous memory locations.
 Operations:
o Access: Fast (constant time O(1))
o Insertion/Deletion: Slow (linear time O(n)) unless done at the end
 Use case: Suitable for situations where quick access to elements by index is required.

2. Linked Lists

 Description: A linked list is a linear data structure where each element (node) points to
the next element. Unlike arrays, linked lists are not stored in contiguous memory
locations.
 Types:
o Singly Linked List: Each node points to the next node.
o Doubly Linked List: Each node points to both the next and the previous node.
 Operations:
o Access: Linear time O(n)
o Insertion/Deletion: Efficient at the beginning or middle (constant time O(1) at
head or tail)
 Use case: Ideal for applications where frequent insertion and deletion operations are
required.

3. Stacks

 Description: A stack is a linear data structure that follows the Last In, First Out (LIFO)
principle. It supports two primary operations:
o Push: Add an element to the top of the stack.
o Pop: Remove the top element.
 Operations:
o Push/Pop: O(1) time
o Peek: O(1) time
 Use case: Used in scenarios like function calls, undo operations, and expression
evaluation.

4. Queues
 Description: A queue is a linear data structure that follows the First In, First Out (FIFO)
principle. It supports two main operations:
o Enqueue: Add an element to the rear.
o Dequeue: Remove an element from the front.
 Operations:
o Enqueue/Dequeue: O(1) time
 Use case: Ideal for scheduling tasks, buffering, or handling requests in a system.

5. Trees

 Description: A tree is a hierarchical data structure consisting of nodes, with each node
containing a value and references to child nodes. The topmost node is the root, and nodes
with no children are leaves.
 Types:
o Binary Tree: Each node has at most two children.
o Binary Search Tree (BST): A binary tree with the property that the left child is
smaller and the right child is larger than the parent node.
o AVL Tree, Red-Black Tree: Self-balancing binary search trees that maintain
their balance to ensure efficient searching, insertion, and deletion.
 Operations:
o Search: O(log n) for balanced trees (worst-case O(n) for unbalanced)
o Insertion/Deletion: O(log n) for balanced trees
 Use case: Used in hierarchical data storage, searching, and manipulation of sorted data.

6. Hash Tables

 Description: A hash table is a data structure that stores key-value pairs. It uses a hash
function to map keys to indices in an array, where values are stored.
 Operations:
o Insert: O(1) average time
o Search: O(1) average time
o Deletion: O(1) average time
 Use case: Ideal for fast lookups, such as implementing dictionaries, caching, or counting
occurrences.

7. Graphs

 Description: A graph is a non-linear data structure consisting of nodes (vertices) and


edges that connect the nodes. Graphs can be either directed (edges have a direction) or
undirected.
 Types:
o Directed Graph (Digraph): Edges have a direction.
o Undirected Graph: Edges have no direction.
o Weighted Graph: Edges have weights (costs).
o Unweighted Graph: Edges do not have weights.
 Operations:
o Traversal: Depth-First Search (DFS) and Breadth-First Search (BFS)
o Shortest Path: Algorithms like Dijkstra or Bellman-Ford
 Use case: Used in networking, social networks, and various route/pathfinding problems.

Why are Data Structures Important?

 Efficiency: Using the right data structure can drastically reduce the time complexity of
algorithms, leading to more efficient software.
 Optimization: Data structures help in optimizing both time and space in computational
tasks.
 Flexibility: They enable the efficient handling of a variety of tasks like searching,
sorting, updating, or manipulating large amounts of data.

Data structures are fundamental concepts in computer science that allow us to efficiently store,
organize, and manage data. They are essential for designing algorithms that operate on data,
optimizing time and space complexity, and solving various computational problems effectively.

Here’s an introduction to the main types of data structures:

1. Arrays

 Description: An array is a collection of elements identified by index or key. All elements


in an array are of the same type and stored in contiguous memory locations.
 Operations:
o Access: Fast (constant time O(1))
o Insertion/Deletion: Slow (linear time O(n)) unless done at the end
 Use case: Suitable for situations where quick access to elements by index is required.

2. Linked Lists

 Description: A linked list is a linear data structure where each element (node) points to
the next element. Unlike arrays, linked lists are not stored in contiguous memory
locations.
 Types:
o Singly Linked List: Each node points to the next node.
o Doubly Linked List: Each node points to both the next and the previous node.
 Operations:
o Access: Linear time O(n)
o Insertion/Deletion: Efficient at the beginning or middle (constant time O(1) at
head or tail)
 Use case: Ideal for applications where frequent insertion and deletion operations are
required.

3. Stacks
 Description: A stack is a linear data structure that follows the Last In, First Out (LIFO)
principle. It supports two primary operations:
o Push: Add an element to the top of the stack.
o Pop: Remove the top element.
 Operations:
o Push/Pop: O(1) time
o Peek: O(1) time
 Use case: Used in scenarios like function calls, undo operations, and expression
evaluation.

4. Queues

 Description: A queue is a linear data structure that follows the First In, First Out (FIFO)
principle. It supports two main operations:
o Enqueue: Add an element to the rear.
o Dequeue: Remove an element from the front.
 Operations:
o Enqueue/Dequeue: O(1) time
 Use case: Ideal for scheduling tasks, buffering, or handling requests in a system.

5. Trees

 Description: A tree is a hierarchical data structure consisting of nodes, with each node
containing a value and references to child nodes. The topmost node is the root, and nodes
with no children are leaves.
 Types:
o Binary Tree: Each node has at most two children.
o Binary Search Tree (BST): A binary tree with the property that the left child is
smaller and the right child is larger than the parent node.
o AVL Tree, Red-Black Tree: Self-balancing binary search trees that maintain
their balance to ensure efficient searching, insertion, and deletion.
 Operations:
o Search: O(log n) for balanced trees (worst-case O(n) for unbalanced)
o Insertion/Deletion: O(log n) for balanced trees
 Use case: Used in hierarchical data storage, searching, and manipulation of sorted data.

6. Hash Tables

 Description: A hash table is a data structure that stores key-value pairs. It uses a hash
function to map keys to indices in an array, where values are stored.
 Operations:
o Insert: O(1) average time
o Search: O(1) average time
o Deletion: O(1) average time
 Use case: Ideal for fast lookups, such as implementing dictionaries, caching, or counting
occurrences.
7. Graphs

 Description: A graph is a non-linear data structure consisting of nodes (vertices) and


edges that connect the nodes. Graphs can be either directed (edges have a direction) or
undirected.
 Types:
o Directed Graph (Digraph): Edges have a direction.
o Undirected Graph: Edges have no direction.
o Weighted Graph: Edges have weights (costs).
o Unweighted Graph: Edges do not have weights.
 Operations:
o Traversal: Depth-First Search (DFS) and Breadth-First Search (BFS)
o Shortest Path: Algorithms like Dijkstra or Bellman-Ford
 Use case: Used in networking, social networks, and various route/pathfinding problems.

Why are Data Structures Important?

 Efficiency: Using the right data structure can drastically reduce the time complexity of
algorithms, leading to more efficient software.
 Optimization: Data structures help in optimizing both time and space in computational
tasks.
 Flexibility: They enable the efficient handling of a variety of tasks like searching,
sorting, updating, or manipulating large amounts of data.

Pointers
Pointers in C are variables that store the memory address of another variable. Instead of holding
a data value directly (like an integer or a character), a pointer holds the location in memory
where the value is stored.

Key Concepts:

1. Memory Address: Every variable in a program is stored in memory, and each location in
memory has a unique address (just like an address for a house). Pointers allow us to work
with these addresses directly.
2. Dereferencing: Dereferencing a pointer means accessing the value stored at the memory
address it points to. In C, this is done using the * operator.
3. Pointer Variables: A pointer variable is declared to hold the address of a specific data
type, such as an int, float, or char.

Syntax:

 Pointer Declaration:

c
Copy
type *pointer_name;

o Here, type is the data type the pointer will point to, and * indicates that the
variable is a pointer.
 Pointer Initialization: You assign the memory address of a variable to a pointer:

c
Copy
int num = 5;
int *ptr = # // ptr now points to the memory address of num

o The & operator is used to get the memory address of the variable.
 Dereferencing: You access the value stored at the memory address by using *:

c
Copy
printf("%d", *ptr); // Dereferencing ptr gives the value of num (5)

Example of Pointers in C:
c
Copy
#include <stdio.h>

int main() {
int num = 10; // Regular integer variable
int *ptr = &num; // Pointer that stores the memory address of num

// Printing values
printf("Value of num: %d\n", num); // Direct value
printf("Address of num: %p\n", (void*)&num); // Memory address of num
printf("Value of ptr (address stored): %p\n", (void*)ptr); // Address
stored in pointer
printf("Value pointed to by ptr: %d\n", *ptr); // Dereferencing ptr to get
the value

return 0;
}

Output:
Value of num: 10

Address of num: 0x7ffeefbff4ac // This is the memory address of num (it will
vary)

Value of ptr (address stored): 0x7ffeefbff4ac // Same address as num

Value pointed to by ptr: 10


Key Operations with Pointers:

1. Address-of operator (&): Used to get the memory address of a variable.

c
Copy
int num = 10;
int *ptr = &num; // ptr now holds the address of num

2. Dereference operator (*): Used to get the value stored at the memory address a pointer
is pointing to.

c
Copy
int num = 10;
int *ptr = &num;
printf("%d", *ptr); // Output will be 10

3. Pointer Arithmetic: You can perform arithmetic operations on pointers, such as


incrementing (ptr++), decrementing (ptr--), or adding/subtracting integers to move
between memory locations. This is most useful when dealing with arrays.

c
Copy
int arr[] = {1, 2, 3};
int *ptr = arr;
printf("%d", *(ptr + 1)); // Output will be 2 (accessing arr[1] via
pointer)

Why Use Pointers?

1. Efficiency: Pointers allow direct access to memory, which can make certain operations
faster. For example, when passing large data structures (like arrays) to functions, passing
a pointer is more efficient than passing a copy of the entire structure.
2. Dynamic Memory Allocation: Pointers are used in dynamic memory management with
functions like malloc(), calloc(), and free() to allocate and deallocate memory at
runtime.
3. Arrays and Strings: In C, arrays are essentially pointers to the first element of the array,
making pointers very useful for working with arrays and strings.
4. Function Arguments: Pointers allow functions to modify variables outside their scope
(by passing the memory address of a variable), making them essential for passing by
reference.

Common Pitfalls with Pointers:


1. Dangling Pointer: A pointer that references memory that has been freed. Dereferencing
such pointers leads to undefined behavior.
2. Null Pointer: A pointer that points to nothing (usually NULL), which can be checked
before dereferencing to avoid errors.
3. Memory Leaks: Failing to free dynamically allocated memory can lead to memory
leaks, where the memory is not reclaimed.

Introduction to Arrays in C

An array in C is a collection of elements of the same data type stored in contiguous memory
locations. It allows you to group multiple variables of the same type under a single name, making
it easier to manage and process a collection of data.

Arrays are widely used in C for tasks such as handling lists of numbers, storing characters in
strings, and working with data in a structured way.

Array Declaration

In C, an array is declared by specifying the data type, followed by the array name and the size of
the array (the number of elements it can hold).

c
Copy
type array_name[size];

 type: The data type of the elements (e.g., int, char, float).
 array_name: The name of the array.
 size: The number of elements the array can store.

Example:
c
Copy
int numbers[5]; // Declares an integer array 'numbers' of size 5

This creates an array that can store 5 integer values, with indices ranging from 0 to 4.

Initializing Arrays

Arrays can be initialized at the time of declaration by providing a list of values enclosed in curly
braces {}.

Example:
c
Copy
int numbers[5] = {1, 2, 3, 4, 5}; // Initializes the array with values

If the number of values provided is fewer than the size, the remaining elements will be initialized
to 0 for numeric types.

Example:
c
Copy
int numbers[5] = {1, 2}; // numbers will be {1, 2, 0, 0, 0}

If no values are specified, the array will contain garbage values unless explicitly initialized.

Accessing Array Elements

Array elements are accessed using an index. In C, the index of an array starts at 0, so the first
element is accessed with index 0, the second element with index 1, and so on.

Example:
c
Copy
int numbers[5] = {1, 2, 3, 4, 5};

printf("%d", numbers[0]); // Accessing the first element, prints 1


printf("%d", numbers[3]); // Accessing the fourth element, prints 4

Modifying Array Elements

You can modify the value of an element in an array by accessing it using its index.

Example:
c
Copy
numbers[2] = 10; // Modifies the third element to 10
printf("%d", numbers[2]); // Prints 10

Multidimensional Arrays

In addition to one-dimensional arrays, C supports multidimensional arrays. The most common


example is a 2D array, which can be thought of as a matrix or table.

Syntax for 2D Arrays:


c
Copy
type array_name[rows][columns];
Example:
c
Copy
int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};

Here, matrix is a 2D array with 2 rows and 3 columns. You can access elements like this:

c
Copy
printf("%d", matrix[0][1]); // Prints 2, the second element of the first row

Array Size

The size of an array must be specified at the time of declaration. The size cannot be changed
after the array has been declared.

Example:
c
Copy
int arr[5]; // Fixed size, cannot add more elements

If you need a dynamic array whose size can change at runtime, you must use dynamic memory
allocation with pointers (using malloc(), calloc(), or realloc()).

Arrays and Functions

You can pass arrays to functions in C, but when you pass an array, it is actually passing the
memory address (the pointer to the first element) rather than a copy of the array. This allows the
function to modify the original array.

Example of passing an array to a function:

#include <stdio.h>

void printArray(int arr[], int size) {

for (int i = 0; i < size; i++) {

printf("%d ", arr[i]);

}
printf("\n");

int main() {

int numbers[5] = {1, 2, 3, 4, 5};

printArray(numbers, 5); // Passes the array to the function

return 0;

Common Array Operations

1. Iterating through an array: You can use loops to iterate through the elements of an
array.

Example:
c
Copy
int numbers[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]); // Prints all elements of the array
}

2. Finding the length of an array: To find the length of an array, you can divide the total
size of the array by the size of one element.

Example:
c
Copy
int numbers[5] = {1, 2, 3, 4, 5};
int length = sizeof(numbers) / sizeof(numbers[0]); // 5
printf("Length of array: %d\n", length);

Important Points to Remember:

 Fixed Size: Once an array is declared with a size, it cannot be resized dynamically unless using
dynamic memory allocation techniques (like malloc() or realloc()).
 Indexing: Array indices in C start at 0. Accessing an index out of bounds (e.g., array[5] for an
array of size 5) leads to undefined behavior.
 Array Passing to Functions: Arrays are passed by reference to functions, so changes made to the
array within the function will affect the original array.
Introduction to Linked Lists

A linked list is a linear data structure that consists of a sequence of elements, called nodes,
where each node contains two components:

 Data: The value or information the node is storing.


 Pointer (Next): A reference (memory address) to the next node in the list. This pointer helps to
connect the nodes together, forming a chain.

Unlike arrays, linked lists are not stored in contiguous memory locations, allowing for efficient
insertion and deletion of elements at any position.

Basic Structure of a Linked List

A node in a linked list typically looks like this in C:

c
Copy
struct Node {
int data; // The data held by the node
struct Node* next; // Pointer to the next node in the list
};

In the above structure:

 data stores the value of the node.


 next is a pointer to the next node in the list (or NULL if it's the last node).

Types of Linked Lists

1. Singly Linked List: Each node points to the next node in the sequence. The last node's
next pointer is NULL, marking the end of the list.
2. Doubly Linked List: Each node has two pointers: one pointing to the next node and
another pointing to the previous node. This allows traversal in both directions.
3. Circular Linked List: The last node's next pointer points back to the first node, forming
a circle.

Basic Operations on Linked Lists

1. Traversal: Visiting each node of the list and processing its data.
2. Insertion:
o Insert a node at the beginning of the list.
o Insert a node at the end of the list.
o Insert a node at a specific position in the list.

3. Deletion:
o Delete the first node.
o Delete the last node.
o Delete a node at a specific position in the list.

4. Searching: Find if a specific element exists in the list.

Implementing a Singly Linked List in C

Node Definition
c
Copy
#include <stdio.h>
#include <stdlib.h>

// Define the structure for a node


struct Node {
int data; // Data part
struct Node* next; // Pointer to the next node
};

Creating a New Node

To create a new node dynamically, we use malloc() to allocate memory for it and initialize the
data and next parts.

c
Copy
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL; // Initially, the next pointer is NULL
return newNode;
}

Inserting a Node at the Beginning

To insert a node at the beginning, we make the next pointer of the new node point to the current
head of the list, then update the head to point to the new node.

c
Copy
void insertAtBeginning(struct Node** head, int data) {
struct Node* newNode = createNode(data);
newNode->next = *head; // Point the new node to the current head
*head = newNode; // Update the head to the new node
}
Traversing the List

To traverse the list and print its elements, we start from the head and move through each node
using the next pointer.

c
Copy
void traverseList(struct Node* head) {
struct Node* current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}

Deleting the First Node

To delete the first node, we simply update the head to point to the second node and free the
memory allocated for the first node.

c
Copy
void deleteFirstNode(struct Node** head) {
if (*head == NULL) {
printf("List is empty.\n");
return;
}
struct Node* temp = *head;
*head = (*head)->next; // Update the head to the next node
free(temp); // Free the memory of the old head node
}

Full Example: Basic Linked List Operations


c
Copy
#include <stdio.h>
#include <stdlib.h>

// Define the structure for a node


struct Node {
int data;
struct Node* next;
};

// Function to create a new node


struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}

// Function to insert a node at the beginning


void insertAtBeginning(struct Node** head, int data) {
struct Node* newNode = createNode(data);
newNode->next = *head;
*head = newNode;
}

// Function to traverse the list


void traverseList(struct Node* head) {
struct Node* current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}

// Function to delete the first node


void deleteFirstNode(struct Node** head) {
if (*head == NULL) {
printf("List is empty.\n");
return;
}
struct Node* temp = *head;
*head = (*head)->next; // Update the head to the next node
free(temp); // Free the memory of the old head node
}

int main() {
struct Node* head = NULL; // Initially, the list is empty

// Insert elements at the beginning


insertAtBeginning(&head, 10);
insertAtBeginning(&head, 20);
insertAtBeginning(&head, 30);

// Traverse and print the list


printf("Linked List: ");
traverseList(head);

// Delete the first node


deleteFirstNode(&head);

// Traverse and print the list after deletion


printf("Linked List after deleting first node: ");
traverseList(head);

return 0;
}

Output:
rust
Copy
Linked List: 30 -> 20 -> 10 -> NULL
Linked List after deleting first node: 20 -> 10 -> NULL

Key Points to Remember:

1. Dynamic Memory Allocation: Unlike arrays, linked lists do not require contiguous
memory. Memory is dynamically allocated using malloc() or calloc().
2. Efficient Insertions/Deletions: Linked lists allow for efficient insertions and deletions at
the beginning and middle without needing to shift other elements, unlike arrays.
3. Traversal: Traversing a linked list requires starting from the head and following the
next pointer of each node.
4. No Random Access: Linked lists do not support random access like arrays. To access an
element, you must traverse the list from the head.

Advantages of Linked Lists:

 Dynamic Size: Linked lists can grow or shrink in size dynamically, unlike arrays, where the size is
fixed.
 Efficient Insertions and Deletions: Inserting or deleting elements at the beginning or middle of
the list is more efficient compared to arrays (no shifting required).

Disadvantages of Linked Lists:

 Memory Usage: Each node in a linked list requires additional memory for the pointer (next).
 No Random Access: You cannot directly access an element by its index like you can in arrays.

You might also like