Data Structures

Data Structures” relate to the association and storehouse of data in a way that allows effective access, revision, and manipulation. Data structures are essential in computer programming because they help programmers manage and work with data effectively. In the environment of the C programming language, you can apply colourful data structures using C’s features like arrays, pointers, structures, and dynamic memory allocation.

Data Structures
Data Structures

Introduction

Data structures are a fundamental concept in computer programming that allows programmers to organize and manipulate data efficiently. In the C programming language, there are several data structures that are commonly used, including arrays, linked lists, stacks, queues, and trees.

Basic Terminology

Then are some introductory languages associated with tree.

  1. knot A knot is an abecedarian part of a tree. It represents a single element or reality in the tree.
  2. Edge An edge is a link between two bumps in a tree. It represents the relationship between the bumps.
  3. Root The root is the topmost knot of the tree. It’s the starting point of the tree.
  4. Parent A parent knot is a knot that has one or more child bumps.
  5. Child A child knot is a knot that has a parent knot.

Elementary Data Organization

In C, there are several elementary data organizations, including:

  1. Variables: Variables are used to store data in memory, and they can be of different types, such as int, char, float, double, etc.
  2. Arrays: Arrays are a collection of elements of the same data type that are stored in contiguous memory locations. They can be one-dimensional or multidimensional.
  3. Structures: Structures are used to group together different types of data into a single unit, called a struct. A structure can contain multiple variables of different types.
  4. Unions: Unions are similar to structures, but they allow you to store different types of data in the same memory location.
  5. Pointers: Pointers are variables that store the memory address of another variable. They are commonly used to manipulate and access data in arrays, structures, and other data structures.

Data Structure Operations

In C, there are several data structure operations that can be performed on different data structures. Here are some of the most common data structure operations:

  1. Insertion: Adding a new element to a data structure at a specific location, such as the beginning, end, or a specific index.
  2. Deletion: Removing an element from a data structure at a specific location, such as the beginning, end, or a specific index.
  3. Search: Finding the location of an element in a data structure.
  4. Traversal: Visiting all the elements in a data structure in a specific order.
  5. Sorting: Rearranging the elements in a data structure in a specific order, such as ascending or descending.

Algorithm Complexity and Time-Space trade-off

Algorithm complexity and time-space trade-off are important concepts in computer science and programming that are applicable to many different programming languages, including C.

Algorithm complexity refers to the amount of time and resources an algorithm requires to execute. This can be measured in terms of time complexity, which refers to the number of operations an algorithm performs, and space complexity, which refers to the amount of memory an algorithm requires. The efficiency of an algorithm can be improved by reducing its time and space complexity.

Arrays

In C, an array is a data structure that stores a collection of rudiments of the same data type in a conterminous block of memory. Each element in an array can be penetrated using an indicator, which is an integer value that specifies the position of the element in the array.

Here’s an example of how to declare and initialize an array in C:

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

This declares an integer array called my_array that contains five elements and initializes it with the values 1, 2, 3, 4, and 5.

Array Definition

In computer programming, an array is a data structure that stores a collection of elements of the same data type in a contiguous block of memory. Each element in an array is identified by an index or a subscript, which is an integer value that specifies the position of the element in the array.

Single and Multidimensional Arrays

Single Arrays

A single-dimensional array, also known as a one-dimensional array, is a data structure that stores a collection of elements of the same data type in a linear or sequential order. The elements in a single-dimensional array are accessed using a single index or subscript that specifies the position of the element in the array. For example, an array of integers could be declared as follows in C

Multidimensional Arrays

A multidimensional array, also known as a two-dimensional or n-dimensional array, is a data structure that stores a collection of elements in a rectangular or cuboid arrangement. A multidimensional array can be visualized as a table or matrix with rows and columns. The elements in a multidimensional array are accessed using multiple indices or subscripts that specify the position of the element in each dimension of the array. For example, a two-dimensional array of integers could be declared as follows in C

Address calculation

Address calculation is the process of determining the memory address of a particular element in an array, given its index or subscript. When an array is declared in a program, the elements are allocated contiguous blocks of memory in the computer’s memory. The memory address of the first element in the array is determined by the compiler, and the addresses of the subsequent elements are calculated based on the data type and the size of the array.

Application of Arrays

Arrays are a fundamental data structure in computer programming, and they have numerous applications in various fields, including:

  1. Data storage and retrieval: Arrays are commonly used to store and retrieve large amounts of data, such as lists of numbers or strings. For example, an array of student grades can be used to store and retrieve the grades of multiple students.
  2. Sorting and searching: Arrays can be used to implement various sorting and searching algorithms, such as bubble sort, insertion sort, and binary search. These algorithms are commonly used in database management and information retrieval systems.
  3. Image processing: Arrays can be used to represent and manipulate digital images, where each element of the array represents a pixel value. Various image processing operations, such as filtering, edge detection, and segmentation, can be performed using arrays.
  4. Scientific computing: Arrays are widely used in scientific computing applications, such as simulations, numerical analysis, and signal processing. For example, an array of temperature readings can be used to analyze climate patterns over time.
  5. Games and simulations: Arrays are commonly used in game development and simulation programs to store and manipulate game states, player positions, and other game-related data.

Character String in C

A character string is a sequence of characters stored in consecutive memory locations, terminated by a null character \0. The null character is used to mark the end of the string and is not considered part of the string itself.

Character strings in C are represented using the char data type and are declared using the following syntax:

char str[SIZE];

Character String Operation

In C, character strings can be manipulated using a variety of built-in functions, which can perform operations such as copying, concatenating, comparing, and searching strings. Here are some of the most commonly used string functions in C:

  1. strlen() – returns the length of a string (excluding the null character)
  2. strcpy() – copies one string to another
  3. strcat() – concatenates two strings
  4. strcmp() – compares two strings
  5. strchr() – searches for a character in a string and returns a pointer to the first occurrence
  6. strstr() – searches for a substring in a string and returns a pointer to the first occurrence
  7. sprintf() – formats a string using a printf-style format string and writes the result to a buffer
  8. sscanf() – reads data from a string using a scarf-style format string
  9. strtok() – splits a string into tokens based on a delimiter character or substring

Array as Parameters

In C, arrays can be passed as parameters to functions, allowing you to write functions that operate on arrays of any size and shape. When you pass an array to a function, you can either pass the array directly, or you can pass a pointer to the first element of the array.

Ordered List

An ordered list is a data structure where elements are stored in a specific order. Each element in the list contains a key and a value. The key is used to determine the position of the element in the list. An ordered list is useful in situations where the data needs to be accessed in a specific order.

In C, an ordered list can be implemented using an array or a linked list. If an array is used, the elements can be sorted using a sorting algorithm such as bubble sort or quicksort. If a linked list is used, the elements can be sorted as they are inserted into the list.

Sparse Matrices

An ordered list is a data structure where elements are stored in a specific order. Each element in the list contains a key and a value. The key is used to determine the position of the element in the list. An ordered list is useful in situations where the data needs to be accessed in a specific order.

In C, an ordered list can be implemented using an array or a linked list. If an array is used, the elements can be sorted using a sorting algorithm such as bubble sort or quicksort. If a linked list is used, the elements can be sorted as they are inserted into the list.

Linked Lists

A linked list is a dynamic data structure in which each element, called a node, is linked to the next node using a pointer. Each node contains two parts: data and the pointer to the next node.

In C, a linked list can be implemented using a struct to define the node and pointers to connect the nodes.

For example:

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

Singly Linked Lists Representation

A singly linked list is a linear data structure that consists of nodes linked together by pointers. Each node in the list contains two fields: a data field that holds the value of the element stored in the node, and a next field that contains a pointer to the next node in the list.

Singly Linked List Implementation

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

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

struct Node *head = NULL;

void insert(int data) {
    struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;

    if (head == NULL) {
        head = newNode;
    } else {
        struct Node *temp = head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
}

void delete(int data) {
    if (head == NULL) {
        printf("List is empty\n");
        return;
    }

    if (head->data == data) {
        struct Node *temp = head;
        head = head->next;
        free(temp);
        return;
    }

    struct Node *prev = head;
    struct Node *curr = head->next;
    while (curr != NULL && curr->data != data) {
        prev = curr;
        curr = curr->next;
    }

    if (curr == NULL) {
        printf("Data not found\n");
        return;
    }

    prev->next = curr->next;
    free(curr);
}

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

int main() {
    insert(1);
    insert(2);
    insert(3);
    insert(4);
    insert(5);
    display();

    delete(3);
    delete(6);
    display();

    return 0;
}

Two-way Header List

A two-way header list is a type of linked list in which each node has two pointers, one pointing to the next node in the list and the other pointing to the previous node. Additionally, there are two special nodes called header nodes that mark the beginning and end of the list.

To implement a two-way header list in C, we can use the following struct definition:

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

Traversing and Searching of Linked Lis

Traversing and searching are important operations performed on linked lists. Traversing means visiting each node in the list, while searching means finding a node with a particular value or key.

Overflow and Underflow

Overflow and underflow are two common problems that can occur in linked lists.

Overflow occurs when there is not enough memory to create a new node in the linked list. This can happen when the linked list is full or when there is not enough memory available in the system to allocate a new node. In some cases, overflow can be avoided by using dynamic memory allocation, which allows nodes to be created and deleted as needed. If overflow does occur, the program may crash or terminate abnormally.

Insertion and deletion from Linked Lists

Insertion

Insertion refers to adding a new node to the linked list. There are several ways to insert a new node into a linked list

  1. Insert at the beginning
  2. Insert at the end
  3. Insert at a specific position

Deletion

Deletion refers to removing a node from the linked list. There are several ways to delete a node from a linked list:

  1. Delete the head
  2. Delete the tail

Insertion and Deletion Algorithms

In digital electronics, insertion and deletion algorithms are commonly used in data structures such as arrays, linked lists, and binary search trees. These algorithms allow for efficient adding or removing of elements from these data structures.

Here is an example implementation of insertion and deletion algorithms for an array data structure in C:

Doubly linked list

A doubly linked list is a data structure that consists of a sequence of bumps, each containing two pointers, one to the former knot and one to the coming knot in the list. Unlike an independently linked list, which only has a pointer to the coming knot, a twice-linked list can be covered in both forward and backward directions.

Linked List of Array

A linked list of arrays is a data structure that consists of a sequence of arrays, each containing a fixed number of elements, where each array is linked to the next one in the list. This data structure is useful when we need to store a large number of elements that don’t fit into a single array.

Polynomial representation and addition

Polynomials are mathematical expressions consisting of one or more terms, where each term is the product of a coefficient and one or more variables raised to a non-negative integer power. Polynomials are commonly represented in computer science using arrays or linked lists.

Generalized linked list

A generalized linked list is a data structure that is a variation of the traditional linked list, where each node can point to either another node or to a data value, such as an integer, float, or string. This allows the generalized linked list to store not only nodes but also other data types.

Garbage Collection and Compaction

Garbage collection and contraction are two ways used in memory operation to optimize the use of memory in a computer system. G C is the process of automatically freeing up memory that’s no longer being used by a program. When an object is created in memory, it’s allocated a certain quantum of memory space. However, the memory space allocated to it’s considered” scrap” and can be reclaimed by the system, If that object is no longer being used by the program. Garbage collection is performed by the runtime terrain of a programming language or operating system, which periodically checks the memory space to identify and collect unused objects.

Stacks

A mound is a direct data structure that follows the Last-In-First-eschewal ( LIFO) principle. This means that the element which is fitted last will be the first one to be removed.

A mound has two primary operations

  1. Push Adds an element to the top of the mound.
  2. Pop Removes the element from the top of the mound.

Array Implementation of stack

In an array implementation of a stack, we use an array to store the mound rudiments. The array has a fixed size and is generally initialized with a maximum capacity. A pointer variable, generally called top, is used to keep track of the topmost element in the mound. The top variable is originally set to 1 to indicate an empty mound.

Operations and Stacks

In computer wisdom, an operation is a function or a set of instructions that are performed on data to produce a result. Operations can range from simple computation operations like addition and deduction to more complex operations like sorting and searching.

A mound is a data structure that stores and retrieves data grounded on the principle of last-in, first-out ( LIFO). In a mound, the last item added to the mound is the first one to be removed. This means that the most recently added item is always at the top of the mound, and any item added before it will be below it.

Push and POP

Push and Pop are the two primary operations performed on a stack data structure. These operations are used to add and remove elements from the top of the stack, respectively.

Array Representation of Stack

In an array representation of a stack, we use an array to store the elements of the stack. The top of the stack is represented by an index pointing to the last inserted element in the array.

Linked Representation of stack

In a linked representation of a stack, instead of using an array to store the elements, we use a linked list. Each node in the linked list contains an element of the stack and a pointer to the next node in the list.

Application of stack

Stacks have a wide range of applications in computer science, including:

  1. Function calls and recursion: When a function is called, the system pushes the return address and other information onto the stack. When the function returns, the system pops the information off the stack to return to the calling function. This allows for recursive function calls, where a function can call itself multiple times.
  2. Expression evaluation: Stacks can be used to evaluate arithmetic expressions, such as postfix expressions. In a postfix expression, the operator comes after the operands, so the expression is evaluated from left to right using a stack.
  3. Parsing: Stacks can be used in parsing algorithms, such as the shunting-yard algorithm, to convert an infix expression to postfix notation.
  4. Undo/redo functionality: Stacks can be used to implement undo and redo functionality in software applications. Each operation is pushed onto a stack, and undoing an operation pops it off the stack and reverses the operation.
  5. History in web browsers: When a user navigates through a website, each page is pushed onto a stack. When the user clicks the back button, the previous page is popped off the stack and displayed.

Conversion of Infix to Prefix and Postfix Expressions

Converting an infix expression to a postfix or prefix memorandum involves rearranging the expression so that the operands appear in the correct order relative to the drivers. One way to do this is to use a mound to keep track of the drivers in the expression.

Then is an algorithm for converting an infix expression to a postfix memorandum

  1. produces an empty mound to hold drivers.
  2. overlook the infix expression from left to right.
  3. still, affair it to the postfix expression, If the current commemorative is an operand.
  4. still, push it onto the mound, If the current commemorative is a driver.
  5. still, push it onto the mound, If the current commemorative is a left gap.

Evaluation of postfix expression using stack

To estimate a postfix expression using a mound, we can use the following algorithm

  1. To produce an empty mound to hold operands.
  2. overlook the postfix expression from left to right.
  3. still, push it onto the mound, If the current commemorative is an operand.
  4. still, pop two operands off the mound, and apply the driver to them in the correct order, If the current commemorative is a driver.
  5. After surveying the entire expression, the result should be the only value left on the mound.

Recursion

Recursion is a programming technique in which a function calls itself to solve a problem. The idea is to break down a complex problem into simpler subproblems and solve each subproblem by calling the same function recursively.

Recursive definition and processes

A recursive definition is a definition that uses the term being defined in its own definition. In other words, a recursive definition is one that defines something in terms of itself.

For example, a recursive definition of the factorial function can be given as follows:

Base case: 0! = 1
Recursive case: n! = n * (n-1)!
This definition defines the factorial function in terms of itself. The base case is the simplest case that can be solved without any further recursion. The recursive case uses the same function (factorial) to solve a simpler subproblem (n-1).

A recursive process is a process that involves a function calling itself. When a function calls itself, it creates a new instance of itself on the call stack. The call stack is a data structure that stores information about each function call, including the parameters and local variables.

Queue

A line is a direct data structure in which rudiments are added from one end and removed from the other end. It follows the First-In- First-Out (FIFO) principle, which means the element that’s added first will be removed first.

Array representation and implementation of a queue

In an array representation of a queue, we use a fixed-size array to hold the elements of the queue. We maintain two pointers, front and rear, which point to the first and last elements of the queue, respectively. Initially, both front and rear point to -1, indicating that the queue is empty.

Linked representation and implementation of a queue

In a linked representation of a queue, we use a linked list to hold the elements of the queue. Each node of the linked list contains an element and a pointer to the next node. We maintain two pointers, front and rear, which point to the first and last nodes of the queue, respectively. Initially, both front and rear point to NULL, indicating that the queue is empty.

Operations on Queue

The two main operations that can be performed on a line are

1. Enqueue :

This operation adds an element to the hinder end of the line. The recently added element becomes the last element of the queue. However, the element becomes both the first and last element of the line, If the line is empty. The enqueue operation is also known as” drive” or” fit “.

2. Dequeue

This operation removes an element from the frontal end of the line. The element that’s removed is the first element of the queue. However, there are no first or last rudiments in the line, If the line becomes empty after the element is removed. The dequeue operation is also known as” pop” or” cancel”.

Trees

Trees are a type of data structure used in computer wisdom and information technology to represent hierarchical connections between data rudiments. A tree consists of bumps, which are connected by edges. The topmost knot of the tree is called the root, while bumps with no children are called leaves. Each knot in a tree can have zero or further child bumps, and each child knot can have its own child bumps, forming a branching structure.

Basic Terminology

Then are some introductory languages associated with tree.

  1. knot A knot is an abecedarian part of a tree. It represents a single element or reality in the tree.
  2. Edge An edge is a link between two bumps in a tree. It represents the relationship between the bumps.
  3. Root The root is the topmost knot of the tree. It’s the starting point of the tree.
  4. Parent A parent knot is a knot that has one or more child bumps.
  5. Child A child knot is a knot that has a parent knot.

Binary Tree

A binary tree is a tree data structure where each knot can have at most two children, which are appertained to as the left child and the right child. Each knot in a double tree contains a value or data and two pointers, one pointing to its left child and the other pointing to its right child.

Binary tree representation Algebraic Expressions

Binary tree representation of algebraic expressions is a common way of representing expressions in computer science and mathematics. In this representation, each node in the tree corresponds to an operator or an operand, and the edges represent the operands that the operator is operating on.

Complete Binary Tree

A complete binary tree is a binary tree in which every level of the tree is completely filled, except possibly for the last level. In the last level, all the nodes must be as far left as possible.

More specifically, a binary tree is considered complete if all levels except possibly the last are completely filled, and all nodes in the last level are as far left as possible.

Extended Binary Tree

An Extended Binary Tree (EBT) is a binary tree in which every internal node has exactly two children, and at least one leaf node is replaced by an interior node called an external node, and each external node has exactly one child.

Array Representation of a Binary Tree

In the array representation of a binary tree, the nodes are stored in an array according to their level order traversal. That is, the root node is stored in the first element of the array, the left child of the root is stored in the second element, the right child of the root is stored in the third element, and so on. If a node does not have a child, its corresponding array element is set to a special value such as null. This representation allows for efficient indexing and random access to the nodes of the tree. However, it can waste space if the tree is not full, and it can be difficult to resize the array if the tree needs to be modified.

Linked Representation of a Binary Tree

In the linked representation of a binary tree, each node is represented as an object or a struct that contains a value and two pointers to its left and right children. The root node is represented by a pointer to the object that contains its value and child pointers. This representation allows for dynamic resizing of the tree and efficient memory usage, but it can be more difficult to traverse the tree efficiently compared to the array representation.

Traversing Binary Trees

Covering a double tree means visiting every knot in the tree exactly formerly in some order. There are three common ways to cut a double tree

  1. In-order traversal.
  2. Pre-order traversal.
  3. Post-order traversal.

Threaded Binary Trees

A threaded binary tree is a binary tree data structure that allows for efficient traversal of the tree without the use of a stack or recursion. In a threaded binary tree, certain nodes have additional links, called threads, that connect them to their in-order predecessor or successor.

Traversing Threaded Binary Trees

Traversing a threaded binary tree involves visiting each node in a particular order. A threaded binary tree is a binary tree that has additional threads, which are pointers that link nodes to their in-order successor or predecessor.

There are three types of traversals for threaded binary trees:

  1. Inorder traversal.
  2. Preorder traversal.
  3. Postorder traversal.

Huffman Algorithm

The Huffman algorithm is a data compression algorithm that was invented by David A. Huffman in 1952. The goal of the algorithm is to compress a file by encoding the most frequent characters with shorter binary codes and the least frequent characters with longer binary codes. The algorithm works by building a binary tree called the Huffman tree, which is based on the frequency of each character in the file.

Binary Search (BST)

A binary search tree (BST) is a type of binary tree data structure where each node has at most two child nodes, referred to as the left child and the right child.

In a BST, the left child of a node contains a key smaller than the parent node’s key, and the right child contains a key greater than or equal to the parent node’s key. This property ensures that the tree is ordered in a specific way, making searching, insertion, and deletion operations efficient.

Insertion in BST

To insert a new node into a BST, we follow the following steps:

  1. If the tree is empty, then create a new node and make it the root of the tree.
  2. If the value of the new node is less than the value of the current node, then move to the left subtree of the current node.
  3. If the value of the new node is greater than the value of the current node, then move to the right subtree of the current node.
  4. Repeat steps 2 and 3 until a suitable empty position is found, then create a new node there.

Deletion in BST

Deletion of a node in a BST can be a bit more complicated than insertion. Here are the steps we need to follow to delete a node from a BST:

  1. Find the node to be deleted.
  2. Still, simply remove it from the tree, If the knot has no children.
  3. If the node has only one child, replace the node with its child.
  4. If the node has two children, find the node with the next highest value (i.e., the leftmost node in the right subtree), swap its value with the node to be deleted, and then delete that node.

Sorting

Sorting is the process of arranging rudiments or data in a particular order. The order can be thrusting or descending, grounded on some criteria like numerical value, alphabetical order, or any other characteristic that can be compared.

Selection Sort

A sorting algorithm that selects the smallest element from the unsorted portion of the array and places it at the beginning of the sorted portion.

Insertion Sort

A sorting algorithm that iterates through the list, comparing each element with the elements before it and shifting them if necessary.

Bubble sort

A simple algorithm that constantly compares conterminous rudiments and barters them if they’re in the wrong order.

Quick Sort

A divide-and-conquer algorithm that selects a pivot element, partitions the array into two sub-arrays according to the pivot, and then recursively sorts the sub-arrays.

Searching

Searching refers to the process of finding a specific element in a data structure or a database. It is a fundamental operation in computer science and is used in many applications, such as searching for a word in a document, searching for a product in an online store, or searching for a record in a database.

Hashing

Hashing, on the other hand, is a technique used for efficient data storage and retrieval. It involves the use of a hash function that takes an input (usually a key) and maps it to a unique value in a hash table. The hash table is a data structure that stores the values associated with each key. Hashing is commonly used in databases, file systems, and in implementing data structures such as hash maps and hash sets.

Merge Sort Sequential

Merge Sort is a popular sorting algorithm that uses the divide-and-conquer technique to sort a given list of elements. The algorithm divides the input list into two halves, sorts each half recursively, and then merges the sorted halves back together. Here are the steps to perform Merge Sort sequentially:

  1. Divide the unsorted list into two sub-lists, each containing roughly half of the original list.
  2. Recursively sort each sub-list by dividing it into smaller sub-lists until each sub-list contains only one element. A sub-list containing only one element is already sorted.
  3. Merge the sorted sub-lists back together to form the sorted list.

Binary searching

Binary searching is a searching algorithm that works by constantly dividing the hunt interval in half. It starts by comparing the middle element of the array with the target value to be searched. However, the hunt is successful, If the target value is equal to the middle element. else, if the target value is lower than the middle element, the hunt continues on the lower half of the array, else, the hunt continues on the upper half of the array. This process is repeated until the target value is set up or the hunt interval becomes empty.

Hash Table

A hash table, also known as a hash map, is a data structure that stores key-value pairs, where each key is unique. The key is used to index and retrieve the corresponding value from the hash table.

Hash tables use a hash function to map each key to a unique index in an array. The hash function takes the key as input and produces an integer, which is used as an index in the array. The value corresponding to the key is then stored at the index in the array.

Hash Function

A hash function is a mathematical function that takes in input data (usually a string of arbitrary length) and produces a fixed-size output value called a hash code or hash digest. The hash code is typically a unique and deterministic representation of the input data.

Collection Resolution Strategies.

Collection resolution strategies refer to the various methods used by businesses to collect debts owed by their customers. These strategies can range from friendly reminders to legal action, depending on the severity of the debt and the stage of the collection process. Some common collection resolution strategies include:

  1. Friendly reminders.
  2. Payment plans.
  3. Debt settlement.
  4. Legal action.
  5. Write-off.