Professional Documents
Culture Documents
LINK: https://www.geeksforgeeks.org/insertion-sort/
Insertion sort is a simple sorting algorithm that works the way we sort
playing cards in our hands.
Algorithm
// Sort an arr[] of size n
insertionSort(arr, n)
Loop from i = 1 to n-1.
……a) Pick element arr[i] and insert it into sorted sequence arr[0…i-1]
Time Complexity: O(n*2)
Auxiliary Space: O(1)
Boundary Cases: Insertion sort takes maximum time to sort if elements are
sorted in reverse order. And it takes minimum time (Order of n) when elements
are already sorted.
Merge Sort
Link: https://www.geeksforgeeks.org/merge-sort/
if(left[i]<=right[j]){
arr[k]=left[i];
i++;
}else{
arr[k]=right[j];
j++;
}
k++;
}
/* Copy the remaining elements of left[], if there
are any */
while(i<n1){
arr[k]=left[i];
i++;
k++;
}
/* Copy the remaining elements of right[], if there
are any */
while(j<n2){
arr[k]=right[j];
j++;
k++;
}
}
/* l is for left index and r is right index of the
sub-array of arr to be sorted */
void mergeSort(int arr[], int l, int r){
if(l<r){
// Same as (l+r)/2, but avoids overflow for
// large l and h
int m=l+(r-l)/2;
//sort first and second halves
mergeSort(arr,l,m);
mergeSort(arr,m+1,r);
merge(arr, l, m , r);
}
}
/* UTILITY FUNCTIONS */
/* Function to print an array */
void printArray(int A[], int size){
int i;
for(i=0;i<size;i++){
printf("%d ",A[i]);
printf("\t");
}
}
Auxiliary Space: O(n)
Algorithmic Paradigm: Divide and Conquer
Applications of Merge Sort
Merge Sort is useful for sorting linked lists in O(nLogn) time.In the case of
linked lists, the case is different mainly due to the difference in memory
allocation of arrays and linked lists. Unlike arrays, linked list nodes may
not be adjacent in memory. Unlike an array, in the linked list, we can insert
items in the middle in O(1) extra space and O(1) time. Therefore merge
operation of merge sort can be implemented without extra space for linked
lists.
In arrays, we can do random access as elements are contiguous in memory. Let
us say we have an integer (4-byte) array A and let the address of A[0] be x
then to access A[i], we can directly access the memory at (x + i*4). Unlike
arrays, we can not do random access in the linked list. Quick Sort requires a
lot of this kind of access. In linked list to access i’th index, we have to
travel each and every node from the head to i’th node as we don’t have a
continuous block of memory. Therefore, the overhead increases for quicksort.
Merge sort accesses data sequentially and the need of random access is low.
QuickSort
Link: https://www.geeksforgeeks.org/quick-sort/
#include <stdio.h>
#include <stdlib.h>
int i,j;
int aux=0;
x=a[r];
i=p-1;
for(j=p;j<=r-1;j++){
if(a[j]<=x){
i=i+1;
aux=a[i];
a[i]=a[j];
a[j]=aux;
//
a[r]=a[i+1];
a[i+1]=x;
return i+1;
}
int quick_sort(int a[],int p,int r){
int q=0;
if(p<r){
q=partition(a,p,r);
quick_sort(a,p,q-1);
quick_sort(a,q+1,r);
return 0;
int i;
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
printf("n = %d\n",n);
}
void printArray(int a[], int n){
int i;
int contor=0;
for(i=1;i<=n;i++){
printf("%d ",a[i]);
printf("\t");
contor++;
int main()
int a[50];
int n;
scanf("%d",&n);
read_array(a,n);
printArray(a,n);
printf("Hello world!\n");
quick_sort(a,1,n);
printf("\n");
printArray(a,n);
return 0;
The first two terms are for two recursive calls, the last term is for the
partition process. k is the number of elements which are smaller than pivot.
The time taken by QuickSort depends upon the input array and partition
strategy. Following are three cases.
Worst Case: The worst case occurs when the partition process always picks
greatest or smallest element as pivot. If we consider above partition
strategy where last element is always picked as pivot, the worst case would
occur when the array is already sorted in increasing or decreasing order.
Best Case: The best case occurs when the partition process always picks the
middle element as pivot.
Average Case:
To do average case analysis, we need to consider all possible permutation of
array and calculate time taken by every permutation which doesn’t look easy.
We can get an idea of average case by considering the case when partition
puts O(n/9) elements in one set and O(9n/10) elements in other set.
Although the worst case time complexity of QuickSort is O(n 2) which is more
than many other sorting algorithms like Merge Sort and Heap Sort, QuickSort
is faster in practice, because its inner loop can be efficiently implemented
on most architectures, and in most real-world data. QuickSort can be
implemented in different ways by changing the choice of pivot, so that the
worst case rarely occurs for a given type of data. However, merge sort is
generally considered better when data is huge and stored in external storage.
If a Greedy Algorithm can solve a problem, then it generally becomes the best
method to solve that problem as the Greedy algorithms are in general more
efficient than other techniques like Dynamic Programming. But Greedy
algorithms cannot always be applied.
The greedy algorithms are sometimes also used to get an approximation for
Hard optimization problems. For example, Traveling Salesman Problem is a NP-
Hard problem. A Greedy choice for this problem is to pick the nearest
unvisited city from the current city at every step. This solutions don’t
always produce the best optimal solution but can be used to get an
approximately optimal solution.
The greedy choice is to always pick the next activity whose finish time is
least among the remaining activities and the start time is more than or equal
to the finish time of previously selected activity. We can sort the
activities according to their finishing time so that we always consider the
next activity as minimum finishing time activity.
1) Sort the activities according to their finishing time
2) Select the first activity from the sorted array and print it.
3) Do following for remaining activities in the sorted array.
…….a) If the start time of this activity is greater than or equal to the
finish time of previously selected activity then select this activity and
print it.
Time Complexity : It takes O(n log n) time if input activities may not be
sorted. It takes O(n) time when it is given that input activities are always
sorted.
#include <stdio.h>
#include <stdlib.h>
int j, i=0;
s[0]=0; // s[]- start , f[]- final
printf(" Activitatile cu numarul : %d\t",i); // intotdeauna prima
activitate este aleasa
for(j=1;j<n;j++){
if(s[j]>=f[i]){
printf("%d\t",j);
//printf("\n");
i=j;
}
int main()
{
int n, i, j;
printf("\t");
}
printf("Hello world!\n");
printMaxAct(s,f,n);
return 0;
}
HeapSort
Heap sort is a comparison based sorting technique based on Binary Heap data
structure. It is similar to selection sort where we first find the maximum
element and place the maximum element at the end. We repeat the same process
for remaining element.
What is Binary Heap?
Let us first define a Complete Binary Tree. A complete binary tree is a
binary tree in which every level, except possibly the last, is completely
filled, and all nodes are as far left as possible (Source Wikipedia)
A Binary Heap is a Complete Binary Tree where items are stored in a special
order such that value in a parent node is greater(or smaller) than the values
in its two children nodes. The former is called as max heap and the latter is
called min heap. The heap can be represented by binary tree or array.
Notes:
Heap sort is an in-place algorithm.
Its typical implementation is not stable, but can be made stable (See this)
Time Complexity: Time complexity of heapify is O(Logn). Time complexity of
createAndBuildHeap() is O(n) and overall time complexity of Heap Sort is
O(nLogn).
Applications of HeapSort
1. Sort a nearly sorted (or K sorted) array
2. k largest(or smallest) elements in an array
Heap sort algorithm has limited uses because Quicksort and Mergesort are
better in practice. Nevertheless, the Heap data structure itself is
enormously used.
#include <stdio.h>
#include <stdlib.h>
}
void printArray(int a[], int n){
int i;
for(i=0;i<n;i++){
printf("%d",a[i]);
printf("\t");
}
}
int main()
{
printf("\n");
int a[]={12,11,13,5,6,7};
int n=sizeof(a)/sizeof(a[0]);
printf("array-u initial : \n");
printArray(a,n);
heapSort(a,n);
Example:
Input: V = 70
Output: 2
We need a 50 Rs note and a 20 Rs note.
Input: V = 121
Output: 3
We need a 100 Rs note, a 20 Rs note and a
1 Rs coin.
The idea is simple Greedy Algorithm. Start from largest possible denomination
and keep adding denominations while remaining value is greater than 0. Below
is complete algorithm.
int coinList[MAX]={0};
int i, k=0;
for(i=COINS-1;i>=0;i--){ // merge de la ultimu elem-1 pana la 0 si se
decrementeaza
while(cost>=coins[i]){ //daca valoarea noastra e >= cu moneda de pe
pozitia i
cost -=coins[i]; //scade din valoare moneda gasita
coinList[k++]=coins[i]; // adauga in lista noua moneda gasita
} // while se apeleaza pana se epuizeaza
optiunea
}
for(i=0;i<k;i++){
printf(" %d\t",coinList[i]);
}
// return;
int main()
{
int i,k;
Cutting a Rod
Given a rod of length n inches and an array of prices that contains prices of
all pieces of size smaller than n. Determine the maximum value obtainable by
cutting up the rod and selling the pieces. For example, if length of the rod
is 8 and the values of different pieces are given as following, then the
maximum obtainable value is 22 (by cutting in two pieces of lengths 2 and 6)
length | 1 2 3 4 5 6 7 8
--------------------------------------------
price | 1 5 8 9 10 17 17 20
And if the prices are as following, then the maximum obtainable value is 24
(by cutting in eight pieces of length 1)
length | 1 2 3 4 5 6 7 8
--------------------------------------------
price | 3 5 8 9 10 17 17 20
A naive solution for this problem is to generate all configurations of
different pieces and find the highest priced configuration. This solution is
exponential in term of time complexity. Let us see how this problem possesses
both important properties of a Dynamic Programming (DP) Problem and can
efficiently solved using Dynamic Programming.
1) Optimal Substructure:
We can get the best price by making a cut at different positions and
comparing the values obtained after a cut. We can recursively call the same
function for a piece obtained after a cut.
Let cutRod(n) be the required (best possible price) value for a rod of length
n. cutRod(n) can be written as following.
cutRod(n) = max(price[i] + cutRod(n-i-1)) for all i in {0, 1 .. n-1}
2) Overlapping Subproblems
Following is simple recursive implementation of the Rod Cutting problem. The
implementation simply follows the recursive structure mentioned above.
Itereaza acasa toata problema recursive
O sa am de pus – infinit
Cum fac asta: include libraria <limits.h>
Si folosesc INT_MIN
q=INT_MIN;
Ce am inteles:
Cut_rod(0,n)
Memorized :
makenull() , cu santinela
cauta pe net ca nu ai fost atenta
Geeks: https://www.geeksforgeeks.org/doubly-linked-list/
Ce am inteles:
Se leaga succesorul nodului head cu urmatorul element
Un nod are 3 casute , next, key, prev
SEARCH :
LIST_SEARCH(LISTA L, KEY) //L param. IN//fct returnează un pointer către
nodul găsit
Nod_lista x //Nod_lista este un pointer
x := L.head
WHILE x <> NULL AND x.cheie<> KEY DO // atata timp cat cheia nu s-a gasit si
nu e sfarsitu listei
x := x.next // x pointeaza catre element urmator
END WHILE
RETURN x // daca s-a gasit sau s-a terminat siru , se
returneaza X
END LIST_SEARCH
Atunci cand nu sunt indeplinite ambele conditii x devine NULL , pointeaza
spre valoarea NULL deoarece nu mai avem elemente
Like arrays, Linked List is a linear data structure. Unlike arrays, linked
list elements are not stored at a contiguous location; the elements are
linked using pointers.
Steps
Let the pointer to this given node be next_node and the data of the new node
to be added as new_data.
5. Check if the next_node is NULL or not. If it’s NULL, return from the
function because any new node can not be added before a NULL
6. Allocate memory for the new node, let it be called new_node
7. Set new_node->data = new_data
8. Set the previous pointer of this new_node as the previous node of the
next_node, new_node->prev = next_node->prev
9. Set the previous pointer of the next_node as the new_node, next_node-
>prev = new_node
10. Set the next pointer of this new_node as the next_node, new_node-
>next = next_node;
11. If the previous node of the new_node is not NULL, then set the
next pointer of this previous node as new_node, new_node->prev->next =
new_node
12. Else, if the prev of new_node is NULL, it will be the new head
node. So, make (*head_ref) = new_node.
/* Given a node as prev_node, insert a new node after the given node */
void insertAfter(struct Node* prev_node, int new_data)
{
/*1. check if the given prev_node is NULL */
if (prev_node == NULL) {
printf("the given previous node cannot be NULL");
return;
}
return;
}
// This function prints contents of linked list starting from the given
node
void printList(struct Node* node)
{
struct Node* last;
printf("\nTraversal in forward direction \n");
while (node != NULL) {
printf(" %d ", node->data);
last = node;
node = node->next;
}
getchar();
return 0;
}
typedef struct {
t_nod_lista *head;
}t_lista;
t_nod_lista *x;
x=L->head->next;
while(x!=NULL){
list_delete(L,x);
free(x);
x=L->head->next;
}
free(L->head);
}
int main()
{
printf("Bun venit in program\n");
int s,key;
t_lista *L;
t_nod_lista *x;
printf("crapa la makenull\n");
makenull(L); // merge in makenull si crapa
s=1;
printf(" inainte de while\n");
while(s!=0){
printf("in while");
printf("cheia : ");
scanf("%d",&key);
if(s==1){
printf("cheia : ");
scanf("%d",&key);
malloc(sizeof(x));
list_insert(L,x);
}else if(s==2){
printf("cheia : ");
scanf("%d",&key);
x=list_search(*L,key);
if(x!=NULL){
printf(" key= %d,x= %d",key,x);
}else{
printf("cheie negasita");
}
}else if(s==3){
printf("cheia : ");
scanf("%d",&key);
x=list_search(*L,key);
if(x!=NULL){
list_delete(L,x);
}else{
printf("cheia negasita");
}
}else{
list_print(L);
}
}
list_free(L);
printf("Hello World");
return 0;
}
/* given a node as prev_node, insert a new node after the given node*/
}
void append(struct Node** head_ref, int new_data){
//1. aloca memorie pt nod
struct Node* new_node=(struct Node*)malloc(sizeof(struct Node));
struct Node* last=*head_ref; //folosit in pasu 5
// 2.put in the data
new_node->data=new_data;
//3.nodu asta o sa fie ultimu nod asa ca facem next-u lui ca fiind NULL
new_node->next=NULL;
//4.daca lista linkuita ii goala, fa un nou nod ca si cap
if((*head_ref)==NULL){
new_node->prev=NULL;
*head_ref=new_node;
return;
}
//5.else traverse till the last node
while(last->next!=NULL){
last=last->next;
}
//6.chimba nextu ultimului nod
last->next=new_node;
//7. fa last node , prev-u noului nod
new_node->prev=last;
return;
}
void printList(struct Node* node){
struct Node* last;
printf("\nTraversal in forward direction \n");
while(node!=NULL){
printf("%d",node->data);
last=node;
node=node->next;
}
printf("\nTraversal in reverse direction \n");
while(last!=NULL){
printf("%d",last->data);
last=last->prev;
}
}
void deleteNode(struct Node** head_ref,struct Node* del){
// cazu de baza cand nu exista elem in lista sau nu avem elem de sters
if(*head_ref==NULL||del==NULL){
return;
}
// daca nodul de sters este capul listei:
if(*head_ref==del){
*head_ref= del->next;
}
// schimbam next numai daca nodul de sters nu e ultimu elem din sir
if(del->next!=NULL){
del->next->prev=del->prev;
}
// schimbam prev- daca nodu de sters nu e head
if(del->prev!=NULL){
del->prev->next=del->next;
}
return 0;
}
HASH TABLE
Coliziune: prin adresare directa sau inlantuire
Atunci cand avem doua chei pe aceeasi pozitie
HASH_INIT(T[], M) //tabela este T[0..M-1]
FOR j := 0 TO M – 1
T[j] := -1 END FOR END HASH_INIT
// initializeaza fiecare element din sir cu –1 ca sa stim ca slotul e
gol(putem sa il folosim)
// cauta functia de probare liniara! (no ideea what it is)
HASH_PROBEF(K, I, M) //functia de probare liniara
RETURN (HASH_PRIM(K, M)+I) MOD M
END HASH_PROBEF
// cauta o pozitie pe care sa insereze un numar , se duce de la 0 la m
returnand o pozitie
// de obicei incearca sa puna numarul la pozitia = cu numaru daca are cum
}
int hash_prim(int k, int m){
return (k%m);
}
int hash_probef(int k, int i, int m){
return (hash_prim(k,m)+1)%m;
}
int hash_insert(int T[], int k , int m){
int i=0,j=0;
j=hash_probef(k,i,m); // determina pozitia pe care sa insereze
if(T[j]==-1){ // daca pozitia are valoarea -1 inseamna ca e libera
T[j]=k; // se insereaza cheia pe pozitia gasita
return j; // returneaza pozitia cheii inserate
}else{
i=i+1; // altfel continua sa caute o alta pozitie
}
while(k!=0){
j=hash_insert(T,k,m);
printf("cheia inserata la locatia %d", j);
printf("\nnext key: ");
scanf("%d",&k);
}
printf("tabela cu numere inserate este: ");
hash_print(T,m);
j=hash_search(T,k,m);
if(j>-1){
printf("cheie gasita la locatia: %d",j);
}else{
printf("CHEIE NEGASITA");
}
printf("\nstergere cheie: ");
scanf("%d",&k);
j=hash_delete(T,k,m);
if(j>-1){
printf("\n cheie stearsa de la locatia %d",j);
hash_print(T,m);
}else{
printf(" \n cheia nu a fost stearsa");
}
printf("\nHello World");
return 0;
}
In inserare : cand se umple lista o sa returneze –1;
Separate Chaining:
The idea is to make each cell of hash table point to a linked list of records
that have same hash function value.
Let us consider a simple hash function as “key mod 7” and sequence of keys as
50, 700, 76, 85, 92, 73, 101.
Advantages:
1) Simple to implement.
2) Hash table never fills up, we can always add more elements to the chain.
3) Less sensitive to the hash function or load factors.
4) It is mostly used when it is unknown how many and how frequently keys may
be inserted or deleted.
Disadvantages:
1) Cache performance of chaining is not good as keys are stored using a
linked list. Open addressing provides better cache performance as everything
is stored in the same table.
2) Wastage of Space (Some Parts of hash table are never used)
3) If the chain becomes long, then search time can become O(n) in the worst
case.
4) Uses extra space for links.
Vezi linku asta:
https://www.sanfoundry.com/c-program-implement-hash-tables-chaining-doubly-
linked-lists/
\
}t_nod_arb;
typedef struct{
t_nod_arb *root;
}t_arbore;
}
t_nod_arb* create_node(int key){
t_nod_arb *n;
n=(t_nod_arb*)malloc(sizeof(t_nod_arb));
n->key=key;
n->left=NULL;
n->right=NULL;
n->parent=NULL;
return n;
}
}
void transplant(t_arbore *A, t_nod_arb *u, t_nod_arb *v){
if(u->parent==NULL){
A->root=v;
}else if(u==u->parent->left){
u->parent->left=v;
}else{
u->parent->right=v;
}
if(v!=NULL){
v->parent=u->parent;
}
}
void tree_delete(t_arbore *A,t_nod_arb *n){
t_nod_arb *y;
if(n->left==NULL){ //nodul n are 1 copil dreapta/stanga
transplant(A,n,n->right);
}else if(n->right==NULL){
transplant(A,n,n->left);
}else{ // nodul n are 2 copii
y=tree_min(n->right);
if(y->parent!=n){
transplant(A,y,y->right);
y->right=n->right;
y->right->parent=y;
}
transplant(A,n,y);
y->left=n->left;
y->left->parent=y;
}
}
int main()
{
t_arbore T[20];
int x;
t_nod_arb *n,*r,*s;
printf("\nnodul radacina cu cheia x=");
scanf("%d",&x);
r=make_root(T,x);
printf("\nintroduceti pana la citirea lui o\n");
printf("x=");
scanf("%d",&x);
while(x!=0){
n=create_node(x);
tree_insert(T,n);
printf("x=");
scanf("%d",&x);
}
printf("inorder_walk:\n");
inorder_walk(r);
printf("\npreorder_walk: ");
preorder_walk(r);
printf("\n");
printf("Regasire nod cu cheia x= ");
scanf("%d",&x);
n=it_tree_search(r,x);
if(n!=NULL){
printf("nodul cu cheia %d gasit iterativ\n",n->key);
}else{
printf("nodul nu a fost gasit iterativ\n");
}
n=tree_search(r,x);
if(n!=NULL){
printf("nodul cu cheia %d gasit recursiv\n",n->key);
}else{
printf("nodul nu a fost gasit recursiv\n");
}
n=tree_min(r);
printf("\nTree minimum: %d\n",n->key);
n=tree_max(r);
printf("tree maximum: %d\n",n->key);
n=tree_search(r,x);
// succesorul nodului n va fi nodul succesorul
s=tree_succesor(n);
if(s!=NULL){
printf("Nod succesor: %d \n",s->key);
}else{
printf(" NULL \n");
}
Trees: Unlike Arrays, Linked Lists, Stack and queues, which are linear data
structures, trees are hierarchical data structures.
Tree Vocabulary: The topmost node is called root of the tree. The elements
that are directly under an element are called its children. The element
directly above something is called its parent. For example, ‘a’ is a child of
‘f’, and ‘f’ is the parent of ‘a’. Finally, elements with no children are
called leaves.
Why Trees?
1. One reason to use trees might be because you want to store information
that naturally forms a hierarchy. For example, the file system on a computer:
file system----------- / <-- root / \... home /
\ ugrad course / / | \ ... cs101 cs112
cs113
Binary Tree: A tree whose elements have at most 2 children is called a binary
tree. Since each element in a binary tree can have only 2 children, we
typically name them the left and right child.
5) In Binary tree where every node has 0 or 2 children, number of leaf nodes
is always one more than nodes with two children.
L = T + 1Where L = Number of leaf nodes T = Number of internal nodes
with two children
RED_BLACK TREE :
3) There are no two adjacent red nodes (A red node cannot have a red parent
or red child).
4) Every path from a node (including root) to any of its descendant NULL node
has the same number of black nodes.
From the above examples, we get some idea how Red-Black trees ensure balance.
Following is an important fact about balancing in Red-Black Trees.
Number of nodes from a node to its farthest descendant leaf is no more than
twice as the number of nodes to the nearest descendant leaf.
Every Red Black Tree with n nodes has height <= 2Log2(n+1)
2) From property 4 of Red-Black trees and above claim, we can say in a Red-
Black Tree with n nodes, there is a root to leaf path with at-most Log2(n+1)
black nodes.
3) From property 3 of Red-Black trees, we can claim that the number black
nodes in a Red-Black tree is at least ⌊ n/2 ⌋ where n is the total number of
nodes.
From above 2 points, we can conclude the fact that Red Black Tree with n
nodes has height <= 2Log2(n+1)
1) Recoloring
2) Rotation
We try recoloring first, if recoloring doesn’t work, then we go for rotation.
Following is detailed algorithm. The algorithms has mainly two cases
depending upon the color of uncle. If uncle is red, we do recoloring. If
uncle is black, we do rotations and/or recoloring.
….b) If x’s uncle is BLACK, then there can be four configurations for x, x’s
parent (p) and x’s grandparent (g) (This is similar to AVL Tree)
……..i) Left Left Case (p is left child of g and x is left child of p)
……..ii) Left Right Case (p is left child of g and x is right child of p)
……..iii) Right Right Case (Mirror of case i)
……..iv) Right Left Case (Mirror of case ii)
La practic:
GRAFURI :
Grafuri orientate si neorientate …
Ii un sir de liste dublu inlantuite , lucram ca si la listele dublu
inlantuite , avem head dar de data asta are si o cheie , next si prev , si
inseram vecinii cheii in acelasi mod ca si la liste da inainte se face
functia makenull
NSERT_VECINI(LISTA_ADIACENTA G,S)
NOD_LISTA nod
PRINT “Nod sursa ”+S+”: “
G[S].head->cheie := S // se apeleaza cu punct g[s].head
Ii punctulet pentru ca ii pointer catre lista , adica pointeaza catre toata
lista
S- nodul sursaa
Graph Data Structure And Algorithms
In the above Graph, the set of vertices V = {0,1,2,3,4} and the set of edges
E = {01, 12, 23, 34, 04, 14, 13}.
Graphs are used to solve many real-life problems. Graphs are used to
represent networks. The networks may include paths in a city or telephone
network or circuit network. Graphs are also used in social networks like
linkedIn, Facebook. For example, in Facebook, each person is represented with
a vertex(or node). Each node is a structure and contains information like
person id, name, gender, locale etc.
Given an undirected, connected and weighted graph, find Minimum Spanning Tree
(MST) of the graph using Kruskal’s algorithm.
Below are the steps for finding MST using Kruskal’s algorithm
13. Sort all the edges in non-decreasing order of their weight.
14. Pick the smallest edge. Check if it forms a cycle with the
spanning tree formed so far. If cycle is not formed, include this edge.
Else, discard it.
15. Repeat step#2 until there are (V-1) edges in the spanning tree.
Here are some key points which will be useful for us in implementing the
Kruskal’s algorithm using STL.
16. Use a vector of edges which consist of all the edges in the graph
and each item of a vector will contain 3 parameters: source,
destination and the cost of an edge between the source and destination.
vector<pair<int, pair<int, int> > > edges;
17. Here in the outer pair (i.e pair<int,pair<int,int> > ) the first
element corresponds to the cost of a edge while the second element is
itself a pair, and it contains two vertices of edge.
18. Use the inbuilt std::sort to sort the edges in the non-decreasing
order; by default the sort function sort in non-decreasing order.
19. We use the Union Find Algorithm to check if it the current edge forms a
cycle if it is added in the current MST. If yes discard it, else
include it (union).
Pseudo Code:
// Initialize resultmst_weight = 0// Create V single item setsfor each vertex
vparent[v] = v;rank[v] = 0;Sort all edges into non decreasing order by weight
wfor each (u, v) taken from the sorted list E do if FIND-SET(u) != FIND-
SET(v) print edge(u, v) mst_weight += weight of edge(u, v)
UNION(u, v)
Minimum Spanning Tree (MST) problem: Given connected graph G with positive
edge weights, find a min weight set of edges that connects all of the
vertices.
MST is fundamental problem with diverse applications.
Network design.
– telephone, electrical, hydraulic, TV cable, computer, road
The standard application is to a problem like phone network design. You have
a business with several offices; you want to lease phone lines to connect
them up with each other; and the phone company charges different amounts of
money to connect different pairs of cities. You want a set of lines that
connects all your offices with a minimum total cost. It should be a spanning
tree, since if a network isn’t a tree you can always remove some edges and
save money.
Approximation algorithms for NP-hard problems.
– traveling salesperson problem, Steiner tree
A less obvious application is that the minimum spanning tree can be used to
approximately solve the traveling salesman problem. A convenient formal way
of defining this problem is to find the shortest path that visits each point
at least once.
Note that if you have a path visiting all points exactly once, it’s a special
kind of tree. For instance in the example above, twelve of sixteen spanning
trees are actually paths. If you have a path visiting some vertices more than
once, you can always drop some edges to get a tree. So in general the MST
weight is less than the TSP weight, because it’s a minimization over a
strictly larger set.
On the other hand, if you draw a path tracing around the minimum spanning
tree, you trace each edge twice and visit all points, so the TSP weight is
less than twice the MST weight. Therefore this tour is within a factor of two
of optimal.
Indirect applications.
– max bottleneck paths
– LDPC codes for error correction
– image registration with Renyi entropy
– learning salient features for real-time face verification
– reducing data storage in sequencing amino acids in a protein
– model locality of particle interactions in turbulent fluid flows
– autoconfig protocol for Ethernet bridging to avoid cycles in a network
Cluster analysis
k clustering problem can be viewed as finding an MST and deleting the k-1
most
expensive edges.
The idea of using key values is to pick the minimum weight edge from cut. The
key values are used only for vertices which are not yet included in MST, the
key value for these vertices indicate the minimum weight edges connecting
them to the set of vertices included in MST.
Let us understand with the following example:
The set mstSet is initially empty and keys assigned to vertices are {0, INF,
INF, INF, INF, INF, INF, INF} where INF indicates infinite. Now pick the
vertex with minimum key value. The vertex 0 is picked, include it in mstSet.
So mstSet becomes {0}. After including to mstSet, update key values of
adjacent vertices. Adjacent vertices of 0 are 1 and 7. The key values of 1
and 7 are updated as 4 and 8. Following subgraph shows vertices and their key
values, only the vertices with finite key values are shown. The vertices
included in MST are shown in green color.
Pick the vertex with minimum key value and not already included in MST (not
in mstSET). The vertex 1 is picked and added to mstSet. So mstSet now becomes
{0, 1}. Update the key values of adjacent vertices of 1. The key value of
vertex 2 becomes 8.
Pick the vertex with minimum key value and not already included in MST (not
in mstSET). We can either pick vertex 7 or vertex 2, let vertex 7 is picked.
So mstSet now becomes {0, 1, 7}. Update the key values of adjacent vertices
of 7. The key value of vertex 6 and 8 becomes finite (1 and 7 respectively).
Pick the vertex with minimum key value and not already included in MST (not
in mstSET). Vertex 6 is picked. So mstSet now becomes {0, 1, 7, 6}. Update
the key values of adjacent vertices of 6. The key value of vertex 5 and 8 are
updated.
We repeat the above steps until mstSet includes all vertices of given graph.
Finally, we get the following graph.
Solution: As edge weights are unique, there will be only one edge emin and
that will be added to MST, therefore option (A) is always true.
As spanning tree has minimum number of edges, removal of any edge will
disconnect the graph. Therefore, option (B) is also true.
As all edge weights are distinct, G will have a unique minimum spanning
tree. So, option (D) is correct.
Option C is false as emax can be part of MST if other edges with lesser
weights are creating cycle and number of edges before adding emax is less
than (n-1).
Type 2. How to find the weight of minimum spanning tree given the graph –
This is the simplest type of question based on MST. To solve this using
kruskal’s algorithm,
Type 4. Out of given sequences, which one is not the sequence of edges added
to the MST using Kruskal’s algorithm –
To solve this type of questions, try to find out the sequence of edges which
can be produced by Kruskal. The sequence which does not match will be the
answer.
Que – 4. Consider the following graph:
PRIM:
Pot incepe de la orice nod
Initializez toate valorile cu infinit, si incep cu primul nod, verific
vecinii nodului si ne uitam la valorile lor , actualizez valorile (ca le.am
pus ca si infinit), aleg calea mai scurta si scot nodu din coada(pasii se
repeta)
Ideea e sa fie conectate fiecare “casa”