Daa Unit 3
Daa Unit 3
Input: n = 4 and k = 2
Output: 6
Explanation: 4 C 2 is 4!/(2!*2!) = 6
Input: n = 5 and k = 2
Output: 10
Explanation: 5 C 2 is 5!/(3!*2!) = 10
We have discussed O(n*k) time and O(k) extra space algorithm
in this post. The value of C(n, k) can be calculated in O(k) time and
O(1) extra space.
Approach:
Share
1. change r to n-r if r is greater than n-r. and create a variable to store
the answer.
2. Run a loop from 0 to r-1
3. In every iteration update ans as (ans*(n-i))/(i+1) where i is the loop
counter.
4. So the answer will be equal to ((n/1)*((n-1)/2)*…*((n-r+1)/r)
which is equal to nCr.
C(n, k)
= n! / (n-k)! * k!
= [n * (n-1) *....* 1] / [ ( (n-k) * (n-k-1) * .... * 1) *
( k * (k-1) * .... * 1 ) ]
After simplifying, we get
C(n, k)
= [n * (n-1) * .... * (n-k+1)] / [k * (k-1) * .... * 1]
return res;
}
// Driver Code
int main()
{ int n = 8, k = 2;
cout << "Value of C(" << n << ", " << k << ") is "
<< binomialCoeff(n, k);
return 0; }
Output
Value of C(8, 2) is 28
Complexity Analysis:
Time Complexity: O(r) A loop has to be run from 0 to r. So, the time
complexity is O(r).
Auxiliary Space: O(1) As no extra space is required.
Dynamic Programming Binomial Coefficients:
Dynamic algorithm constructs a nxk table, with the first column and
diagonal filled out using the IC.
Construct the table:
k
0 1 2 ... k-1 k
0 1
1 1 1
2 1 2 1
n .
.
.
k 1 1
.
.
.
n-1 1 C(n-
1, k-1)
n 1 C(n, k)
The table is then filled out iteratively, row by row using the recursive
relation.
Algorithm Binomial(n, k)
for i ← 0 to n do // fill out the table row wise
for i = 0 to min(i, k) do
if j==0 or j==i then C[i, j] ← 1 // IC
else C[i, j] ← C[i-1, j-1] + C[i-1, j] // recursive relation
return C[n, k]
the cost of the algorithm is filing out the table. Addition is the basic
operation. Because k ≤ n, the sum needs to be split into two parts
because only the half the table needs to be filled out for i < k and
remaining part of the table is filled out across the entire row.
A(n, k) = sum for upper triangle + sum for the lower rectangle
= ∑i=1k ∑j=1i-1 1 + ∑i=1n ∑j=1k 1
= ∑i=1k (i-1) + ∑i=1n k
= (k-1)k/2 + k(n-k) ε Θ(nk)
Step 1: Initialize the Distance[][] matrix using the input graph such that
Distance[i][j]= weight of edge from i to j, also Distance[i][j] = Infinity if
there is no edge from i to j.
Step 2: Treat node A as an intermediate node and calculate the
Distance[][] for every {i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to A) +
(Distance from A to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][A] +
Distance[A][j])
Step 3: Treat node B as an intermediate node and calculate the
Distance[][] for every {i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to B) +
(Distance from B to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][B] +
Distance[B][j])
Step 4: Treat node C as an intermediate node and calculate the
Distance[][] for every {i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to C) +
(Distance from C to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][C] +
Distance[C][j])
Step 5: Treat node D as an intermediate node and calculate the
Distance[][] for every {i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to D) +
(Distance from D to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][D] +
Distance[D][j])
Step 6: Treat node E as an intermediate node and calculate the
Distance[][] for every {i,j} node pair using the formula:
= Distance[i][j] = minimum (Distance[i][j], (Distance from i to E) +
(Distance from E to j ))
= Distance[i][j] = minimum (Distance[i][j], Distance[i][E] +
Distance[E][j])
Step 7: Since all the nodes have been treated as an intermediate node,
we can now return the updated Distance[][] matrix as our answer matrix.
// C++ Program for Floyd Warshall Algorithm
#include <bits/stdc++.h>
using namespace std;
int i, j, k;
/* Add all vertices one by one to
the set of intermediate vertices.
---> Before start of an iteration,
we have shortest distances between all
pairs of vertices such that the
shortest distances consider only the
vertices in set {0, 1, 2, .. k-1} as
intermediate vertices.
----> After the end of an iteration,
vertex no. k is added to the set of
intermediate vertices and the set becomes {0, 1, 2, ..
k} */
for (k = 0; k < V; k++) {
// Pick all vertices as source one by one
for (i = 0; i < V; i++) {
// Pick all vertices as destination for the
// above picked source
for (j = 0; j < V; j++) {
// If vertex k is on the shortest path from
// i to j, then update the value of
// dist[i][j]
if (dist[i][j] > (dist[i][k] + dist[k][j])
&& (dist[k][j] != INF
&& dist[i][k] != INF))
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
// Driver's code
int main()
{
/* Let us create the following weighted graph
10
(0)------->(3)
| /|\
5| |
| |1
\|/ |
(1)------->(2)
3 */
int graph[V][V] = { { 0, 5, INF, 10 },
{ INF, 0, 3, INF },
{ INF, INF, 0, 1 },
{ INF, INF, INF, 0 } };
// Function call
floydWarshall(graph);
return 0;
}
Output
The following matrix shows the shortest distances between every pair
of vertices
0 5 8 9
INF 0 3 4
INF INF 0 1
INF INF INF 0
Complexity Analysis of Floyd Warshall Algorithm:
Time Complexity: O(V3), where V is the number of vertices in the
graph and we run three nested loops each of size V
Auxiliary Space: O(V2), to create a 2-D matrix in order to store the
shortest distance for each pair of nodes.
Optimal Binary Search Tree
An Optimal Binary Search Tree (OBST), also known as a Weighted
Binary Search Tree, is a binary search tree that minimizes the expected
search cost. In a binary search tree, the search cost is the number of
comparisons required to search for a given key.
In an OBST, each node is assigned a weight that represents the
probability of the key being searched for. The sum of all the weights in
the tree is 1.0. The expected search cost of a node is the sum of the
product of its depth and weight, and the expected search cost of its
children.
To construct an OBST, we start with a sorted list of keys and their
probabilities. We then build a table that contains the expected search
cost for all possible sub-trees of the original list. We can use dynamic
programming to fill in this table efficiently. Finally, we use this table to
construct the OBST.
The time complexity of constructing an OBST is O(n^3), where n is the
number of keys. However, with some optimizations, we can reduce the
time complexity to O(n^2). Once the OBST is constructed, the time
complexity of searching for a key is O(log n), the same as for a regular
binary search tree.
The OBST is a useful data structure in applications where the keys
have different probabilities of being searched for. It can be used to
improve the efficiency of searching and retrieval operations in
databases, compilers, and other computer programs.
Given a sorted array key [0.. n-1] of search keys and an array freq[0.. n-
1] of frequency counts, where freq[i] is the number of searches
for keys[i]. Construct a binary search tree of all keys such that the total
cost of all the searches is as small as possible.
Let us first define the cost of a BST. The cost of a BST node is the level
of that node multiplied by its frequency. The level of the root is 1.
Examples:
Input: keys[] = {10, 12}, freq[] = {34, 50}
There can be following two possible BSTs
10 12
\ /
12 10
I II
Frequency of searches of 10 and 12 are 34 and 50 respectively.
The cost of tree I is 34*1 + 50*2 = 134
The cost of tree II is 50*1 + 34*2 = 118
// Driver code
public static void main(String[] args) {
int keys[] = {10, 12, 20};
int freq[] = {34, 8, 50};
int n = keys.length;
System.out.println("Cost of Optimal BST is " +
optimalSearchTree(keys, freq, n));
}
}
Output
Cost of Optimal BST is 142
Among the subsets that do not include the ith item, the value of
an optimal subset is, by definition, F (i − 1, j ).
Among the subsets that do include the ith item (hence, j − wi ≥ 0), an
optimal subset is made up of this item and an optimal subset of the
first i − 1 items that fits into the knapsack of capacity j − wi. The value
of such an optimal subset is vi + F (i − 1, j − wi).
Thus, the value of an optimal solution among all feasible subsets of the
first i items is the maximum of these two values. Of course, if the ith
item does not fit into the knapsack, the value of an optimal subset
selected from the first i items is the same as the value of an optimal
subset selected from the first i − 1 items. These observations lead to the
following recurrence:
Figure 8.4 illustrates the values involved in equations (8.6) and (8.7).
For i, j > 0, to compute the entry in the ith row and the j th column, F (i,
j ), we compute the maximum of the entry in the previous row and the
same column and the sum of vi and the entry in the previous row
and wi columns to the left. The table can be filled either row by row or
column by column.
The dynamic programming table, filled by applying formulas (8.6) and
(8.7), is shown in Figure 8.5.
Thus, the maximal value is F (4, 5) = $37. We can find the composition
of an optimal subset by backtracing the computations of this entry in the
table. Since F (4, 5) > F (3, 5), item 4 has to be included in an optimal
solution along with an optimal subset for filling 5 − 2 = 3 remaining
units of the knapsack capacity. The value of the latter is F (3, 3). Since F
(3, 3) = F (2, 3), item 3 need not be in an optimal subset. Since F (2, 3) >
F (1, 3), item 2 is a part of an optimal selection, which leaves element F
(1, 3 − 1) to specify its remaining composition. Similarly, since F (1, 2)
> F (0, 2), item 1 is the final part of the optimal solution {item 1, item 2,
item 4}.
The time efficiency and space efficiency of this algorithm are both
in (nW ). The time needed to find the composition of an optimal
solution is in O(n). You are asked to prove these assertions in the
exercises.
Memory Functions
The following algorithm implements this idea for the knapsack problem.
After initializing the table, the recursive function needs to be called
with i = n (the number of items) and j = W (the knapsack capacity).
ALGORITHM MFKnapsack(i, j )
if F [i, j ] < 0
if j < Weights[i]
value ← MFKnapsack(i − 1, j )
else
value ← max(MFKnapsack(i − 1, j ),
Just one nontrivial entry, V (1, 2), is retrieved rather than being
recomputed. For larger instances, the proportion of such entries can be
significantly larger.
In general, we cannot expect more than a constant-factor gain in using
the memory function method for the knapsack problem, because its time
efficiency class is the same as that of the bottom-up algorithm (why?). A
more significant improvement can be expected for dynamic
programming algorithms in which a computation of one value takes
more than constant time. You should also keep in mind that a memory
function algorithm may be less space-efficient than a space-efficient
version of a bottom-up algorithm.
Exercises 8.2
a. Apply the bottom-up dynamic programming algorithm to the
following instance of the knapsack problem:
How many different optimal subsets does the instance of part (a)
have?
In general, how can we use the table generated by the dynamic program-
ming algorithm to tell whether there is more than one optimal subset for
the knapsack problem’s instance?
a. Write pseudocode of the bottom-up dynamic programming
algorithm for the knapsack problem.
Greedy Algorithm
The greedy method is one of the strategies like Divide and conquer used
to solve the problems. This method is used for solving optimization
problems. An optimization problem is a problem that demands either
maximum or minimum results. Let's understand through some terms.
The above is the greedy algorithm. Initially, the solution is assigned with
zero value. We pass the array and number of elements in the greedy
algorithm. Inside the for loop, we select the element one by one and
checks whether the solution is feasible or not. If the solution is feasible,
then we perform the union.
P:A→B
If we say that we have to cover the journey at the minimum cost. This
means that we have to travel this distance as minimum as possible, so
this problem is known as a minimization problem. Till now, we have
two feasible solutions, i.e., one by train and another one by air. Since
travelling by train will lead to the minimum cost so it is an optimal
solution. An optimal solution is also the feasible solution, but providing
the best result so that solution is the optimal solution with the minimum
cost. There would be only one optimal solution.
The problem that requires either minimum or maximum result then that
problem is known as an optimization problem. Greedy method is one of
the strategies used for solving the optimization problems.
In order to find the most weighted path all possible path sum must
be computed and their path sum must be compared to get the
desired result, it is visible that the most weighted path in the above
graph is 10 -> 1 -> 30 that gives the path sum 41.
Correct Approach
Prim's Algorithm
In this article, we will discuss the prim's algorithm. Along with the
algorithm, we will also see the complexity, working, example, and
implementation of prim's algorithm.
Before starting the main topic, we should discuss the basic and
important terms such as spanning tree and minimum spanning tree.
ADVERTISEMENT
Prim's algorithm starts with the single node and explores all the adjacent
nodes with all the connecting edges at every step. The edges with the
minimal weights causing no cycles in the graph got selected.
Prim's algorithm is a greedy algorithm that starts from one vertex and
continue to add the edges with the smallest weight until the goal is
reached. The steps to implement the prim's algorithm are given as
follows -
Now, let's see the working of prim's algorithm using an example. It will
be easier to understand the prim's algorithm using an example.
ADVERTISEMENT
Step 1 - First, we have to choose a vertex from the above graph. Let's
choose B.
Step 2 - Now, we have to choose and add the shortest edge from vertex
B. There are two edges from vertex B that are B to C with weight 10 and
edge B to D with weight 4. Among the edges, the edge BD has the
minimum weight. So, add it to the MST.
Step 3 - Now, again, choose the edge with the minimum weight among
all the other edges. In this case, the edges DE and CD are such edges.
Add them to MST and explore the adjacent of C, i.e., E and A. So, select
the edge DE and add it to the MST.
Step 4 - Now, select the edge CD, and add it to the MST.
Step 5 - Now, choose the edge CA. Here, we cannot select the edge CE
as it would create a cycle to the graph. So, choose the edge CA and add
it to the MST.
So, the graph produced in step 5 is the minimum spanning tree of the
given graph. The cost of the MST is given below -
Algorithm
1. Step 1: Select a starting vertex
2. Step 2: Repeat Steps 3 and 4 until there are fringe vertices
3.
Step 3: Select an edge 'e' connecting the tree vertex and fringe vertex tha
t has minimum weight
4.
Step 4: Add the selected edge and the vertex to the minimum spanning tr
ee T
5. [END OF LOOP]
6. Step 5: EXIT
Complexity of Prim's algorithm
Now, let's see the time complexity of Prim's algorithm. The running time
of the prim's algorithm depends upon using the data structure for the
graph and the ordering of edges. Below table shows some choices -
o Time Complexity
The time complexity of the prim's algorithm is O(E logV) or O(V logV),
where E is the no. of edges, and V is the no. of vertices.
1. #include <stdio.h>
2. #include <limits.h>
3. #define vertices 5 /*Define the number of vertices in the graph*/
4.
/* create minimum_key() method for finding the vertex that has minimu
m key-value and that is not added in MST yet */
5. int minimum_key(int k[], int mst[])
6. {
7. int minimum = INT_MAX, min,i;
8.
9. /*iterate over all vertices to find the vertex with minimum key-
value*/
10. for (i = 0; i < vertices; i++)
11. if (mst[i] == 0 && k[i] < minimum )
12. minimum = k[i], min = i;
13. return min;
14. }
15. /* create prim() method for constructing and printing the MST.
16.
/* create array of size equal to total number of vertices for storing the
MST*/
20. int parent[vertices];
21.
/* create k[vertices] array for selecting an edge having minimum weig
ht*/
22. int k[vertices];
23. int mst[vertices];
24. int i, count,edge,v; /*Here 'v' is the vertex*/
25. for (i = 0; i < vertices; i++)
26. {
27. k[i] = INT_MAX;
28. mst[i] = 0;
29. }
30. k[0] = 0; /*It select as first vertex*/
31. parent[0] = -1; /* set first value of parent[] array to -
1 to make it root of MST*/
32. for (count = 0; count < vertices-1; count++)
33. {
34.
/*select the vertex having minimum key and that is not added in the
MST yet from the set of vertices*/
35. edge = minimum_key(k, mst);
36. mst[edge] = 1;
37. for (v = 0; v < vertices; v++)
38. {
39. if (g[edge][v] && mst[v] == 0 && g[edge][v] < k[v])
40. {
41. parent[v] = edge, k[v] = g[edge][v];
42. }
43. }
44. }
45. /*Print the constructed Minimum spanning tree*/
46. printf("\n Edge \t Weight\n");
47. for (i = 1; i < vertices; i++)
48. printf(" %d <-> %d %d \n", parent[i], i, g[i][parent[i]]);
49.
50. }
51. int main()
52. {
53. int g[vertices][vertices] = {{0, 0, 3, 0, 0},
54. {0, 0, 10, 4, 0},
55. {3, 10, 0, 2, 6},
56. {0, 4, 2, 0, 1},
57. {0, 0, 6, 1, 0},
58. };
59. prim(g);
60. return 0;
61. }
Output
So, that's all about the article. Hope, the article will be helpful and
informative to you.
Kruskal's Algorithm
In Kruskal's algorithm, we start from edges with the lowest weight and
keep adding the edges until the goal is reached. The steps to implement
Kruskal's algorithm are listed as follows -
The weight of the edges of the above graph is given in the below table -
Edge AB AC AD AE BC CD DE
Weight 1 7 10 5 3 4 2
Now, sort the edges given above in the ascending order of their weights.
Edge AB DE BC CD AE AC AD
Weight 1 2 3 4 5 7 10
Step 2 - Add the edge DE with weight 2 to the MST as it is not creating
the cycle.
Step 3 - Add the edge BC with weight 3 to the MST, as it is not creating
any cycle or loop.
Step 4 - Now, pick the edge CD with weight 4 to the MST, as it is not
forming the cycle.
Step 5 - After that, pick the edge AE with weight 5. Including this edge
will create the cycle, so discard it.
Step 6 - Pick the edge AC with weight 7. Including this edge will create
the cycle, so discard it.
Step 7 - Pick the edge AD with weight 10. Including this edge will also
create the cycle, so discard it.
So, the final minimum spanning tree obtained from the given weighted
graph by using Kruskal's algorithm is -
Now, the number of edges in the above tree equals the number of
vertices minus 1. So, the algorithm stops here.
Algorithm
1.
Step 1: Create a forest F in such a way that every vertex of the graph is a
separate tree.
2. Step 2: Create a set E that contains all the edges of the graph.
3.
Step 3: Repeat Steps 4 and 5 while E is NOT EMPTY and F is not spann
ing
4. Step 4: Remove an edge from E with minimum weight
5.
Step 5: IF the edge obtained in Step 4 connects two different trees, then
add it to the forest F
6. (for combining two trees into one tree).
7. ELSE
8. Discard the edge
9. Step 6: END
Complexity of Kruskal's algorithm
o Time Complexity
The time complexity of Kruskal's algorithm is O(E logE) or O(V
logV), where E is the no. of edges, and V is the no. of vertices.
1. #include <iostream>
2. #include <algorithm>
3. using namespace std;
4. const int MAX = 1e4 + 5;
5. int id[MAX], nodes, edges;
6. pair <long long, pair<int, int> > p[MAX];
7. void init()
8. {
9. for(int i = 0;i < MAX;++i)
10. id[i] = i;
11. }
12. int root(int x)
13. {
14. while(id[x] != x)
15. {
16. id[x] = id[id[x]];
17. x = id[x];
18. }
19. return x;
20. }
21. void union1(int x, int y)
22. {
23. int p = root(x);
24. int q = root(y);
25. id[p] = id[q];
26. }
27. long long kruskal(pair<long long, pair<int, int> > p[])
28. {
29. int x, y;
30. long long cost, minimumCost = 0;
31. for(int i = 0;i < edges;++i)
32. {
33. x = p[i].second.first;
34. y = p[i].second.second;
35. cost = p[i].first;
36. if(root(x) != root(y))
37. {
38. minimumCost += cost;
39. union1(x, y);
40. }
41. }
42. return minimumCost;
43. }
44. int main()
45. {
46. int x, y;
47. long long weight, cost, minimumCost;
48. init();
49. cout <<"Enter Nodes and edges";
50. cin >> nodes >> edges;
51. for(int i = 0;i < edges;++i)
52. {
53. cout<<"Enter the value of X, Y and edges";
54. cin >> x >> y >> weight;
55. p[i] = make_pair(weight, make_pair(x, y));
56. }
57. sort(p, p + edges);
58. minimumCost = kruskal(p);
59. cout <<"Minimum cost is "<< minimumCost << endl;
60. return 0;
61. }
Output
So, that's all about the article. Hope the article will be helpful and
informative to you.
Dijkstra's Algorithm
Dijkstra's shortest path algorithm was invented in 1956 by the Dutch
computer scientist Edsger W. Dijkstra during a twenty minutes coffee
break, while out shopping with his fiancée in Amsterdam.
The reason for inventing the algorithm was to test a new computer called
ARMAC.
It’s worth noting that Dijkstra’s algorithm is appropriate only when all
weights are favourable, as the weights of the edges are added to find the
shortest path during implementation.
It was about 1959, he issued an article of about three pages. The title of
the page was: “A note on two problems in connexion with graphs”.
Here, he explained the whole algorithm.
It differs from the minimum spanning tree because the shortest distance
between two vertices might not include all the vertices of the graph.
Dijkstra's Algorithm works on the basis that any subpath B -> D of the
shortest path A -> D between vertices A and D is also the shortest path
between vertices B and D.
It is easier to start with an example and then think about the algorithm.
Start with a weighted graph
Choose a starting vertex and assign infinity path values to all other
devices
Go to each vertex and update its path length
If the path length of the adjacent vertex is lesser than new path length,
don't update it
Avoid updating path lengths of already visited vertices
After each iteration, we pick the unvisited vertex with the least path
length. So we choose 5 before 7
Notice how the rightmost vertex has its path length updated twice
Repeat until all the vertices have been visited
We need to maintain the path distance of every vertex. We can store that
in an array of size v, where v is the number of vertices.
We also want to be able to get the shortest path, not only know the
length of the shortest path. For this, we map each vertex to the vertex
that last updated its path length.
Once the algorithm is over, we can backtrack from the destination vertex
to the source vertex to find the path.
import sys
num_of_vertices = len(vertices[0])
visited_and_distance = [[0, 0]]
for i in range(num_of_vertices-1):
visited_and_distance.append([0, sys.maxsize])
visited_and_distance[to_visit][0] = 1
i=0
In a telephone network
Algorithm:
Q=c
for i<-1 to n-1
do
{
temp <- get node ()
3. Create a new internal node with a frequency equal to the sum of the
two nodes frequencies. Make the first extracted node as its left child
and the other extracted node as its right child. Add this node to the
min heap.
4. Repeat steps#2 and #3 until the heap contains only one node. The
remaining node is the root node and the tree is complete.
Let us understand the algorithm with an example:
character Frequency
a 5
b 9
c 12
d 13
e 16
f 45
Step 1. Build a min heap that contains 6 nodes where each node
represents root of a tree with single node.
Step 2 Extract two minimum frequency nodes from min heap. Add a
new internal node with frequency 5 + 9 = 14.
Illustration of step 2
Now min heap contains 5 nodes where 4 nodes are roots of trees with
single element each, and one heap node is root of tree with 3 elements
character Frequency
c 12
d 13
Internal Node 14
e 16
f 45
Step 3: Extract two minimum frequency nodes from heap. Add a new
internal node with frequency 12 + 13 = 25
Illustration of step 3
Now min heap contains 4 nodes where 2 nodes are roots of trees with
single element each, and two heap nodes are root of tree with more
than one nodes
character Frequency
Internal Node 14
e 16
Internal Node 25
f 45
Step 4: Extract two minimum frequency nodes. Add a new internal
node with frequency 14 + 16 = 30
Illustration of step 4
Illustration of step 5
Illustration of step 6
Heap
priority-queue
+2 more
Morgan Stanley
Amazon
+3 more
Solve Problem
Submission count: 34K
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
class Huffman {
&& Character.isLetter(root.c)) {
return;
printCode(root.left, s + "0");
printCode(root.right, s + "1");
// main function
// number of characters.
int n = 6;
char[] charArray = { 'a', 'b', 'c', 'd', 'e', 'f'
};
PriorityQueue<HuffmanNode> q
= new
PriorityQueue<HuffmanNode>(
n, new MyComparator());
HuffmanNode hn = new
HuffmanNode();
hn.c = charArray[i];
hn.data = charfreq[i];
hn.left = null;
hn.right = null;
q.add(hn);
HuffmanNode x = q.peek();
q.poll();
HuffmanNode y = q.peek();
q.poll();
// new node f which is equal
HuffmanNode f = new
HuffmanNode();
f.c = '-';
f.left = x;
f.right = y;
// marking the f node as the root
node.
root = f;
q.add(f);
printCode(root, "");
class HuffmanNode {
int data;
char c;
HuffmanNode left;
HuffmanNode right;
Output
f: 0
c: 100
d: 101
a: 1100
b: 1101
e: 111
Time complexity: O(nlogn) where n is the number of unique
characters. If there are n nodes, extractMin() is called 2*(n – 1) times.
extractMin() takes O(logn) time as it calls minHeapify(). So, the
overall complexity is O(nlogn).
If the input array is sorted, there exists a linear time algorithm. We will
soon be discussing this in our next post.
Space complexity :- O(N)
Applications of Huffman Coding:
1. They are used for transmitting fax and text.
2. They are used by conventional compression formats like PKZIP,
GZIP, etc.
3. Multimedia codecs like JPEG, PNG, and MP3 use Huffman
encoding(to be more precise the prefix codes).
It is useful in cases where there is a series of frequently occurring
characters.