0% found this document useful (0 votes)
13 views25 pages

Data Structures: Unit-I

The document provides an overview of data structures, defining them as methods for organizing and managing data efficiently. It categorizes data structures into primitive and non-primitive types, detailing linear structures like arrays and linked lists, as well as non-linear structures like trees and graphs. Additionally, it discusses abstract data types (ADTs), their implementation in C++, and various operations associated with arrays and specialized data structures.

Uploaded by

musthaq
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views25 pages

Data Structures: Unit-I

The document provides an overview of data structures, defining them as methods for organizing and managing data efficiently. It categorizes data structures into primitive and non-primitive types, detailing linear structures like arrays and linked lists, as well as non-linear structures like trees and graphs. Additionally, it discusses abstract data types (ADTs), their implementation in C++, and various operations associated with arrays and specialized data structures.

Uploaded by

musthaq
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 25

UNIT-I

Data Structures
Definition:
A data structure is a specific way of organizing, storing, and managing data in a computer so
that it can be efficiently accessed and modified. It provides a framework to organize data
based on the operations and algorithms applied to it.
Uses of Data Structures:
1. Efficient Data Management: Allows data to be stored and retrieved efficiently.
2. Algorithm Implementation: Many algorithms depend on data structures to process and
manipulate data.
3. Memory Optimization: Helps in the efficient use of memory space.
4. Real-world Applications: Powers applications like databases, operating systems,
search engines, and networks.
5. Problem Solving: Provides tools for solving complex problems by structuring the
problem data.
Types of Data Structures:
Data structures are broadly classified into two categories:

1. Primitive Data Structures


 These are basic structures provided by programming languages.
 Examples: Integer, Float, Character, Boolean

2. Non-Primitive Data Structures


These are more complex and can be further divided into:
a. Linear Data Structures
Data is organized sequentially, one after another.
1. Array: A collection of elements of the same type stored in contiguous memory.
o Example: [1, 2, 3, 4]
o Uses: Sorting, searching, matrix operations.
2. Linked List: A sequence of nodes where each node points to the next.
o Example: Node1 -> Node2 -> Node3
o Uses: Dynamic memory allocation, efficient insertion/deletion.
3. Stack: A collection of elements with a Last-In-First-Out (LIFO) principle.
o Example: A stack of plates.
o Uses: Undo functionality, syntax parsing, expression evaluation.
4. Queue: A collection of elements with a First-In-First-Out (FIFO) principle.
o Example: People in a line.
o Uses: Task scheduling, data buffering.

b. Non-Linear Data Structures


Data is organized hierarchically or in a network.
1. Tree: A hierarchical structure with nodes connected by edges.
o Types: Binary Tree, Binary Search Tree, AVL Tree, etc.
o Uses: Databases, file systems, AI decision trees.
2. Graph: A collection of nodes (vertices) and edges representing relationships.
o Types: Directed, Undirected, Weighted.
o Uses: Social networks, routing, web crawling.

c. Hashing
 Uses a hash function to map keys to values.
 Uses: Indexing, caches, associative arrays.

d. Specialized Data Structures


 Heap: Specialized tree-based structure (min-heap or max-heap).
o Uses: Priority queues, heap sort.
 Trie: A tree-like structure for storing strings.
o Uses: Autocomplete, dictionary implementation.
Arrays:
Abstract Data Types (ADTs):
An Abstract Data Type (ADT) is a high-level, mathematical model for data and the operations
that can be performed on it. It defines the what of data structure behavior (its operations and
properties) without specifying the how it will be implemented.
Key Features of ADTs:
1. Encapsulation: Only exposes the interface for operations, hiding implementation
details.
2. Independence: Can be implemented using different underlying data structures.
3. Focus on Functionality: Deals with operations like insertion, deletion, and access,
rather than the internal workings.
Examples of ADTs:
 List: Supports operations like append, remove, and traverse.
 Stack: Operations include push, pop, and peek (LIFO).
 Queue: Operations include enqueue, dequeue, and peek (FIFO).
 Deque: A double-ended queue supporting insertion and removal at both ends.
 Map: Key-value pair operations like insert, delete, and search.

C++ Class and ADTs:


In C++, a class provides a way to implement ADTs by encapsulating data (member variables)
and operations (member functions) in a single construct.
How a C++ Class Represents an ADT:
1. Encapsulation:
o Data is kept private to restrict direct access.
o Public methods define the interface (operations) of the ADT.
2. Implementation Independence:
o The internal representation of data can change without affecting code that uses
the class.
3. Modularity:
o Classes separate the ADT definition (interface) from its implementation.
Example: Stack ADT as a C++ Class
cpp
Copy code
#include <iostream>
using namespace std;

class Stack {
private:
int* arr; // Pointer to stack array
int top; // Index of the top element
int capacity; // Maximum size of the stack

public:
// Constructor
Stack(int size) {
arr = new int[size];
capacity = size;
top = -1;
}

// Destructor
~Stack() {
delete[] arr;
}

// Push an element onto the stack


void push(int x) {
if (isFull()) {
cout << "Stack Overflow\n";
return;
}
arr[++top] = x;
}

// Pop an element from the stack


int pop() {
if (isEmpty()) {
cout << "Stack Underflow\n";
return -1; // Indicating error
}
return arr[top--];
}

// Peek at the top element


int peek() {
if (!isEmpty()) {
return arr[top];
}
cout << "Stack is empty\n";
return -1; // Indicating error
}

// Check if the stack is empty


bool isEmpty() {
return top == -1;
}

// Check if the stack is full


bool isFull() {
return top == capacity - 1;
}
};
// Example usage
int main() {
Stack s(5);

s.push(10);
s.push(20);
s.push(30);

cout << "Top element is: " << s.peek() << endl;

cout << "Popped element: " << s.pop() << endl;

s.push(40);

while (!s.isEmpty()) {
cout << "Popped element: " << s.pop() << endl;
}

return 0;
}
Explanation:
1. Private Section:
o Encapsulates data (arr, top, capacity) to protect it from unauthorized access.
2. Public Section:
o Defines the interface for stack operations (push, pop, peek, etc.).
3. Implementation Independence:
o Users of the Stack class interact with its interface, unaware of the underlying
implementation (array-based in this case).
Array as an Abstract Data Type (ADT):
An array is a fundamental Abstract Data Type (ADT) that represents a
collection of elements, where each element is identified by an index or
subscript. The array ADT specifies the operations that can be performed on the
array but does not dictate the specific implementation.
Array ADT Definition:
 Data: A collection of elements of the same data type stored in a
contiguous block of memory.
 Operations:
1. Access an element by its index.
2. Update an element at a specific index.
3. Traverse through all elements.
4. Search for an element.
5. Insert or delete elements (though this is not efficient in static
arrays).

Characteristics of Array ADT:


1. Fixed Size:
o In most implementations, the size of the array is defined when it is
created and cannot be changed (static arrays). Dynamic arrays (like
vectors in C++) provide flexibility.
2. Random Access:
o Elements can be accessed directly using an index in O(1) time.
3. Efficient Storage:
o Elements are stored in contiguous memory locations.
4. Homogeneous Data:
o All elements must be of the same data type.

Operations Supported by Array ADT:


Here are some standard operations and their time complexities:
Operation Description Time Complexity
Retrieve or modify an
Access O(1)O(1)O(1)
element by index
Find an element (linear O(n)O(n)O(n) or O(log⁡n)O(\log
Search
search or binary search) n)O(logn) (sorted)
Insert (at Add an element at a specific
O(n)O(n)O(n)
index) index
Delete (at Remove an element at a
O(n)O(n)O(n)
index) specific index
Traverse Visit all elements O(n)O(n)O(n)

Implementation of Array ADT in C++:


Here’s a simple implementation of an array ADT using a C++ class:
cpp
Copy code
#include <iostream>
using namespace std;

class Array {
private:
int* arr; // Pointer to the array
int size; // Current number of elements
int capacity; // Maximum capacity of the array

public:
// Constructor
Array(int capacity) {
this->capacity = capacity;
size = 0;
arr = new int[capacity];
}

// Destructor
~Array() {
delete[] arr;
}

// Access element at index


int get(int index) {
if (index >= 0 && index < size)
return arr[index];
else
throw out_of_range("Index out of range");
}

// Insert element at the end


void insert(int value) {
if (size == capacity) {
cout << "Array is full\n";
return;
}
arr[size++] = value;
}
// Delete element at a given index
void removeAt(int index) {
if (index < 0 || index >= size) {
cout << "Index out of range\n";
return;
}
for (int i = index; i < size - 1; i++) {
arr[i] = arr[i + 1];
}
size--;
}

// Display the array


void display() {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}

// Get current size


int getSize() {
return size;
}
};

// Example usage
int main() {
Array arr(5);

arr.insert(10);
arr.insert(20);
arr.insert(30);

cout << "Array elements: ";


arr.display();

cout << "Element at index 1: " << arr.get(1) << endl;

arr.removeAt(1);

cout << "Array after removal: ";


arr.display();

return 0;
}

Explanation of Implementation:
1. Encapsulation:
o Data (arr, size, capacity) is private to prevent direct modification.
o Public methods (insert, get, removeAt) define the interface.
2. Array Operations:
o get(index): Access an element.
o insert(value): Add an element (if space is available).
o removeAt(index): Delete an element and shift the rest.
3. Dynamic Behavior:
o Though the class uses a fixed-size array, dynamic resizing could be
implemented by allocating a larger array when the current one is
full.

Advantages and Disadvantages of Array ADT


Advantages:
 Direct Access: Efficient retrieval of elements.
 Predictable Memory Usage: Contiguous memory allocation makes
memory usage predictable.
Disadvantages:
 Fixed Size: Cannot resize static arrays once created.
 Costly Insert/Delete: Operations require shifting elements, making them
O(n)O(n)O(n).
 Wasted Space: If the array is not fully used, memory is wasted.
Representation of Arrays, Matrices, Special Matrices Sparse Matrices,
Strings:
1. Arrays
An array is a collection of elements stored in contiguous memory locations.
Each element can be accessed directly using its index.
Representation:
 1D Array: Linear collection of elements.
text
Copy code
Index: 0 1 2 3 4
Values: 10 20 30 40 50
 Memory Layout: Elements are stored in adjacent memory locations.
Storage in Memory:
If the array starts at address AAA and each element occupies BBB bytes:
 Address of the iii-th element = A+(i×B)A + (i \times B)A+(i×B).

2. Matrices
A matrix is a 2D array where elements are arranged in rows and columns.
Representation:
 Row-Major Order: Store elements row by row.
o Example: Matrix [1234]\begin{bmatrix} 1 & 2 \\ 3 & 4 \
end{bmatrix}[1324]
 Stored as: [1, 2, 3, 4]
 Address of (a[i][j] = \text{Base Address} + [(i \times \
text{Number of Columns}) + j] \times \text{Element Size}`.
 Column-Major Order: Store elements column by column.
o Stored as: [1, 3, 2, 4]
o Address of (a[i][j] = \text{Base Address} + [(j \times \text{Number
of Rows}) + i] \times \text{Element Size}`.

3. Special Matrices
These are matrices with specific patterns or properties that allow optimized
storage.
Types of Special Matrices:
1. Diagonal Matrix:
o Only the diagonal elements are non-zero.
o Example:
text
Copy code
1 0 0
0 2 0
0 0 3
o Storage: Store only diagonal elements in a 1D array: [1, 2, 3].
2. Triangular Matrix:
o Upper Triangular: Elements below the main diagonal are zero.
o Lower Triangular: Elements above the main diagonal are zero.
o Storage: Store non-zero elements in a 1D array (row or column-
wise).
3. Symmetric Matrix:
o Elements are symmetric about the diagonal (a[i][j]=a[j][i]a[i][j] =
a[j][i]a[i][j]=a[j][i]).
o Storage: Store only upper (or lower) triangular part.
4. Band Matrix:
o Non-zero elements are concentrated around the diagonal.
o Storage: Store only the bands in separate arrays.

4. Sparse Matrices
A sparse matrix is a matrix with a large number of zero elements.
Representation:
1. Array of Tuples:
o Each tuple stores (row, column, value) for non-zero elements.
o Example:
text
Copy code
Matrix:
0 0 3
0 4 0
5 0 0

Tuple Representation:
(row, col, value)
(0, 2, 3)
(1, 1, 4)
(2, 0, 5)
2. Compressed Sparse Row (CSR):
o Data Array: Stores non-zero values.
o Row Index Array: Indicates the start of each row in the data array.
o Column Index Array: Stores the column indices of non-zero values.
3. Compressed Sparse Column (CSC):
o Similar to CSR but organized column-wise.

5. Strings
A string is a sequence of characters terminated by a null character (\0) in
languages like C.
Representation:
 Contiguous Memory:
text
Copy code
"hello" -> ['h', 'e', 'l', 'l', 'o', '\0']
o Stored in contiguous memory locations.
o Length is determined by counting characters up to the null
terminator.
String as Abstract Data Type:
 Operations:
o Access: Retrieve a character by index.
o Concatenate: Join two strings.
o Substring: Extract a portion of the string.
o Compare: Check if two strings are equal.
Summary Table
Structure Description Storage Optimization
Array 1D collection of elements Contiguous memory
2D array (row-major or Use indexing formulas for
Matrix
column-major order) compact storage
Diagonal
Non-zero diagonal elements Store only diagonal elements
Matrix
Triangular Non-zero elements in triangular Store only non-zero triangular
Matrix regions elements
Use tuple or compressed
Sparse Matrix Large number of zeroes
formats
Contiguous memory with null
String Sequence of characters
termination

UNIT-II
Stacks and Queues
A stack is a linear data structure that follows the Last In, First Out (LIFO)
principle. Elements can only be added or removed from the top of the stack.
Key Operations:
1. Push: Add an element to the top of the stack.
2. Pop: Remove the top element of the stack.
3. Peek/Top: View the element at the top of the stack without removing it.
4. IsEmpty: Check if the stack is empty.
5. IsFull: Check if the stack is full (in case of a fixed-size stack).

Representation of Stacks:
Stacks can be represented using:
1. Arrays
2. Linked Lists
1. Stack Using Arrays
An array-based stack uses a fixed-size array to store elements.
Representation:
 A stack is represented using:
o Array: To hold the stack elements.
o Top Pointer: Points to the top element in the stack.
Implementation:
Here is a conceptual representation of a stack using an array:
text
Copy code
Array: [10, 20, 30, _, _, _]
Top: ^
Algorithms:
 Push:
1. Check if the stack is full (top == capacity - 1).
2. Increment the top pointer.
3. Add the new element at stack[top].
 Pop:
1. Check if the stack is empty (top == -1).
2. Retrieve the element at stack[top].
3. Decrement the top pointer.
 Peek:
1. Check if the stack is empty.
2. Return the element at stack[top].

C++ Implementation (Array-based Stack):


cpp
Copy code
#include <iostream>
using namespace std;

class Stack {
private:
int* arr;
int top;
int capacity;

public:
// Constructor
Stack(int size) {
arr = new int[size];
capacity = size;
top = -1;
}

// Destructor
~Stack() {
delete[] arr;
}

// Push operation
void push(int value) {
if (top == capacity - 1) {
cout << "Stack Overflow\n";
return;
}
arr[++top] = value;
}

// Pop operation
int pop() {
if (top == -1) {
cout << "Stack Underflow\n";
return -1;
}
return arr[top--];
}

// Peek operation
int peek() {
if (top == -1) {
cout << "Stack is empty\n";
return -1;
}
return arr[top];
}

// Check if the stack is empty


bool isEmpty() {
return top == -1;
}
};

// Example usage
int main() {
Stack stack(5);

stack.push(10);
stack.push(20);
stack.push(30);

cout << "Top element: " << stack.peek() << endl;

cout << "Popped element: " << stack.pop() << endl;

stack.push(40);

while (!stack.isEmpty()) {
cout << "Popped element: " << stack.pop() << endl;
}

return 0;
}

2. Stack Using Linked Lists


A linked list-based stack uses a dynamic structure where each node
represents an element.
Representation:
 A stack is represented as a linked list where:
o Each node contains:
1. Data: The value of the stack element.
2. Next: A pointer to the next node (or NULL for the bottom of
the stack).
o The top points to the first node (topmost element).
Implementation:
Here is a conceptual representation of a stack using a linked list:
text
Copy code
Top -> [30] -> [20] -> [10] -> NULL
Algorithms:
 Push:
1. Create a new node.
2. Set the next pointer of the new node to point to the current top.
3. Update the top pointer to the new node.
 Pop:
1. Check if the stack is empty (top == NULL).
2. Retrieve the data of the top node.
3. Move the top pointer to top->next.
4. Free the memory of the popped node.
 Peek:
1. Check if the stack is empty.
2. Return the data of the top node.

C++ Implementation (Linked List-based Stack):


cpp
Copy code
#include <iostream>
using namespace std;

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

class Stack {
private:
Node* top;

public:
// Constructor
Stack() {
top = nullptr;
}

// Push operation
void push(int value) {
Node* newNode = new Node();
newNode->data = value;
newNode->next = top;
top = newNode;
}

// Pop operation
int pop() {
if (top == nullptr) {
cout << "Stack Underflow\n";
return -1;
}
int value = top->data;
Node* temp = top;
top = top->next;
delete temp;
return value;
}

// Peek operation
int peek() {
if (top == nullptr) {
cout << "Stack is empty\n";
return -1;
}
return top->data;
}

// Check if the stack is empty


bool isEmpty() {
return top == nullptr;
}
};
// Example usage
int main() {
Stack stack;

stack.push(10);
stack.push(20);
stack.push(30);

cout << "Top element: " << stack.peek() << endl;

cout << "Popped element: " << stack.pop() << endl;

stack.push(40);

while (!stack.isEmpty()) {
cout << "Popped element: " << stack.pop() << endl;
}

return 0;
}

Comparison of Array and Linked List Representations


Linked List-Based
Aspect Array-Based Stack
Stack
Memory Fixed size, pre- Dynamic, grows/shrinks
Usage allocated as needed
Faster access (direct Slightly slower (pointer
Efficiency
indexing) traversal)
Linked List-Based
Aspect Array-Based Stack
Stack
Occurs when array No overflow (limited by
Overflow
size is exceeded system memory)
Occurs if trying to
Underflow Same
pop an empty stack

You might also like