Blog

  • Strongly Connected Components

    Strongly Connected Components (SCCs) are specific sub-graphs in a directed graph where every node can reach every other node within that sub-graph. In simple terms, SCCs are clusters of nodes that are tightly connected but are separate from other parts of the graph. Understanding SCCs is important, as they help in detecting cycles and studying network structures.

    A directed graph is said to be strongly connected if every node can reach every other node directly or indirectly. However, in larger graphs, we may have multiple strongly connected parts that are not connected to each other. These independent sections are called strongly connected components.

    For example, consider a directed graph with nodes A, B, C, D, and E. If A can reach B and B can reach A, but C, D, and E form a separate cluster where they can all reach each other but not A or B, then there are two SCCs in the graph: {A, B} and {C, D, E}.

    Strongly Connected Components Algorithm

    There are two popular algorithms to find strongly connected components in a graph:

    • Kosaraju’s Algorithm
    • Tarjan’s Algorithm

    Kosaraju’s Algorithm

    Kosaraju’s Algorithm is a two-pass algorithm that finds strongly connected components in a directed graph. Here’s how it works:

    • First Pass: Perform a Depth First Search (DFS) on the graph and store the order of nodes based on their finishing times.
    • Second Pass: Reverse the graph and perform another DFS on the nodes in the order of their finishing times from the first pass. This will give us the strongly connected components.

    Kosaraju’s Algorithm Example

    Let’s consider a directed graph with nodes A, B, C, D, and E, and the following edges:

       A -> B
       B -> C
       C -> A
       C -> D
       D -> E
       E -> D
    

    Using Kosaraju’s Algorithm, we can find the strongly connected components in the graph:

    • First Pass: The finishing times of the nodes are E, D, C, B, A.
    • Second Pass: The strongly connected components are {A, B, C} and {D, E}.

    Code for Kosaraju’s Algorithm

    Here’s an example code snippet for Kosaraju’s Algorithm in C, C++, Java, and Python:

    CC++JavaPython

    #include <stdio.h>#include <stdlib.h>#include <string.h>#define MAX_VERTICES 5// Graph adjacency matrixint adj[MAX_VERTICES][MAX_VERTICES]={{0,1,0,0,0},{0,0,1,0,0},{1,0,0,1,0},{0,0,0,0,1},{0,0,0,1,0}};int visited[MAX_VERTICES]={0};int finishing_time[MAX_VERTICES];int finish_index =0;// Mapping index to letters (A-E)char map[MAX_VERTICES]={'A','B','C','D','E'};voidDFS(int vertex,int print){
       visited[vertex]=1;if(print)printf("%c ", map[vertex]);// Print vertex if it's in SCC traversalfor(int v =0; v < MAX_VERTICES; v++){if(adj[vertex][v]&&!visited[v]){DFS(v, print);}}if(!print) finishing_time[finish_index++]= vertex;// Store finishing time if not printing SCC}voidreverse_graph(){int temp[MAX_VERTICES][MAX_VERTICES];for(int i =0; i < MAX_VERTICES; i++){for(int j =0; j < MAX_VERTICES; j++){
             temp[i][j]= adj[i][j];}}// Transpose the graphfor(int i =0; i < MAX_VERTICES; i++){for(int j =0; j < MAX_VERTICES; j++){
             adj[i][j]= temp[j][i];}}}voidfind_scc(){// Step 1: Compute finishing times in the original graphfor(int v =0; v < MAX_VERTICES; v++){if(!visited[v]){DFS(v,0);// First pass DFS (store finish times)}}// Step 2: Reverse the graphreverse_graph();// Step 3: Second DFS based on decreasing finishing timesmemset(visited,0,sizeof(visited));// Reset visited arrayprintf("Strongly Connected Components:\n");for(int i = MAX_VERTICES -1; i >=0; i--){int vertex = finishing_time[i];if(!visited[vertex]){printf("SCC: ");DFS(vertex,1);// Second pass DFS (print SCC)printf("\n");}}}intmain(){find_scc();return0;}

    Output

    Following is the output of the above code:

    Strongly Connected Components:
    SCC: A C B
    SCC: D E
    

    Tarjan’s Algorithm

    Tarjan’s Algorithm is another popular algorithm to find strongly connected components in a directed graph. It uses Depth First Search (DFS) to traverse the graph and identify SCCs. Here’s how it works:

    • Initialize a stack to keep track of visited nodes and their order of traversal.
    • Perform a DFS traversal of the graph, assigning a unique ID to each node and keeping track of the lowest ID reachable from that node.
    • Nodes with the same ID and low-link value form a strongly connected component.

    Tarjan’s Algorithm Example

    Consider the same directed graph with nodes A, B, C, D, and E, and the following edges:

       A -> B
       B -> C
       C -> A
       C -> D
       D -> E
       E -> D
    

    Using Tarjan’s Algorithm, we can find the strongly connected components in the graph:

    • The strongly connected components are {A, B, C} and {D, E}.

    Code for Tarjan’s Algorithm

    Here’s an example code snippet for Tarjan’s Algorithm in C, C++, Java, and Python:

    CC++JavaPython

    #include <stdio.h>#include <stdlib.h>#include <string.h>#define MAX_VERTICES 5// Graph adjacency matrixint adj[MAX_VERTICES][MAX_VERTICES]={{0,1,0,0,0},{0,0,1,0,0},{1,0,0,1,0},{0,0,0,0,1},{0,0,0,1,0}};int visited[MAX_VERTICES]={0};int stack[MAX_VERTICES];int stack_index =0;int ids[MAX_VERTICES];int low[MAX_VERTICES];int id =0;// Mapping index to letters (A-E)char map[MAX_VERTICES]={'A','B','C','D','E'};int map_index =0;voidDFS(int vertex){
       stack[stack_index++]= vertex;
       visited[vertex]=1;
       ids[vertex]= low[vertex]= id++;for(int v =0; v < MAX_VERTICES; v++){if(adj[vertex][v]){if(!visited[v]){DFS(v);}if(ids[v]!=-1){
                low[vertex]= low[vertex]0){int node = stack[--stack_index];
             low[node]= ids[vertex];printf("%c ", map[node]);if(node == vertex)break;}printf("\n");}}voidfind_scc(){memset(ids,-1,sizeof(ids));memset(low,-1,sizeof(low));for(int v =0; v < MAX_VERTICES; v++){if(!visited[v]){DFS(v);}}}intmain(){find_scc();return0;}

    Output

    Following is the output of the above code:

    SCC: E D
    SCC: C B A
    

    Applications of Strongly Connected Components

    Following are some common applications of Strongly Connected Components:

    • Network Analysis: SCCs help in understanding the structure and connectivity of networks, such as social networks, transportation networks, and communication networks.
    • Graph Algorithms: SCCs are used in various graph algorithms, such as cycle detection, pathfinding, and network flow optimization.
    • Software Engineering: SCCs are useful in software engineering for dependency analysis, module identification, and code refactoring.

    Conclusion

    Understanding Strongly Connected Components is essential for analyzing the connectivity and structure of directed graphs. Algorithms like Kosaraju’s Algorithm and Tarjan’s Algorithm provide efficient ways to identify SCCs in graphs, enabling various applications in network analysis, graph algorithms, and software engineering.

  • Topological Sorting in Graph Data Structure

    Topological sorting is a way of arranging the nodes of a Directed Acyclic Graph (DAG) in a line, making sure that for every directed edge from u to v, node u comes before v. If the graph has cycles, topological sorting isn’t possible.

    In topological sorting, if theres an edge from u to vu should come before v in the order. Its different from DFS, where we visit a node and then explore its neighbors. In topological sorting, a node should be printed before any of its connected nodes.

    Now, lets understand Directed Acyclic Graphs (DAGs). A directed graph has edges that go from one node to another in a specific direction. It is called acyclic if there are no cyclesmeaning theres no way to start from a node and return to it by following edges.

    Topological sorting only works for DAGs. If theres a cycle in the graph, we cant arrange the nodes in a proper order because some nodes will keep pointing back, making a valid linear order impossible.

    Topological Sort

    Topological Sort Algorithm

    Topological sorting can be done using Depth First Search (DFS) algorithm. The algorithm follows the following steps:

    Algorithm

    Following are the steps to perform topological sorting using DFS:

    • Call the DFS function for a vertex u.
    • In the DFS function, mark the vertex u as visited.
    • For every adjacent vertex v of u, if v is not visited, then call the DFS function for vertex v.
    • After visiting all the adjacent vertices of vertex u, add the vertex u to the topological order list.

    After performing the above steps for all the vertices, the topological order list will have the vertices in topological order.

    Code for Topological Sort

    Let’s see the code for topological sorting using Depth First Search (DFS) algorithm:

    CC++JavaPython

    #include <stdio.h>#define MAX_VERTICES 6int adj[MAX_VERTICES][MAX_VERTICES]={{0,1,1,0,0,0},{0,0,0,1,1,0},{0,0,0,0,1,0},{0,0,0,0,0,1},{0,0,0,0,0,1},{0,0,0,0,0,0}};int visited[MAX_VERTICES]={0};int topological_order[MAX_VERTICES];int order_index = MAX_VERTICES -1;voidDFS(int vertex){
       visited[vertex]=1;for(int v =0; v < MAX_VERTICES; v++){if(adj[vertex][v]&&!visited[v]){DFS(v);}}
       topological_order[order_index--]= vertex;}voidtopological_sort(){for(int v =0; v < MAX_VERTICES; v++){if(!visited[v]){DFS(v);}}}voidprint_topological_order(){printf("Topological Order: ");for(int i =0; i < MAX_VERTICES; i++){printf("%d ", topological_order[i]);}printf("\n");}intmain(){topological_sort();print_topological_order();return0;}

    Output

    Following is the output of the above code:

    Topological Order: 0 2 1 3 4 5
    

    Time Complexity of Topological Sort

    When using Depth First Search (DFS) for topological sorting, the time complexity is O(V + E), where V is the number of vertices and E is the number of edges in the graph. This is because we visit each node once and explore all its edges.

    Applications of Topological Sort

    Topological sorting has many applications in various fields. Some of the applications of topological sort are:

    • Task Scheduling: Used to schedule tasks based on dependencies. Each task is a node, and dependencies are edges. This ensures tasks are executed in the correct order.
    • Course Prerequisites: Helps in deciding the order of taking courses. Courses are nodes, and prerequisites are edges, ensuring prerequisites are completed first.
    • Build Systems: Used in software build processes to determine the correct sequence for compiling files based on dependencies.
    • Network Routing: Helps in routing packets through a network by determining the correct order of processing based on connections between routers.
  • Spanning Tree

    What is Spanning Tree?

    A spanning tree is a subset of Graph G, which has all the vertices covered with minimum possible number of edges. Hence, a spanning tree does not have cycles and it cannot be disconnected..

    By this definition, we can draw a conclusion that every connected and undirected Graph G has at least one spanning tree. A disconnected graph does not have any spanning tree, as it cannot be spanned to all its vertices.

    Spanning Trees

    We found three spanning trees off one complete graph. A complete undirected graph can have maximum nn-2 number of spanning trees, where n is the number of nodes. In the above addressed example, n is 3, hence 33−2 = 3 spanning trees are possible.

    General Properties of Spanning Tree

    We now understand that one graph can have more than one spanning tree. Following are a few properties of the spanning tree connected to graph G −

    • A connected graph G can have more than one spanning tree.
    • All possible spanning trees of graph G, have the same number of edges and vertices.
    • The spanning tree does not have any cycle (loops).
    • Removing one edge from the spanning tree will make the graph disconnected, i.e. the spanning tree is minimally connected.
    • Adding one edge to the spanning tree will create a circuit or loop, i.e. the spanning tree is maximally acyclic.

    Mathematical Properties of Spanning Tree

    • Spanning tree has n-1 edges, where n is the number of nodes (vertices).
    • From a complete graph, by removing maximum e – n &plus; 1 edges, we can construct a spanning tree.
    • A complete graph can have maximum nn-2 number of spanning trees.

    Thus, we can conclude that spanning trees are a subset of connected Graph G and disconnected graphs do not have spanning tree.

    Application of Spanning Tree

    Spanning tree is basically used to find a minimum path to connect all nodes in a graph. Common application of spanning trees are −

    • Civil Network Planning
    • Computer Network Routing Protocol
    • Cluster Analysis

    Let us understand this through a small example. Consider, city network as a huge graph and now plans to deploy telephone lines in such a way that in minimum lines we can connect to all city nodes. This is where the spanning tree comes into picture.

    Minimum Spanning Tree (MST)

    In a weighted graph, a minimum spanning tree is a spanning tree that has minimum weight than all other spanning trees of the same graph. In real-world situations, this weight can be measured as distance, congestion, traffic load or any arbitrary value denoted to the edges.

    Minimum Spanning-Tree Algorithm

    We shall learn about two most important spanning tree algorithms here −

    • Kruskal’s Algorithm
    • Prim’s Algorithm

    These two algorithms are Greedy algorithms.

  • Breadth First Search (BFS) Algorithm

    Breadth First Search (BFS) Algorithm

    Breadth First Search (BFS) algorithm traverses a graph in a breadthward motion to search a graph data structure for a node that meets a set of criteria. It uses a queue to remember the next vertex to start a search, when a dead end occurs in any iteration.

    Breadth First Search (BFS) algorithm starts at the tree root and explores all nodes at the present depth prior to moving on to the nodes at the next depth level.

    Breadth First Traversal

    As in the example given above, BFS algorithm traverses from A to B to E to F first then to C and G lastly to D. It employs the following rules.

    • Rule 1 − Visit the adjacent unvisited vertex. Mark it as visited. Display it. Insert it in a queue.
    • Rule 2 − If no adjacent vertex is found, remove the first vertex from the queue.
    • Rule 3 − Repeat Rule 1 and Rule 2 until the queue is empty.
    StepTraversalDescription
    1Breadth First Search Step OneInitialize the queue.
    2Breadth First Search Step TwoWe start from visiting S (starting node), and mark it as visited.
    3Breadth First Search Step ThreeWe then see an unvisited adjacent node from S. In this example, we have three nodes but alphabetically we choose A, mark it as visited and enqueue it.
    4Breadth First Search Step FourNext, the unvisited adjacent node from S is B. We mark it as visited and enqueue it.
    5Breadth First Search Step FiveNext, the unvisited adjacent node from S is C. We mark it as visited and enqueue it.
    6Breadth First Search Step SixNow, S is left with no unvisited adjacent nodes. So, we dequeue and find A.
    7Breadth First Search Step SevenFrom A we have D as unvisited adjacent node. We mark it as visited and enqueue it.

    At this stage, we are left with no unmarked (unvisited) nodes. But as per the algorithm we keep on dequeuing in order to get all unvisited nodes. When the queue gets emptied, the program is over.

    Example

    Following are the implementations of Breadth First Search (BFS) Algorithm in various programming languages −

    CC++JavaPython

    #include <stdio.h>#include <stdlib.h>#include <stdbool.h>#define MAX 5structVertex{char label;
       bool visited;};//queue variablesint queue[MAX];int rear =-1;int front =0;int queueItemCount =0;//graph variables//array of verticesstructVertex* lstVertices[MAX];//adjacency matrixint adjMatrix[MAX][MAX];//vertex countint vertexCount =0;//queue functionsvoidinsert(int data){
       queue[++rear]= data;
       queueItemCount++;}intremoveData(){
       queueItemCount--;return queue[front++];}
    bool isQueueEmpty(){return queueItemCount ==0;}//graph functions//add vertex to the vertex listvoidaddVertex(char label){structVertex* vertex =(structVertex*)malloc(sizeof(structVertex));
       vertex->label = label;  
       vertex->visited = false;     
       lstVertices[vertexCount++]= vertex;}//add edge to edge arrayvoidaddEdge(int start,int end){
       adjMatrix[start][end]=1;
       adjMatrix[end][start]=1;}//display the vertexvoiddisplayVertex(int vertexIndex){printf("%c ",lstVertices[vertexIndex]->label);}//get the adjacent unvisited vertexintgetAdjUnvisitedVertex(int vertexIndex){int i;for(i =0; i<vertexCount; i++){if(adjMatrix[vertexIndex][i]==1&& lstVertices[i]->visited == false)return i;}return-1;}voidbreadthFirstSearch(){int i;//mark first node as visited
       lstVertices[0]->visited = true;//display the vertexdisplayVertex(0);//insert vertex index in queueinsert(0);int unvisitedVertex;while(!isQueueEmpty()){//get the unvisited vertex of vertex which is at front of the queueint tempVertex =removeData();//no adjacent vertex foundwhile((unvisitedVertex =getAdjUnvisitedVertex(tempVertex))!=-1){    
             lstVertices[unvisitedVertex]->visited = true;displayVertex(unvisitedVertex);insert(unvisitedVertex);}}//queue is empty, search is complete, reset the visited flag        for(i =0;i<vertexCount;i++){
          lstVertices[i]->visited = false;}}intmain(){int i, j;for(i =0; i<MAX; i++){// set adjacency for(j =0; j<MAX; j++)// matrix to 0
             adjMatrix[i][j]=0;}addVertex('S');// 0addVertex('A');// 1addVertex('B');// 2addVertex('C');// 3addVertex('D');// 4addEdge(0,1);// S - AaddEdge(0,2);// S - BaddEdge(0,3);// S - CaddEdge(1,4);// A - DaddEdge(2,4);// B - DaddEdge(3,4);// C - Dprintf("\nBreadth First Search: ");breadthFirstSearch();return0;}

    Output

    Breadth First Search: S A B C D
    

    Click to check C implementation of Breadth First Search (BFS) Algorithm

    Complexity of BFS Algorithm

    Time Complexity

    The time complexity of the BFS algorithm is represented in the form of O(V + E), where V is the number of nodes and E is the number of edges.

    Space Complexity

    The space complexity of the BFS algorithm is O(V).

  • Depth First Search (DFS) Algorithm

    Depth First Search (DFS) Algorithm

    Depth First Search (DFS) algorithm is a recursive algorithm for searching all the vertices of a graph or tree data structure. This algorithm traverses a graph in a depthward motion and uses a stack to remember to get the next vertex to start a search, when a dead end occurs in any iteration.

    Depth First Travesal

    As in the example given above, DFS algorithm traverses from S to A to D to G to E to B first, then to F and lastly to C. It employs the following rules.

    • Rule 1 − Visit the adjacent unvisited vertex. Mark it as visited. Display it. Push it in a stack.
    • Rule 2 − If no adjacent vertex is found, pop up a vertex from the stack. (It will pop up all the vertices from the stack, which do not have adjacent vertices.)
    • Rule 3 − Repeat Rule 1 and Rule 2 until the stack is empty.
    StepTraversalDescription
    1Depth First Search Step OneInitialize the stack.
    2Depth First Search Step TwoMark S as visited and put it onto the stack. Explore any unvisited adjacent node from S. We have three nodes and we can pick any of them. For this example, we shall take the node in an alphabetical order.
    3Depth First Search Step ThreeMark A as visited and put it onto the stack. Explore any unvisited adjacent node from A. Both S and D are adjacent to A but we are concerned for unvisited nodes only.
    4Depth First Search Step FourVisit D and mark it as visited and put onto the stack. Here, we have B and C nodes, which are adjacent to D and both are unvisited. However, we shall again choose in an alphabetical order.
    5Depth First Search Step FiveWe choose B, mark it as visited and put onto the stack. Here B does not have any unvisited adjacent node. So, we pop B from the stack.
    6Depth First Search Step SixWe check the stack top for return to the previous node and check if it has any unvisited nodes. Here, we find D to be on the top of the stack.
    7Depth First Search Step SevenOnly unvisited adjacent node is from D is C now. So we visit C, mark it as visited and put it onto the stack.

    As C does not have any unvisited adjacent node so we keep popping the stack until we find a node that has an unvisited adjacent node. In this case, there’s none and we keep popping until the stack is empty.

    Example

    Following are the implementations of Depth First Search (DFS) Algorithm in various programming languages −

    CC++JavaPython

    #include <stdio.h>#include <stdlib.h>#include <stdbool.h>#define MAX 5structVertex{char label;
       bool visited;};//stack variablesint stack[MAX];int top =-1;//graph variables//array of verticesstructVertex* lstVertices[MAX];//adjacency matrixint adjMatrix[MAX][MAX];//vertex countint vertexCount =0;//stack functionsvoidpush(int item){ 
       stack[++top]= item;}intpop(){return stack[top--];}intpeek(){return stack[top];}
    bool isStackEmpty(){return top ==-1;}//graph functions//add vertex to the vertex listvoidaddVertex(char label){structVertex* vertex =(structVertex*)malloc(sizeof(structVertex));
       vertex->label = label;  
       vertex->visited = false;     
       lstVertices[vertexCount++]= vertex;}//add edge to edge arrayvoidaddEdge(int start,int end){
       adjMatrix[start][end]=1;
       adjMatrix[end][start]=1;}//display the vertexvoiddisplayVertex(int vertexIndex){printf("%c ",lstVertices[vertexIndex]->label);}//get the adjacent unvisited vertexintgetAdjUnvisitedVertex(int vertexIndex){int i;for(i =0; i < vertexCount; i++){if(adjMatrix[vertexIndex][i]==1&& lstVertices[i]->visited == false){return i;}}return-1;}voiddepthFirstSearch(){int i;//mark first node as visited
       lstVertices[0]->visited = true;//display the vertexdisplayVertex(0);//push vertex index in stackpush(0);while(!isStackEmpty()){//get the unvisited vertex of vertex which is at top of the stackint unvisitedVertex =getAdjUnvisitedVertex(peek());//no adjacent vertex foundif(unvisitedVertex ==-1){pop();}else{
             lstVertices[unvisitedVertex]->visited = true;displayVertex(unvisitedVertex);push(unvisitedVertex);}}//stack is empty, search is complete, reset the visited flag        for(i =0;i < vertexCount;i++){
          lstVertices[i]->visited = false;}}intmain(){int i, j;for(i =0; i < MAX; i++){// set adjacencyfor(j =0; j < MAX; j++)// matrix to 0
             adjMatrix[i][j]=0;}addVertex('S');// 0addVertex('A');// 1addVertex('B');// 2addVertex('C');// 3addVertex('D');// 4addEdge(0,1);// S - AaddEdge(0,2);// S - BaddEdge(0,3);// S - CaddEdge(1,4);// A - DaddEdge(2,4);// B - DaddEdge(3,4);// C - Dprintf("Depth First Search: ");depthFirstSearch();return0;}

    Output

    Depth First Search: S A D B C
    

    Click to check C implementation of Depth First Search (BFS) Algorithm

    Complexity of DFS Algorithm

    Time Complexity

    The time complexity of the DFS algorithm is represented in the form of O(V + E), where V is the number of nodes and E is the number of edges.

    Space Complexity

    The space complexity of the DFS algorithm is O(V).

  • Graph Data Structure

    What is a Graph?

    A graph is an abstract data type (ADT) which consists of a set of objects that are connected to each other via links. The interconnected objects are represented by points termed as vertices, and the links that connect the vertices are called edges.

    Formally, a graph is a pair of sets (V, E), where V is the set of vertices and E is the set of edges, connecting the pairs of vertices. Take a look at the following graph −

    Graph Basics

    In the above graph,

    V = {a, b, c, d, e}

    E = {ab, ac, bd, cd, de}

    Graph Data Structure

    Mathematical graphs can be represented in data structure. We can represent a graph using an array of vertices and a two-dimensional array of edges. Before we proceed further, let’s familiarize ourselves with some important terms −

    • Vertex − Each node of the graph is represented as a vertex. In the following example, the labeled circle represents vertices. Thus, A to G are vertices. We can represent them using an array as shown in the following image. Here A can be identified by index 0. B can be identified using index 1 and so on.
    • Edge − Edge represents a path between two vertices or a line between two vertices. In the following example, the lines from A to B, B to C, and so on represents edges. We can use a two-dimensional array to represent an array as shown in the following image. Here AB can be represented as 1 at row 0, column 1, BC as 1 at row 1, column 2 and so on, keeping other combinations as 0.
    • Adjacency − Two node or vertices are adjacent if they are connected to each other through an edge. In the following example, B is adjacent to A, C is adjacent to B, and so on.
    • Path − Path represents a sequence of edges between the two vertices. In the following example, ABCD represents a path from A to D.
    graph
    graph

    Operations of Graphs

    The primary operations of a graph include creating a graph with vertices and edges, and displaying the said graph. However, one of the most common and popular operation performed using graphs are Traversal, i.e. visiting every vertex of the graph in a specific order.

    There are two types of traversals in Graphs −

    Depth First Search Traversal

    Depth First Search is a traversal algorithm that visits all the vertices of a graph in the decreasing order of its depth. In this algorithm, an arbitrary node is chosen as the starting point and the graph is traversed back and forth by marking unvisited adjacent nodes until all the vertices are marked.

    The DFS traversal uses the stack data structure to keep track of the unvisited nodes.

    Click and check Depth First Search Traversal

    Breadth First Search Traversal

    Breadth First Search is a traversal algorithm that visits all the vertices of a graph present at one level of the depth before moving to the next level of depth. In this algorithm, an arbitrary node is chosen as the starting point and the graph is traversed by visiting the adjacent vertices on the same depth level and marking them until there is no vertex left.

    The DFS traversal uses the queue data structure to keep track of the unvisited nodes.

    Click and check Breadth First Search Traversal

    Representation of Graphs

    While representing graphs, we must carefully depict the elements (vertices and edges) present in the graph and the relationship between them. Pictorially, a graph is represented with a finite set of nodes and connecting links between them. However, we can also represent the graph in other most commonly used ways, like −

    • Adjacency Matrix
    • Adjacency List

    Adjacency Matrix

    The Adjacency Matrix is a V x V matrix where the values are filled with either 0 or 1. If the link exists between Vi and Vj, it is recorded 1; otherwise, 0.

    For the given graph below, let us construct an adjacency matrix −

    Adjacency_Matrix

    The adjacency matrix is −

    adjacency_matrix

    Adjacency List

    The adjacency list is a list of the vertices directly connected to the other vertices in the graph.

    Adjacency_Matrix

    The adjacency list is −

    adjacency list

    Types of graph

    There are two basic types of graph −

    • Directed Graph
    • Undirected Graph

    Directed graph, as the name suggests, consists of edges that possess a direction that goes either away from a vertex or towards the vertex. Undirected graphs have edges that are not directed at all.

    Directed Graph

    Directed Graph

    Undirected_Grap

    Undirected Graph

    Spanning Tree

    spanning tree is a subset of an undirected graph that contains all the vertices of the graph connected with the minimum number of edges in the graph. Precisely, the edges of the spanning tree is a subset of the edges in the original graph.

    If all the vertices are connected in a graph, then there exists at least one spanning tree. In a graph, there may exist more than one spanning tree.

    Properties

    • A spanning tree does not have any cycle.
    • Any vertex can be reached from any other vertex.

    Example

    In the following graph, the highlighted edges form a spanning tree.

    Spanning Tree

    Minimum Spanning Tree

    Minimum Spanning Tree (MST) is a subset of edges of a connected weighted undirected graph that connects all the vertices together with the minimum possible total edge weight. To derive an MST, Prim’s algorithm or Kruskal’s algorithm can be used. Hence, we will discuss Prim’s algorithm in this chapter.

    As we have discussed, one graph may have more than one spanning tree. If there are n number of vertices, the spanning tree should have n − l1 number of edges. In this context, if each edge of the graph is associated with a weight and there exists more than one spanning tree, we need to find the minimum spanning tree of the graph.

    Moreover, if there exist any duplicate weighted edges, the graph may have multiple minimum spanning tree.

    Minimum Spanning Tree

    In the above graph, we have shown a spanning tree though it’s not the minimum spanning tree. The cost of this spanning tree is (5+7+3+3+5+8+3+4)=38.

    Shortest Path

    The shortest path in a graph is defined as the minimum cost route from one vertex to another. This is most commonly seen in weighted directed graphs but are also applicable to undirected graphs.

    A popular real−world application of finding the shortest path in a graph is a map. Navigation is made easier and simpler with the various shortest path algorithms where destinations are considered vertices of the graph and routes are the edges. The two common shortest path algorithms are −

    • Dijkstra’s Shortest Path Algorithm
    • Bellman Ford’s Shortest Path Algorithm

    Example

    Following are the implementations of this operation in various programming languages −

    CC++JavaPython

    #include <stdio.h>#include <stdlib.h>#include <stdlib.h>#define V 5 // Maximum number of vertices in the graphstructgraph{// declaring graph data structurestructvertex*point[V];};structvertex{// declaring verticesint end;structvertex*next;};structEdge{// declaring edgesint end, start;};structgraph*create_graph(structEdge edges[],int x){int i;structgraph*graph =(structgraph*)malloc(sizeof(structgraph));for(i =0; i < V; i++){
          graph->point[i]=NULL;}for(i =0; i < x; i++){int start = edges[i].start;int end = edges[i].end;structvertex*v =(structvertex*)malloc(sizeof(structvertex));
          v->end = end;
          v->next = graph->point[start];
          graph->point[start]= v;}return graph;}intmain(){structEdge edges[]={{0,1},{0,2},{0,3},{1,2},{1,4},{2,4},{2,3},{3,1}};int n =sizeof(edges)/sizeof(edges[0]);structgraph*graph =create_graph(edges, n);printf("The graph created is: ");for(int i =0; i < V; i++){structvertex*ptr = graph->point[i];while(ptr !=NULL){printf("(%d -> %d)\t", i, ptr->end);
             ptr = ptr->next;}printf("\n");}return0;}

    Output

    The graph created is:
    (1 -> 3)	(1 -> 0)	
    (2 -> 1)	(2 -> 0)	
    (3 -> 2)	(3 -> 0)	
    (4 -> 2)	(4 -> 1)	
  • LU Decomposition in Matrices

    LU Decomposition in Matrices is a method of decomposing a square matrix into two matrices, one of which is a lower triangular matrix and the other is an upper triangular matrix.

    The LU decomposition is used in numerical analysis to solve systems of linear equations.

    The LU decomposition is also used in the solution of linear systems of equations, the calculation of the determinant of a matrix, and the calculation of the inverse of a matrix.

    What is LU Decomposition in Data Structures?

    In data structures, LU decomposition means splitting a square matrix A into two smaller matrices:

    • L – Lower triangular matrix
    • U – Upper triangular matrix

    This decomposition helps in efficient computation of the determinant and inverse of a matrix.

    Why LU Decomposition is Important?

    It simplifies the process of solving linear equations and calculating the determinant and inverse of a matrix by breaking down the original matrix into two simpler matrices.

    Imagine you have a project where you have to build a feature that require solving linear equations and you don’t want it to be complex. In this case, you can use LU decomposition to simplify the process. It means you can solve the same equations with less effort and complexity by breaking down the matrix into two simpler matrices.

    LU Decomposition Algorithm

    The LU decomposition algorithm is as follows:

    1. Read the matrix A
    2. Set the size of the matrix A as n x n
    3. Initialize the matrices L and U as n x n matrices
    4. Set the diagonal elements of L as 1 and the other elements as 0
    5. Set the elements of U as the elements of A
    6. For k = 1 to n-1
    7. For i = k+1 to n
    8. Set L[i][k] = U[i][k]/U[k][k]
    9. For j = k to n
    10. Set U[i][j] = U[i][j] - L[i][k]*U[k][j]
    11. Display the matrices L and U
    

    LU Decomposition Example

    Let’s consider a 3×3 matrix A. We will perform LU decomposition on this matrix. Following is the example, using Java, CPP, C and Python programming languages.

    CC++JavaPython

    //C Program to perform LU Decomposition#include <stdio.h>intmain(){int n =3;float A[3][3]={{2,-1,-2},{-4,6,3},{-4,-2,8}};float L[3][3], U[3][3];int i, j, k;for(i =0; i < n; i++){for(j =0; j < n; j++){if(i > j){
                U[i][j]=0;
                L[i][j]= A[i][j];}elseif(i == j){
                L[i][j]=1;
                U[i][j]= A[i][j];}else{
                L[i][j]=0;
                U[i][j]= A[i][j];}}}for(k =0; k < n; k++){for(i = k +1; i < n; i++){
             L[i][k]= U[i][k]/ U[k][k];for(j = k; j < n; j++){
                U[i][j]= U[i][j]- L[i][k]* U[k][j];}}}printf("L Matrix\n");for(i =0; i < n; i++){for(j =0; j < n; j++){printf("%f ", L[i][j]);}printf("\n");}printf("U Matrix\n");for(i =0; i < n; i++){for(j =0; j < n; j++){printf("%f ", U[i][j]);}printf("\n");}return0;}

    Output

    The output obtained is as follows −

    L Matrix
    1.000000 0.000000 0.000000
    -2.000000 1.000000 0.000000
    -2.000000 1.000000 1.000000
    U Matrix
    2.000000 -1.000000 -2.000000
    0.000000 4.000000 7.000000
    0.000000 0.000000 1.000000
    
    

    Applications of LU Decomposition

    LU decomposition is used in various applications, such as:

    • Solving systems of linear equations
    • Calculating the determinant of a matrix
    • Calculating the inverse of a matrix

    LU decomposition is also used in numerical analysis, scientific computing, and engineering to solve complex problems.

    Conclusion

    In this chapter, we learned about LU decomposition in matrices. We discussed the importance of LU decomposition in data structures and its applications in solving linear equations, calculating the determinant and inverse of a matrix. We also saw the LU decomposition algorithm and an example of LU decomposition in a 3×3 matrix using different programming languages.

  • LUP Decomposition in Matrices

    LUP Decomposition in Matrices is a similar method as LU Decomposition, but the difference is that LUP decomposition includes a permutation matrix.

    The LUP decomposition is used in numerical analysis to solve systems of linear equations, and also in the solution of linear systems of equations, the calculation of the determinant of a matrix, and the calculation of the inverse of a matrix.

    What is LUP Decomposition in Data Structures?

    In data structures, LUP decomposition means splitting a square matrix A into three smaller matrices:

    • L – Lower triangular matrix: A square matrix in which all the elements above the main diagonal are zero.
    • U – Upper triangular matrix: A square matrix in which all the elements below the main diagonal are zero.
    • P – Permutation matrix: A square matrix that represents the permutation of the rows of the identity matrix.

    Why LUP Decomposition?

    LUP decomposition is preferred over LU decomposition because it includes a permutation matrix P. The permutation matrix helps in reducing the error in the calculation of the determinant and inverse of a matrix.

    LUP Decomposition Algorithm

    The LUP decomposition algorithm is as follows:

    1. Read the matrix A
    2. Set the size of the matrix A as n x n
    3. Initialize the matrices L, U, and P as n x n matrices
    4. Set the diagonal elements of L as 1 and the other elements as 0
    5. Set the elements of U as the elements of A
    6. Set the elements of P as the elements of the identity matrix
    7. For k = 1 to n-1
    8. Find the pivot element in the k-th column
    9. Swap the rows of U, L, and P according to the pivot element
    10. For i = k+1 to n
    11. Set L[i][k] = U[i][k]/U[k][k]
    12. For j = k to n
    13. Set U[i][j] = U[i][j] - L[i][k]*U[k][j]
    14. Display the matrices L, U, and P
    

    LUP Decomposition Code Example

    Let’s consider a 3×3 matrix A. We will perform LUP decomposition on this matrix. Following is the example, using Java, CPP, C and Python programming languages.

    CC++Java“”Python

    #include <stdio.h>#include <stdlib.h>#include <math.h>voidLUPDecomposition(int n,float A[n][n],float L[n][n],float U[n][n],float P[n][n]){int i, j, k;for(i =0; i < n; i++){for(j =0; j < n; j++){
             L[i][j]=(i == j)?1:0;
             U[i][j]= A[i][j];
             P[i][j]=(i == j)?1:0;}}for(k =0; k < n -1; k++){float max =0;int pivot = k;for(i = k; i < n; i++){if(fabs(U[i][k])> max){
                max =fabs(U[i][k]);
                pivot = i;}}if(pivot != k){for(j =0; j < n; j++){float temp = U[k][j];
                U[k][j]= U[pivot][j];
                U[pivot][j]= temp;
    
                temp = P[k][j];
                P[k][j]= P[pivot][j];
                P[pivot][j]= temp;if(j < k){
                   temp = L[k][j];
                   L[k][j]= L[pivot][j];
                   L[pivot][j]= temp;}}}if(U[k][k]==0){printf("Error: Singular matrix detected.\n");exit(1);}for(i = k +1; i < n; i++){
             L[i][k]= U[i][k]/ U[k][k];for(j = k; j < n; j++){
                U[i][j]-= L[i][k]* U[k][j];}}}}voidprintMatrix(int n,float M[n][n],constchar*name){printf("\n%s Matrix:\n", name);for(int i =0; i < n; i++){for(int j =0; j < n; j++){printf("%8.3f ", M[i][j]);}printf("\n");}}intmain(){int n =3;float A[3][3]={{2,-1,-2},{-4,6,3},{-4,-2,8}};float L[3][3], U[3][3], P[3][3];LUPDecomposition(n, A, L, U, P);printMatrix(n, L,"L");printMatrix(n, U,"U");printMatrix(n, P,"P");return0;}

    Output

    The output produced is as follows −

    L Matrix:
       1.000    0.000    0.000 
       1.000    1.000    0.000 
      -0.500   -0.250    1.000 
    
    U Matrix:
      -4.000    6.000    3.000 
       0.000   -8.000    5.000 
       0.000    0.000    0.750 
    
    P Matrix:
       0.000    1.000    0.000 
       0.000    0.000    1.000 
       1.000    0.000    0.000  
    

    Applications of LUP Decomposition

    LUP decomposition is used in various applications in computer science, such as:

    • Calculating the determinant of a matrix
    • Calculating the inverse of a matrix
    • Solving systems of linear equations
    • Implementing numerical algorithms
    • Performing matrix operations

    Conclusion

    In this chapter, we learned about LUP decomposition in matrices. LUP decomposition is a method used to solve systems of linear equations, calculate the determinant of a matrix, and calculate the inverse of a matrix.

    LUP decomposition includes three matrices: L (lower triangular matrix), U (upper triangular matrix), and P (permutation matrix). LUP decomposition is preferred over LU decomposition because it includes a permutation matrix that helps in reducing errors in the calculation of the determinant and inverse of a matrix.

  • Matrices in Data Structures

    matrix is a two-dimensional data structure, where we can store data in rows and columns format. In data structures, a matrix is a two-dimensional array of elements, with the same data type. All values in a matrix must have the same data type. The matrix can have a fixed number of rows and columns, or it can be dynamically allocated based on the requirement.

    Matrices can be used in various applications, such as image processing, data analysis, and machine learning. In this chapter, we will learn about matrices in data structures, how to create and access elements in a matrix, and various operations that can be performed on matrices.

    If the matrix has m rows and n columns, there are m n elements. The matrix is represented by uppercase letters (in this case, “A“), and the elements in the matrix are represented by lowercase letters and two subscripts that represent the positions of the elements in the same order. In the case of, ‘‘, where i is the number of rows and j is the number of columns.

    Types of Matrices in Data Structure

    There are many types of matrices, which are basically categorized based on element values, order, number of rows and columns, and so on. There are different types of matrices in linear algebra. All types of matrices are distinguished based on their elements, order, and specific conditions.

    Special types of matrices are square, diagonal, identity, translocations, and symmetric matrices. This is a square matrix with the same number of rows and columns. Currently, using different terms, different matrix types are categorized below, along with their definitions and examples.

    • Null Matrix : If all specified elements in a matrix are 0, then the matrix is called a null matrix and is usually represented by zero.
     A = [ [0, 0], [0, 0] ]

    Row Matrix: If a matrix has only one row, it is called a row matrix.

     A = [ [1, 2, 3] ] 

    Column Matrix: If a matrix has only one column, it is called a column matrix.

     A = [ [1], [2], [3] ] 

    Square Matrix: If the number of rows and columns in a matrix is the same, it is called a square matrix.

     A = [ [1, 2], [3, 4] ] 

    Triangular Matrix : It is a rectangular matrix with all the 0 factors below and/or above the diagonal. There are two principal types of triangular matrices – lower triangular matrix and upper triangular matrix.

     A = [ [1, 0, 0], [2, 3, 0], [4, 5, 6] ] 

    Identity Matrix : If the diagonal elements of a square matrix are 1 and all other elements are 0, it is called an identity matrix.

     A = [ [1, 0, 0], [0, 1, 0], [0, 0, 1] ] 

    Diagonal Matrix : If all elements of a square matrix are 0, except the diagonal elements, it is called a diagonal matrix.

     A = [ [1, 0, 0], [0, 2, 0], [0, 0, 3] ] 

    Scalar Matrix : If all diagonal elements of a square matrix are the same, it is called a scalar matrix.

     A = [ [2, 0, 0], [0, 2, 0], [0, 0, 2] ] 

    Symmetric Matrix : If a matrix is equal to its transpose, it is called a symmetric matrix.

     A = [ [1, 2, 3], [2, 4, 5], [3, 5, 6] ] 

    Transpose of a Matrix : The transpose of a matrix is obtained by interchanging rows and columns. If A = [aij] m n, then the transpose of A is represented by AT = [bij] n m, where bij = aji.

     A = [ [1, 2], [3, 4] ] 
     AT = [ [1, 3], [2, 4] ] 

    Components of a Matrix

    • Size – The size of a matrix is the number of rows and columns in the matrix. If a matrix has m rows and n columns, the size of the matrix is m n.
    • Element – An element in a matrix is a value stored at a specific position in the matrix. The element is represented by aij, where i is the row number and j is the column number.
    • Row – A row in a matrix is a horizontal sequence of elements. A matrix has m rows, numbered from 1 to m.
    • Column – A column in a matrix is a vertical sequence of elements. A matrix has n columns, numbered from 1 to n.
    • Transpose – We can get transpose of a matrix by interchanging it’s row and column. If A = [aij] m n, then the transpose of A is represented by AT = [bij] n m, where bij = aji.
    • Rank – The rank of a matrix is the maximum number of linearly independent rows or columns in the matrix. The rank of a matrix is denoted by rank(A).

    Operations on Matrices

    There are various opereations that can be performed on matrices. Some of the common operations are:

    • Traversal – Traversing a matrix means visiting each element in the matrix exactly once. This can be done using nested loops to iterate over each row and column in the matrix.
    • Search – Searching for an element in a matrix involves finding the position of a specific element in the matrix. This can be done by traversing the matrix and comparing each element with the target element.
    • Row-wise Traversal – Traversing a matrix row-wise means visiting each element in each row of the matrix. This can be done by iterating over each row and then iterating over each column in the row.
    • Column-wise Traversal – Traversing a matrix column-wise means visiting each element in each column of the matrix. This can be done by iterating over each column and then iterating over each row in the column.
    • Accessing Elements – Accessing an element in a matrix means retrieving the value stored at a specific position in the matrix. This can be done by specifying the row and column index of the element to be accessed.

    Traversal of a Matrix

    Following code demonstrates how to traverse a matrix using nested loops:

    CC++JavaPython

    #include<stdio.h>intmain(){int rows =2, cols =2;int matrix[10][10];
       matrix[0][0]=1;
       matrix[0][1]=2;
       matrix[1][0]=3;
       matrix[1][1]=4;printf("The matrix is:\n");for(int i=0; i<rows; i++){for(int j=0; j<cols; j++){printf("%d ", matrix[i][j]);}printf("\n");}return0;}

    Output

    The output obtained is as follows −

    The matrix is:
    1 2
    3 4
    

    Search in a Matrix

    Following code demonstrates how to search an element in a matrix:

    CC++JavaPython

    //C Program to search an element in a matrix#include<stdio.h>intmain(){int rows =2, cols =2, i, j, key;int matrix[10][10];
       matrix[0][0]=1;
       matrix[0][1]=2;
       matrix[1][0]=3;
       matrix[1][1]=4;
       key =3;for(i=0; i<rows; i++){for(j=0; j<cols; j++){if(matrix[i][j]== key){printf("Element found at position (%d, %d)\n", i, j);return0;}}}printf("Element not found\n");return0;}

    Output

    The output obtained is as follows −

    Element found at position (1, 0)
    

    Row-wise Traversal of a Matrix

    Following code demonstrates how to traverse a matrix row-wise:

    CC++JavaPython

    //C Program to traverse a matrix row-wise#include<stdio.h>intmain(){int rows =2, cols =2, i, j;int matrix[10][10];
       matrix[0][0]=1;
       matrix[0][1]=2;
       matrix[1][0]=3;
       matrix[1][1]=4;printf("The matrix is:\n");for(i=0; i<rows; i++){for(j=0; j<cols; j++){printf("%d ", matrix[i][j]);}printf("\n");}return0;}

    Output

    The output obtained is as follows −

    The matrix is:
    1 2
    3 4
    

    Column-wise Traversal of a Matrix

    Following code demonstrates how to traverse a matrix column-wise:

    CC++JavaPython

    //C Program to traverse a matrix column-wise#include<stdio.h>intmain(){int rows =2, cols =2, i, j;int matrix[10][10];
       matrix[0][0]=1;
       matrix[0][1]=2;
       matrix[1][0]=3;
       matrix[1][1]=4;printf("The matrix is:\n");for(i=0; i<cols; i++){for(j=0; j<rows; j++){printf("%d ", matrix[j][i]);}printf("\n");}return0;}

    Output

    The output obtained is as follows −

    The matrix is:
    1 3
    2 4
    

    Accessing Elements of a Matrix

    Following code demonstrates how to access elements of a matrix:

    CC++JavaPython

    //C Program to access elements of a matrix#include<stdio.h>intmain(){int rows =2, cols =, i, j;int matrix[10][10];
       matrix[0][0]=1;
       matrix[0][1]=2;
       matrix[1][0]=3;
       matrix[1][1]=4;printf("The element at position (1, 1) is %d\n", matrix[0][0]);printf("The element at position (1, 2) is %d\n", matrix[0][1]);printf("The element at position (2, 1) is %d\n", matrix[1][0]);printf("The element at position (2, 2) is %d\n", matrix[1][1]);return0;}

    Output

    The output obtained is as follows −

    The element at position (1, 1) is 1
    The element at position (1, 2) is 2
    The element at position (2, 1) is 3
    The element at position (2, 2) is 4
    

    Application of Matrices

    Following are some of the applications of matrices:

    • Image processing –Matrices are used for images. let’s say we have an image of 100×100 pixels, then the image can be represented as a 100×100 matrix where each element represents the color of a pixel.Matrices can be used to perform operations such as scaling, rotation, and filtering on images.
    • Data analysis –It is also used for data analysis. Imagine we have a data set with multiple features, then the data set can be represented as a matrix where each row represents a data point and each column represents a feature.Matrices can be used to perform operations such as normalization, standardization, and dimensionality reduction on data sets.
    • Machine learning –In machine learning, matrices are used for representing data sets and models. input data, output data, and parameters of a model.Matrices can be used for performing operations such as forward propagation, backward propagation, and optimization in machine learning algorithms.
    • Computer graphics –Matrices are used in computer graphics for representing objects in 3D space, to store the position, rotation, and scale of objects, and perform operations such as translation, rotation, and scaling.
    • Scientific computing –They are also used in scientific computing to represent physical systems and perform simulations.Matrices can be used to store the state of a physical system, and perform operations such as integration, differentiation, and solving differential equations.

    Conclusion

    In this chapter, we learned about matrices in data structures, different types of matrices, components of a matrix, operations that can be performed on matrices, and applications of matrices in various fields. Matrices are a fundamental data structure used in various applications such as image processing, data analysis, machine learning, computer graphics, and scientific computing.

  • Quick Sort Algorithm

    Quick sort is a highly efficient sorting algorithm and is based on partitioning of array of data into smaller arrays. A large array is partitioned into two arrays one of which holds values smaller than the specified value, say pivot, based on which the partition is made and another array holds values greater than the pivot value.

    Quicksort partitions an array and then calls itself recursively twice to sort the two resulting subarrays. This algorithm is quite efficient for large-sized data sets as its average and worst-case complexity are O(n2), respectively.

    Partition in Quick Sort

    Following animated representation explains how to find the pivot value in an array.

    Quick Sort

    The pivot value divides the list into two parts. And recursively, we find the pivot for each sub-lists until all lists contains only one element.

    Quick Sort Pivot Algorithm

    Based on our understanding of partitioning in quick sort, we will now try to write an algorithm for it, which is as follows.

    1. Choose the highest index value has pivot
    2. Take two variables to point left and right of the list 
    excluding pivot
    3. Left points to the low index
    4. Right points to the high
    5. While value at left is less than pivot move right
    6. While value at right is greater than pivot move left
    7. If both step 5 and step 6 does not match swap left and right
    8. If left ≥ right, the point where they met is new pivot
    

    Quick Sort Pivot Pseudocode

    The pseudocode for the above algorithm can be derived as −

    function partitionFunc(left, right, pivot)
       leftPointer = left
       rightPointer = right - 1
    
       while True do
          while A[++leftPointer] < pivot do
          //do-nothing            
          end while
    		
          while rightPointer > 0 && A[--rightPointer] > pivot do
             //do-nothing         
          end while
    		
          if leftPointer >= rightPointer
             break
          else                
             swap leftPointer,rightPointer
          end if
       end while 
    	
       swap leftPointer,right
       return leftPointer
    end function
    

    Quick Sort Algorithm

    Using pivot algorithm recursively, we end up with smaller possible partitions. Each partition is then processed for quick sort. We define recursive algorithm for quicksort as follows −

    1. Make the right-most index value pivot
    2. Partition the array using pivot value
    3. Quicksort left partition recursively
    4. Quicksort right partition recursively
    

    Quick Sort Pseudocode

    To get more into it, let see the pseudocode for quick sort algorithm −

    procedure quickSort(left, right)
       if right-left <= 0
          return
       else     
          pivot = A[right]
          partition = partitionFunc(left, right, pivot)
          quickSort(left,partition-1)
          quickSort(partition+1,right)    
       end if		
    end procedure
    

    Analysis

    The worst case complexity of Quick-Sort algorithm is O(n2). However, using this technique, in average cases generally we get the output in O (n log n) time.

    Implementation

    Following are the implementations of Quick Sort algorithm in various programming languages −

    CC++JavaPython

    #include <stdio.h>#include <stdbool.h>#define MAX 7int intArray[MAX]={4,6,3,2,1,9,7};voidprintline(int count){int i;for(i =0; i < count -1; i++){printf("=");}printf("=\n");}voiddisplay(){int i;printf("[");// navigate through all items for(i =0; i < MAX; i++){printf("%d ", intArray[i]);}printf("]\n");}voidswap(int num1,int num2){int temp = intArray[num1];
       intArray[num1]= intArray[num2];
       intArray[num2]= temp;}intpartition(int left,int right,int pivot){int leftPointer = left -1;int rightPointer = right;while(true){while(intArray[++leftPointer]< pivot){//do nothing}while(rightPointer >0&& intArray[--rightPointer]> pivot){//do nothing}if(leftPointer >= rightPointer){break;}else{printf(" item swapped :%d,%d\n", intArray[leftPointer], intArray[rightPointer]);swap(leftPointer, rightPointer);}}printf(" pivot swapped :%d,%d\n", intArray[leftPointer], intArray[right]);swap(leftPointer, right);printf("Updated Array: ");display();return leftPointer;}voidquickSort(int left,int right){if(right - left <=0){return;}else{int pivot = intArray[right];int partitionPoint =partition(left, right, pivot);quickSort(left, partitionPoint -1);quickSort(partitionPoint +1, right);}}intmain(){printf("Input Array: ");display();printline(50);quickSort(0, MAX -1);printf("Output Array: ");display();printline(50);}

    Output

    Input Array: [4 6 3 2 1 9 7 ]
    ==================================================
     pivot swapped :9,7
    Updated Array: [4 6 3 2 1 7 9 ]
     pivot swapped :4,1
    Updated Array: [1 6 3 2 4 7 9 ]
     item swapped :6,2
     pivot swapped :6,4
    Updated Array: [1 2 3 4 6 7 9 ]
     pivot swapped :3,3
    Updated Array: [1 2 3 4 6 7 9 ]
    Output Array: [1 2 3 4 6 7 9 ]
    ==================================================