Non - Linear - DSA in JAVA
Non - Linear - DSA in JAVA
md 2024-08-20
A tree is a hierarchical data structure that consists of nodes connected by edges. It is a collection of nodes
where each node has a value, and possibly children, which are other nodes. The topmost node is called the
root, and the nodes at the bottom without children are called leaves.
Binary Trees: A tree where each node has at most two children, referred to as the left child and the
right child.
Binary Search Trees (BST): A binary tree with the additional property that for any node, all elements in
the left subtree are less than the node, and all elements in the right subtree are greater.
AVL Trees: A self-balancing binary search tree where the difference in heights between the left and
right subtrees cannot be more than one.
Red-Black Trees: A balanced binary search tree where each node has an extra bit for denoting the
color of the node, either red or black, which helps in balancing the tree during insertions and deletions.
2. Binary Trees
2.1 Structure of a Binary Tree
A binary tree is a tree in which each node has at most two children. These children are referred to as the left
child and the right child. A binary tree is defined by:
class Node {
int data;
Node left, right;
Traversal of a tree means visiting each node exactly once. There are three types of traversal:
1 / 14
Non_Linear_DSA.md 2024-08-20
inorder(node.left);
System.out.print(node.data + " ");
inorder(node.right);
}
Output:
Left Subtree: Contains nodes with values less than the root.
Right Subtree: Contains nodes with values greater than the root.
No Duplicate Nodes: All nodes are distinct.
To insert a node in BST, we start at the root and compare the node's value with the root's value. If the value is
less, we go to the left subtree; if it's more, we go to the right subtree.
2 / 14
Non_Linear_DSA.md 2024-08-20
return root;
}
Output:
After insertion:
5
/ \
3 7
/
6
4. AVL Trees
4.1 Introduction to Balanced Trees
AVL trees are self-balancing binary search trees. The height of two child subtrees of any node differs by at
most one.
Rotations are used to balance the tree when nodes are inserted or deleted. There are four types of rotations:
Left Rotation
Right Rotation
Left-Right Rotation
Right-Left Rotation
Insertion may cause the tree to become unbalanced, requiring rotations to balance it.
Node rightRotate(Node y) {
Node x = y.left;
Node T2 = x.right;
x.right = y;
y.left = T2;
return x;
}
3 / 14
Non_Linear_DSA.md 2024-08-20
Output:
Before Rotation:
30
/
20
/
10
5. Red-Black Trees
5.1 Properties of Red-Black Trees
During insertion, we follow the properties of the Red-Black tree and adjust colors and perform rotations if
necessary to maintain the balance.
6. Graphs
6.1 What is a Graph?
A graph is a data structure that consists of a set of vertices (nodes) and a set of edges connecting pairs of
vertices. Graphs can represent many real-world problems like social networks, maps, etc.
4 / 14
Non_Linear_DSA.md 2024-08-20
class Graph {
private LinkedList<Integer> adjLists[];
Graph(int vertices) {
adjLists = new LinkedList[vertices];
for (int i = 0; i < vertices; i++)
adjLists[i] = new LinkedList();
}
BFS starts at a selected node and explores all its neighbors before moving to the next level.
visited[start] = true;
queue.add(start);
5 / 14
Non_Linear_DSA.md 2024-08-20
while (queue.size() != 0) {
start = queue.poll();
System.out.print(start + " ");
Iterator<Integer> i = adjLists[start].listIterator();
while (i.hasNext()) {
int n = i.next();
if (!visited[n]) {
visited[n] = true;
queue.add(n);
}
}
}
}
Output:
Given Graph:
0-1-2
| |
3---4
void DFS(int v) {
boolean visited[] = new boolean[V];
DFSUtil(v, visited);
}
Iterator<Integer> i = adjLists[v].listIterator();
while (i.hasNext()) {
int n = i.next();
if (!visited[n])
DFSUtil(n, visited);
}
}
Output:
6 / 14
Non_Linear_DSA.md 2024-08-20
Given Graph:
0-1-2
| |
3---4
7. Hash Tables
7.1 Introduction to Hash Tables
A hash table is a data structure that stores key-value pairs. It uses a hash function to compute an index into an
array of buckets or slots, from which the desired value can be found.
A basic hash table implementation involves storing data in an array, with each index corresponding to a key.
class HashTable {
private int arr[];
private int size;
void display() {
for (int i = 0; i < size; i++) {
System.out.println(i + " -> " + arr[i]);
}
}
}
7 / 14
Non_Linear_DSA.md 2024-08-20
Output:
Hash Table:
0 -> -1
1 -> -1
2 -> 12
3 -> 22
4 -> 42
5 -> -1
6 -> -1
7 -> -1
8 -> -1
9 -> -1
When two keys hash to the same index, a collision occurs. There are several ways to handle collisions:
7.3.1 Chaining
In chaining, each bucket points to a linked list of entries that map to the same bucket. When a collision
occurs, the new entry is simply added to the list.
Example: Chaining
class HashTableChaining {
private LinkedList<Integer>[] table;
void display() {
for (int i = 0; i < table.length; i++) {
System.out.print(i + " -> ");
for (int key : table[i]) {
8 / 14
Non_Linear_DSA.md 2024-08-20
Output:
Open addressing is another method to handle collisions by finding another empty slot within the hash table
array itself. There are several strategies for open addressing:
Searches for the next Searches for the next available slot Uses a second hash function to
available slot sequentially. using a quadratic function. determine the next slot.
Simple and easy to Reduces clustering compared to Further reduces clustering and
implement. linear probing. offers better performance.
Example: index = (hash + Example: index = (hash + i^2) % Example: index = (hash + i *
i) % size size hash2(key)) % size
8. Practice
9 / 14
Non_Linear_DSA.md 2024-08-20
Inorder Traversal
inorder(node.left);
System.out.print(node.data + " ");
inorder(node.right);
}
Example Output:
Output: 4 2 5 1 3
Preorder Traversal
Example Output:
Output: 1 2 4 5 3
10 / 14
Non_Linear_DSA.md 2024-08-20
Postorder Traversal
postorder(node.left);
postorder(node.right);
System.out.print(node.data + " ");
}
Example Output:
Output: 4 5 2 3 1
visited[start] = true;
queue.add(start);
while (queue.size() != 0) {
start = queue.poll();
System.out.print(start + " ");
Iterator<Integer> i = adjLists[start].listIterator();
while (i.hasNext()) {
int n = i.next();
if (!visited[n]) {
visited[n] = true;
queue.add(n);
}
}
11 / 14
Non_Linear_DSA.md 2024-08-20
}
}
Example Output:
Output: 0 1 3 2 4
void DFS(int v) {
boolean visited[] = new boolean[V];
DFSUtil(v, visited);
}
Iterator<Integer> i = adjLists[v].listIterator();
while (i.hasNext()) {
int n = i.next();
if (!visited[n])
DFSUtil(n, visited);
}
}
Example Output:
Output: 0 1 2 4 3
12 / 14
Non_Linear_DSA.md 2024-08-20
Example Solution:
Example Output:
Input: [1, 2, 3, 1]
Output: true
Input: [1, 2, 3, 4]
Output: false
Example Solution:
Example Output:
Input: ["eat","tea","tan","ate","nat","bat"]
Output: [["eat","tea","ate"],["tan","nat"],["bat"]]
13 / 14
Non_Linear_DSA.md 2024-08-20
Conclusion
This detailed guide covers all the essential concepts, differences, and practical implementations of Non-linear
Data Structures in Java. By following these explanations and code examples, beginners will be able to grasp
the fundamentals and start applying them in real-world scenarios.
14 / 14