Introduction :
In Java, a data structure is a way of organizing and storing data in memory. There are two types of data structures: static and dynamic.
Static data structures are those in which the size of the structure is fixed at compile time and cannot be changed at runtime. Examples of static data structures in Java include arrays, structs, and static tables. Since the size of these data structures is fixed, they are often used for small and simple data sets.
Dynamic data structures are those in which the size of the structure can be changed at runtime. Examples of dynamic data structures in Java include linked lists, stacks, queues, and trees. Since these data structures can grow or shrink as needed, they are often used for more complex and larger data sets.
The main advantage of dynamic data structures is their flexibility. They can grow or shrink as needed, which makes them more efficient for large data sets. On the other hand, static data structures can be more efficient for small data sets since they have a fixed size and require less overhead.
The data structure is a way of storing and organizing data efficiently such that the required operations on them can be performed efficiently concerning time as well as memory. Simply, Data Structure is used to reduce the complexity (mostly the time complexity) of the code. Data structures can be of two types:
Static Data structure
In the Static data structure, the size of the structure is fixed. The content of the data structure can be modified without changing the memory space allocated to it.
Examples of Static Data Structures:
Array
- An array is a container object that holds a fixed number of values of a single type. The length of an array is established when the array is created. An array is a group of like-typed variables that are referred to by a common name. Arrays in Java work differently than they do in C/C++. Syntax:
// Declaration type var-name[]; OR type[] var-name; // Initialization var-name = new type [size];
- Implementation:
Java
// Java Program to illustrate how to declare, instantiate, // initialize and print the Java array. class Testarray { public static void main(String args[]) { int a[] = new int [ 5 ]; // declaration and instantiation a[ 0 ] = 10 ; // initialization a[ 1 ] = 20 ; a[ 2 ] = 70 ; a[ 3 ] = 40 ; a[ 4 ] = 50 ; // traversing array for ( int i = 0 ; i < a.length; i++) // length is the property of array System.out.println(a[i]); } } // contributed by Jatin Sharma |
C++
#include <iostream> using namespace std; int main() { int arr[3][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; for ( int i = 0; i < 3; i++) { for ( int j = 0; j < 2; j++) { cout << "Element:" ; cout << arr[i][j] << endl; } } return 0; } |
Python3
class Testarray: def main(): a = [ 0 ] * 5 # declaration and instantiation a[ 0 ] = 10 # initialization a[ 1 ] = 20 a[ 2 ] = 70 a[ 3 ] = 40 a[ 4 ] = 50 # traversing array for i in range ( len (a)): # len() is the function to get the length of the array print (a[i]) Testarray.main() # calling the main method of the Testarray class |
10 20 70 40 50
- Problem with above Array implementation: Once we create the Array we cannot alter the size of the array. So the size of the array is unalterable.
Dynamic Data Structure
In Dynamic data structure, the size of the structure is not fixed and can be modified during the operations performed on it. Dynamic data structures are designed to facilitate change of data structures in the run time.
Examples of Dynamic Data Structures:
Singly Linked List
- Linked Lists are linear data structures where the elements are not stored in contiguous locations and every element is a separate object with a data part and address part. The elements are linked using pointers and addresses. Each element is known as a node. Due to the dynamicity and ease of insertions and deletions, they are preferred over the arrays.
C++
#include <iostream> using namespace std; struct Node { int data; struct Node* next; }; struct Node* head = NULL; void insert( int new_data) { struct Node* new_node = ( struct Node*) malloc ( sizeof ( struct Node)); new_node->data = new_data; new_node->next = head; head = new_node; } void display() { struct Node* ptr; ptr = head; while (ptr != NULL) { cout << ptr->data << " " ; ptr = ptr->next; } } int main() { insert(3); insert(1); insert(7); insert(2); insert(9); cout << "The linked list is: " ; display(); return 0; } |
Java
public class SinglyLinkedList { //Represent a node of the singly linked list class Node{ int data; Node next; public Node( int data) { this .data = data; this .next = null ; } } //Represent the head and tail of the singly linked list public Node head = null ; public Node tail = null ; //addNode() will add a new node to the list public void addNode( int data) { //Create a new node Node newNode = new Node(data); //Checks if the list is empty if (head == null ) { //If list is empty, both head and tail will point to new node head = newNode; tail = newNode; } else { //newNode will be added after tail such that tail's next will point to newNode tail.next = newNode; //newNode will become new tail of the list tail = newNode; } } //display() will display all the nodes present in the list public void display() { //Node current will point to head Node current = head; if (head == null ) { System.out.println( "List is empty" ); return ; } System.out.println( "Nodes of singly linked list: " ); while (current != null ) { //Prints each node by incrementing pointer System.out.print(current.data + " " ); current = current.next; } System.out.println(); } public static void main(String[] args) { SinglyLinkedList sList = new SinglyLinkedList(); //Add nodes to the list sList.addNode( 1 ); sList.addNode( 2 ); sList.addNode( 3 ); sList.addNode( 4 ); //Displays the nodes present in the list sList.display(); } } // Contributed by Jatin Sharma |
Python3
class SinglyLinkedList: class Node: def __init__( self , data): self .data = data self . next = None def __init__( self ): self .head = None self .tail = None def addNode( self , data): newNode = self .Node(data) if self .head is None : self .head = newNode self .tail = newNode else : self .tail. next = newNode self .tail = newNode def display( self ): current = self .head if self .head is None : print ( "List is empty" ) return print ( "Nodes of singly linked list: " ) while current is not None : print (current.data, end = " " ) current = current. next print () if __name__ = = '__main__' : sList = SinglyLinkedList() #Add nodes to the list sList.addNode( 1 ) sList.addNode( 2 ) sList.addNode( 3 ) sList.addNode( 4 ) #Displays the nodes present in the list sList.display() |
The linked list is: 9 2 7 1 3
Output 1:
The linked list is: 9 2 7 1 3
Output 2:
Nodes of singly linked list: 1 2 3 4
Doubly Linked List
- A Doubly Linked List (DLL) contains an extra pointer, typically called the previous pointer, together with next pointer and data which are there in a singly linked list.
Java
public class DoublyLinkedList { //Represent a node of the doubly linked list class Node{ int data; Node previous; Node next; public Node( int data) { this .data = data; } } //Represent the head and tail of the doubly linked list Node head, tail = null ; //addNode() will add a node to the list public void addNode( int data) { //Create a new node Node newNode = new Node(data); //If list is empty if (head == null ) { //Both head and tail will point to newNode head = tail = newNode; //head's previous will point to null head.previous = null ; //tail's next will point to null, as it is the last node of the list tail.next = null ; } else { //newNode will be added after tail such that tail's next will point to newNode tail.next = newNode; //newNode's previous will point to tail newNode.previous = tail; //newNode will become new tail tail = newNode; //As it is last node, tail's next will point to null tail.next = null ; } } //display() will print out the nodes of the list public void display() { //Node current will point to head Node current = head; if (head == null ) { System.out.println( "List is empty" ); return ; } System.out.println( "Nodes of doubly linked list: " ); while (current != null ) { //Prints each node by incrementing the pointer. System.out.print(current.data + " " ); current = current.next; } } public static void main(String[] args) { DoublyLinkedList dList = new DoublyLinkedList(); //Add nodes to the list dList.addNode( 1 ); dList.addNode( 2 ); dList.addNode( 3 ); dList.addNode( 4 ); dList.addNode( 5 ); //Displays the nodes present in the list dList.display(); } } //by Jatin Sharma |
C++
#include <iostream> using namespace std; struct Node { int data; struct Node* prev; struct Node* next; }; struct Node* head = NULL; void insert( int newdata) { struct Node* newnode = ( struct Node*) malloc ( sizeof ( struct Node)); newnode->data = newdata; newnode->prev = NULL; newnode->next = head; if (head != NULL) head->prev = newnode; head = newnode; } void display() { struct Node* ptr; ptr = head; while (ptr != NULL) { cout << ptr->data << " " ; ptr = ptr->next; } } int main() { insert(3); insert(1); insert(7); insert(2); insert(9); cout << "The doubly linked list is: " ; display(); return 0; } |
Python3
# Represent a node of the doubly linked list class Node: def __init__( self , data): self .data = data self .previous = None self . next = None # Represent the head and tail of the doubly linked list def __init__( self ): self .head = None self .tail = None # addNode() will add a node to the list def addNode( self , data): # Create a new node newNode = self .Node(data) # If list is empty if self .head = = None : # Both head and tail will point to newNode self .head = self .tail = newNode # head's previous will point to None self .head.previous = None # tail's next will point to None, as it is the last node of the list self .tail. next = None else : # newNode will be added after tail such that tail's next will point to newNode self .tail. next = newNode # newNode's previous will point to tail newNode.previous = self .tail # newNode will become new tail self .tail = newNode # As it is last node, tail's next will point to None self .tail. next = None # display() will print out the nodes of the list def display( self ): # Node current will point to head current = self .head if self .head = = None : print ( "List is empty" ) return print ( "Nodes of doubly linked list: " ) while current ! = None : # Prints each node by incrementing the pointer. print (current.data, end = " " ) current = current. next |
Nodes of doubly linked list: 1 2 3 4 5
Output 1:
Nodes of doubly linked list: 1 2 3 4 5
Output 2:
The doubly linked list is: 9 2 7 1 3
Vector
- The Vector class implements a growable array of objects. Vectors basically fall in legacy classes but now it is fully compatible with collections. Vector implements a dynamic array that means it can grow or shrink as required. Like an array, it contains components that can be accessed using an integer index.
Java
import java.util.*; public class VectorExample { public static void main(String args[]) { //Create a vector Vector<String> vec = new Vector<String>(); //Adding elements using add() method of List vec.add( "Tiger" ); vec.add( "Lion" ); vec.add( "Dog" ); vec.add( "Elephant" ); //Adding elements using addElement() method of Vector vec.addElement( "Rat" ); vec.addElement( "Cat" ); vec.addElement( "Deer" ); System.out.println( "Elements are: " +vec); } } //By Jatin sharma |
C++
#include <iostream> #include <vector> using namespace std; int main() { vector<string> v; v.push_back( " Welcome " ); v.push_back( " to " ); v.push_back( " GFG! " ); for (vector<string>::iterator i = v.begin(); i != v.end(); ++i) cout << *i; return 0; } |
Python3
# create a list of strings strings = [ " Welcome " , " to " , " GFG! " ] # loop through the list and print each string for s in strings: print (s, end = "") |
Elements are: [Tiger, Lion, Dog, Elephant, Rat, Cat, Deer]
- Output:
Elements are: [Tiger, Lion, Dog, Elephant, Rat, Cat, Deer]
2. Output:
Welcome to GFG!
Stack
- Java Collection framework provides a Stack class which models and implements a Stack data structure. The class is based on the basic principle of last-in-first-out. In addition to the basic push and pop operations, the class provides three more functions of empty, search and peek. The class can also be said to extend Vector and treats the class as a stack with the five mentioned functions. The class can also be referred to as the subclass of Vector.
Java
// Java code for stack implementation import java.util.Stack; public class StackEmptyMethodExample { public static void main(String[] args) { //creating an instance of Stack class Stack<Integer> stk= new Stack<>(); // checking stack is empty or not boolean result = stk.empty(); System.out.println( "Is the stack empty? " + result); // pushing elements into stack stk.push( 78 ); stk.push( 113 ); stk.push( 90 ); stk.push( 120 ); //prints elements of the stack System.out.println( "Elements in Stack: " + stk); result = stk.empty(); System.out.println( "Is the stack empty? " + result); } } //By jatin sharma |
C++
#include <iostream> #include <cstdlib> using namespace std; // Define the default capacity of the stack #define SIZE 10 // A class to represent a stack class Stack { int *arr; int top; int capacity; public : Stack( int size = SIZE); // constructor ~Stack(); // destructor void push( int ); int pop(); int peek(); int size(); bool isEmpty(); bool isFull(); }; // Constructor to initialize the stack Stack::Stack( int size) { arr = new int [size]; capacity = size; top = -1; } // Destructor to free memory allocated to the stack Stack::~Stack() { delete [] arr; } // Utility function to add an element `x` to the stack void Stack::push( int x) { if (isFull()) { cout << "Overflow\nProgram Terminated\n" ; exit (EXIT_FAILURE); } cout << "Inserting " << x << endl; arr[++top] = x; } // Utility function to pop a top element from the stack int Stack::pop() { // check for stack underflow if (isEmpty()) { cout << "Underflow\nProgram Terminated\n" ; exit (EXIT_FAILURE); } cout << "Removing " << peek() << endl; // decrease stack size by 1 and (optionally) return the popped element return arr[top--]; } // Utility function to return the top element of the stack int Stack::peek() { if (!isEmpty()) { return arr[top]; } else { exit (EXIT_FAILURE); } } // Utility function to return the size of the stack int Stack::size() { return top + 1; } // Utility function to check if the stack is empty or not bool Stack::isEmpty() { return top == -1; // or return size() == 0; } // Utility function to check if the stack is full or not bool Stack::isFull() { return top == capacity - 1; // or return size() == capacity; } int main() { Stack pt(3); pt.push(1); pt.push(2); pt.pop(); pt.pop(); pt.push(3); cout << "The top element is " << pt.peek() << endl; cout << "The stack size is " << pt.size() << endl; pt.pop(); if (pt.isEmpty()) { cout << "The stack is empty\n" ; } else { cout << "The stack is not empty\n" ; } return 0; } |
Output 1:
Is the stack empty? true Elements in Stack: [78, 113, 90, 120] Is the stack empty? false
Output 2:
Inserting 1 Inserting 2 Removing 2 Removing 1 Inserting 3 The top element is 3 The stack size is 1 Removing 3 The stack is empty
- Related articles:
Queue
- The Queue interface is available in java.util package and extends the Collection interface. The queue collection is used to hold the elements about to be processed and provides various operations like the insertion, removal etc. It is an ordered list of objects with its use limited to insert elements at the end of the list and deleting elements from the start of list i.e. it follows the FIFO or the First-In-First-Out principle.
Java
// Java program to demonstrate working // of Queue interface in Java class Queue { private static int front, rear, capacity; private static int queue[]; Queue( int size) { front = rear = 0 ; capacity = size; queue = new int [capacity]; } // insert an element into the queue static void queueEnqueue( int item) { // check if the queue is full if (capacity == rear) { System.out.printf( "\nQueue is full\n" ); return ; } // insert element at the rear else { queue[rear] = item; rear++; } return ; } //remove an element from the queue static void queueDequeue() { // check if queue is empty if (front == rear) { System.out.printf( "\nQueue is empty\n" ); return ; } // shift elements to the right by one place uptil rear else { for ( int i = 0 ; i < rear - 1 ; i++) { queue[i] = queue[i + 1 ]; } // set queue[rear] to 0 if (rear < capacity) queue[rear] = 0 ; // decrement rear rear--; } return ; } // print queue elements static void queueDisplay() { int i; if (front == rear) { System.out.printf( "Queue is Empty\n" ); return ; } // traverse front to rear and print elements for (i = front; i < rear; i++) { System.out.printf( " %d , " , queue[i]); } return ; } // print front of queue static void queueFront() { if (front == rear) { System.out.printf( "Queue is Empty\n" ); return ; } System.out.printf( "\nFront Element of the queue: %d" , queue[front]); return ; } } public class QueueArrayImplementation { public static void main(String[] args) { // Create a queue of capacity 4 Queue q = new Queue( 4 ); System.out.println( "Initial Queue:" ); // print Queue elements q.queueDisplay(); // inserting elements in the queue q.queueEnqueue( 10 ); q.queueEnqueue( 30 ); q.queueEnqueue( 50 ); q.queueEnqueue( 70 ); // print Queue elements System.out.println( "Queue after Enqueue Operation:" ); q.queueDisplay(); // print front of the queue q.queueFront(); // insert element in the queue q.queueEnqueue( 90 ); // print Queue elements q.queueDisplay(); q.queueDequeue(); q.queueDequeue(); System.out.printf( "\nQueue after two dequeue operations:" ); // print Queue elements q.queueDisplay(); // print front of the queue q.queueFront(); } } //by Jatin sharma |
C++
#include <cstdlib> #include <iostream> using namespace std; // Define the default capacity of a queue #define SIZE 1000 // A class to store a queue class Queue { int * arr; // array to store queue elements int capacity; // maximum capacity of the queue int front; // front points to the front element in the // queue (if any) int rear; // rear points to the last element in the // queue int count; // current size of the queue public : Queue( int size = SIZE); // constructor ~Queue(); // destructor int dequeue(); void enqueue( int x); int peek(); int size(); bool isEmpty(); bool isFull(); }; // Constructor to initialize a queue Queue::Queue( int size) { arr = new int [size]; capacity = size; front = 0; rear = -1; count = 0; } // Destructor to free memory allocated to the queue Queue::~Queue() { delete [] arr; } // Utility function to dequeue the front element int Queue::dequeue() { // check for queue underflow if (isEmpty()) { cout << "Underflow\nProgram Terminated\n" ; exit (EXIT_FAILURE); } int x = arr[front]; cout << "Removing " << x << endl; front = (front + 1) % capacity; count--; return x; } // Utility function to add an item to the queue void Queue::enqueue( int item) { // check for queue overflow if (isFull()) { cout << "Overflow\nProgram Terminated\n" ; exit (EXIT_FAILURE); } cout << "Inserting " << item << endl; rear = (rear + 1) % capacity; arr[rear] = item; count++; } // Utility function to return the front element of the queue int Queue::peek() { if (isEmpty()) { cout << "Underflow\nProgram Terminated\n" ; exit (EXIT_FAILURE); } return arr[front]; } // Utility function to return the size of the queue int Queue::size() { return count; } // Utility function to check if the queue is empty or not bool Queue::isEmpty() { return (size() == 0); } // Utility function to check if the queue is full or not bool Queue::isFull() { return (size() == capacity); } int main() { // create a queue of capacity 5 Queue q(5); q.enqueue(1); q.enqueue(2); q.enqueue(3); cout << "The front element is " << q.peek() << endl; q.dequeue(); q.enqueue(4); cout << "The queue size is " << q.size() << endl; q.dequeue(); q.dequeue(); q.dequeue(); if (q.isEmpty()) { cout << "The queue is empty\n" ; } else { cout << "The queue is not empty\n" ; } return 0; } |
Output1:
Initial Queue: Queue is Empty Queue after Enqueue Operation: 10 , 30 , 50 , 70 , Front Element of the queue: 10 Queue is full 10 , 30 , 50 , 70 , Queue after two dequeue operations: 50 , 70 , Front Element of the queue: 50
Output2:
Inserting 1 Inserting 2 Inserting 3 The front element is 1 Removing 1 Inserting 4 The queue size is 3 Removing 2 Removing 3 Removing 4 The queue is empty
- Related articles:
Tree
- A Tree is a data structure that stores values inside entities called Nodes. Nodes are connected through lines referred to as edges. Each node stores a value inside it. Terminology:
- Root is the topmost node of the tree.
- Parent is a node that has one or more Nodes attached to it.
- Edge is the link joining the two nodes.
- Child is a node that has a parent node
- Leaf is a node that doesn’t have any child node attached to it, it is the bottommost node of a tree.
Java
public class Tree { // Represent the node of tree public static class Node { int data; Node left; Node right; public Node( int data) { // Assign data to the new node, set left and // right children to null this .data = data; this .left = null ; this .right = null ; } } // Represent the root of binary tree public Node root; public Tree() { root = null ; } // factorial() will calculate the factorial of given // number public int factorial( int num) { int fact = 1 ; if (num == 0 ) return 1 ; else { while (num > 1 ) { fact = fact * num; num--; } return fact; } } // numOfBST() will calculate the total number of // possible BST by calculating Catalan Number for given // key public int numOfBST( int key) { int catalanNumber = factorial( 2 * key) / (factorial(key + 1 ) * factorial(key)); return catalanNumber; } public static void main(String[] args) { Tree bt = new Tree(); // Display total number of possible // tree with key 5 System.out.println( "Total number of possible Trees with given key: " + bt.numOfBST( 5 )); } } // by jatin sharma |
Total number of possible Trees with given key: 42