0% found this document useful (0 votes)
126 views93 pages

SDOT Training Day2

The document discusses stacks, which are linear data structures that follow the LIFO (last in, first out) principle. Stacks allow insertion and deletion of elements only at one end, called the top. Common stack operations are push to add an element and pop to remove the top element. Stacks have various applications and can be implemented using arrays or linked lists. The document provides code examples of stack implementations in C and Java using arrays that utilize push, pop, peek and other methods.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
126 views93 pages

SDOT Training Day2

The document discusses stacks, which are linear data structures that follow the LIFO (last in, first out) principle. Stacks allow insertion and deletion of elements only at one end, called the top. Common stack operations are push to add an element and pop to remove the top element. Stacks have various applications and can be implemented using arrays or linked lists. The document provides code examples of stack implementations in C and Java using arrays that utilize push, pop, peek and other methods.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 93

SESSION 2

Stack – Implementation and applications


Introduction to Stack

• Stack can be defined as a Data Structure that serves as saving the data in a
particular fashion.
• In linear data structures like array and linked list a user is allowed to insert
or delete any element to and from any location respectively.
• However, in a Stack both, insertion and deletion, is permitted at one end
only.
• A Stack works on the LIFO (Last In – First Out) basis, i.e , the first element
that is inserted in the stack would be the last to be deleted; or the last
element to be inserted in the stack would be the first to be deleted..
Stacks

push() pop()

top()
Stack
Stack is a A Last In First Out (LIFO) data structure.
Primary operations: Push and Pop
push()
• Add an element to the top of the stack
pop()
• Remove the element from the top of the stack
Additionally, few more methods also defined in typical implementations:
Size()
isEmpty()
If Full()
Stack

Algorithm for PUSH operation


• Check if the stack is full or not.
• If the stack is full, then print error of overflow and exit the program.
• If the stack is not full, then increment the top and add the element.
Algorithm for POP operation
• Check if the stack is empty or not.
• If the stack is empty, then print error of underflow and exit the program.
• If the stack is not empty, then print the element at the top and decrement
the top.
Stack

In a stack implementation using arrays following scenarios depicts


various states of the stack

Position of Top Status of Stack

-1 Stack is Empty
0 Only one element in
Stack
N-1 Stack is Full
N Overflow state of Stack
Stack

TIME COMPLEXITY

METHO TIME
D COMPLEXITY
push() O(1)
pop() O(1)
top() O(1)
search() O(n)
Stack implementation in C
#include<stdio.h> else {
#include<stdlib.h> a[++top] = x;
#define MAX 1000 printf("%d pushed into stack",x);
return true;
bool isEmpty(); }
bool push(int); }
int pop();
int peek(); int pop()
void display(); {
if (top < 0) {
int a[MAX]; // Maximum size of Stack printf("Stack Underflow");
int top = -1; return 0;
}
bool isEmpty() else {
{ int x = a[top--];
return (top < 0); return x;
} }
}
bool push(int x)
{
if (top >= (MAX - 1)) {
printf("Stack Overflow \n");
return false;
}
Stack implementation in C (contd)
int peek() int main()
{ {
if (top < 0) { int ch,key;
printf("Stack Underflow"); do
return 0; {
} printf("Enter the option to perform\n");
else { printf("1. Push\t2. Pop\t3. Peek\t4. Display\t5. Exit \n");
int x = a[top]; scanf("%d",&ch);
return x; switch(ch)
} {
} case 1:
scanf("%d",&key);
void display() push(key);
{ break;
int i = top; case 2:
if (i < 0) { printf("%d is popped from stack", pop());
printf("Stack is empty \n"); break;
} case 3:
else { printf("%d is the top element in stack", peek());
while(i>=0) break;
printf("%d\n",a[i--]); case 4:
} display();
} break;
case 5:
break;
default:
printf("Invalid option...\n");
break;
}
}while(ch < 5);
}
Stack implementation in Java
import java.util.Scanner; int pop()
class Stack { {
static final int MAX = 1000; if (top < 0) {
int top; System.out.println("Stack Underflow");
int a[] = new int[MAX]; // Maximum size of Stack return 0;
}
boolean isEmpty() else {
{ int x = a[top--];
return (top < 0); return x;
} }
Stack() }
{ int peek()
top = -1; {
} if (top < 0) {
System.out.println("Stack Underflow");
boolean push(int x) return 0;
{ }
if (top >= (MAX - 1)) { else {
System.out.println("Stack Overflow"); int x = a[top];
return false; return x;
} }
else { }
a[++top] = x;
System.out.println(x + " pushed into stack");
return true;
}
}
Stack implementation in Java (contd)
void display() Exit \n");
{ ch = sc.nextInt();
int i = top; switch(ch)
System.out.println("Top is "+i); {
if (i < 0) { case 1:
System.out.println("Stack is empty"); int key = sc.nextInt();
} s.push(key);
else { break;
System.out.println("Inside else Top is "+i); case 2:
while(i>=0) System.out.println(s.pop() + " is popped from stack");
System.out.println(a[i--]); break;
} case 3:
} System.out.println(s.peek() + " is the top element in stack");
break;
} case 4:
s.display();
class StackinJava { break;
public static void main(String args[]) case 5:
{ break;
Stack s = new Stack(); default:
Scanner sc = new Scanner(System.in); System.out.println("Invalid option...");
int ch; break;
do }
{ }while(ch < 5);
System.out.println("Enter the option to perform\n"); }
System.out.println("1. Push\t2. Pop\t3. Peek\t4. Display\t5. }
Stack implementation using collections in Java
import java.util.Stack; System.out.println(s.peek() + " is the top element in
import java.util.Scanner; stack");
class StackinCollections{ break;
public static void main(String[] args) case 4:
{ System.out.println("Stack = "+s);
Stack <Integer> s = new Stack<Integer>(); break;
Scanner sc = new Scanner(System.in); case 5:
int ch; break;
do default:
{ System.out.println("Invalid option...");
System.out.println("Enter the option to perform\n"); break;
System.out.println("1. Push\t2. Pop\t3. Peek\t4. }
Display\t5. Exit \n"); }while(ch < 5);
ch = sc.nextInt(); }
switch(ch) }
{
case 1:
int key = sc.nextInt();
s.push(key);
break;
case 2:
System.out.println(s.pop() + " is popped from stack");
break;
case 3:
Stack applications

• Function call and return process


• Expression handling
o Expression conversion
o Expression evaluation
• Backtracking procedure
• Syntax processing
• Recursion
• Parenthesis checking
• Memory management (local variables)
Infix, Prefix, Postfix Expression

• One of a key application of stack is in expression processing


• An expression can be represented in 3 different types of notations
o Infix e.g (A*B)+C
o Postfix e.g AB*C+
o Prefix e.g +C*AB
• Stacks are used in converting these expression from one form to
another form and evaluation of those expressions.
1. Infix Notation (X + Y):
• A string in infix form is the general way we write a equation.
• In simpler words it means that, the operator is written between the
two operands.
• The general form of infix is: (a op b), where a and b are variables
and op is any operator.
2. Prefix Notation (+ XY):
• Also known as Polish Notation.
• A string in prefix notation is the one where the operator op is written
as prefix to the operands.
• In simpler words, a prefix notation is the one where the operator is
written before the two operands.
• The general form of prefix notation is:( op ab ).
3. Postfix Notation( XY +):
• Also known as Reverse Polish Notation.
• A string in postfix notation is the one where the operator op is written
as suffix to the operands.
• In simpler words, a postfix notation is the one where the operator is
written after the two operands.
• The general form of prefix notation is: (ab op).
Infix to Prefix Conversion
• In an Infix to Prefix conversion we need to use the stack, and the stack data, and
push, and pop the operators accordingly.
• The steps in the infix to prefix conversion are as follows::
o The first step is to reverse the given infix string , i.e, ‘(‘ is changed to ‘)’ and ‘)’ is converted
to ‘(‘.
o Next we need to obtain the postfix or reverse polish notation of the modified expression.
o The final step is to reverse the Postfix expression. The resultant expression. will be the
solution to infix into postfix conversion.
• Let us understand with help of an example.
• We are given an Infix string : ( U * V ) + ( W / X ). -> UV*WX/+
Example:

We are given an Infix string : ( U * V ) + ( W / X ).


Step 1:
• We will scan the given expression.
• If we look closely the given string can be divided into three parts.
• First part being ( U * V ).
• Second part: +
• Third part: ( W / X ).
Step 2:
• We take the first part of the string.
• We then convert it into prefix .
• The prefix notation of a string is as (op a b).
• The string becomes: ( * U V ).
Step 4:
• Now as per the prefix notation we write the operator before the
operands.
• Hence we interchange the positions of the ‘+’ and ( * U V ).
Step 5:
• In the final step, We combine all the parts.
• Here we get the final output of an infix string converted into a prefix
string.
• The string ( U * V ) + ( W / X ) is converted to + * U V / W X.
Infix to Postfix Conversion algorithm
• Scan the given infix string from left to right.
• Next, an empty stack is initialized.
• If the scanned character is an operand, output it.
• But if the scanned character is an operator either of the following
options is followed
o If the stack is empty, simply push the operator into the stack.
o If the stack is not empty compare the precedence of the scanned operator
with the top of the stack.
Infix to Postfix Conversion algorithm (contd)

• If the top of the stack has a higher precedence than the scanned character
pop the stack; Else push the scanned character to stack.
• Repeat these steps until the stack is not empty and top of the stack has
greater precedence over the character.
• If the scanned character is a ‘(‘ (opening parenthesis), push it into the stack.
• If the scanned character is a ‘)’ (closing parenthesis), pop the stack and
output it until a ‘(‘ is encountered, and discard both the parenthesis.
• Print and pop the stack until completely empty.
Suppose we are given string in the infix notation : X * ( Y – Z ).
Evaluation of postfix expression

Let us suppose we are given a postfix expression as : 6 5 4 – * 6 /.


Evaluation of postfix expression algorithm

• First the elements 6, 5 ,4 are pushed into the stack.


• In the next step the ‘ – ‘ operator is pushed into the stack.
• The subtraction operation is performed on the elements 5 and
4 which gives us 5 – 4 = 1.
• Next, the ‘ * ‘ is pushed into the stack, where we get 6 * 1 = 6.
• Now the element 3 is pushed in the stack.
• Finally the operator ‘ / ‘ is pushed in the stack where we get, 6 / 3 = 2.
• The final answer is 2 .
• This is how an expression in postfix form is evaluated.
Infix to postfix conversion in C
#include<stdio.h>
#include<stdlib.h> /* for exit() */
#include<ctype.h> /* for isdigit(char ) */
#include<string.h>
#define SIZE 100

char stack[SIZE];
int top = -1;

void push(char item)


{
if(top >= SIZE-1)
{
printf("\nStack Overflow.");
}
else
{
top = top+1;
stack[top] = item;
}
}
Infix to postfix conversion in C
char pop()
{
char item ;
if(top <0)
{
printf("stack under flow: invalid infix expression");
getchar();
exit(1);
}
else
{
item = stack[top];
top = top-1;
return(item);
}
}

int is_operator(char symbol)


Infix to postfix conversion in C
int is_operator(char symbol)
{
if(symbol == '^' || symbol == '*' || symbol == '/' || symbol == '+' || symbol =='-')
{
return 1;
}
else
{
return 0;
}
}
Infix to postfix conversion in C

int precedence(char symbol)


{
if(symbol == '^')/* exponent operator, highest precedence*/
return(3);
else if(symbol == '*' || symbol == '/')
return(2);
else if(symbol == '+' || symbol == '-') /* lowest precedence */
return(1);
else
return(0);
}
Infix to postfix conversion in C
void InfixToPostfix(char infix_exp[], char postfix_exp[])
{
int I =0, j=0;
char item;
char x;

push('('); /* push '(' onto stack */


strcat(infix_exp,")"); /* add ')' to infix expression */
item=infix_exp[i]; /* initialize before loop*/

while(item != '\0') /* run loop till end of infix expression */


{
if(item == '(')
{
push(item);
}
Infix to postfix conversion in C
else if( isdigit(item) || isalpha(item))
{
postfix_exp[j] = item; /* add operand symbol to postfix expr */
j++;
}
else if(is_operator(item) == 1) /* means symbol is operator */
{
x=pop();
while(is_operator(x) == 1 && precedence(x)>= precedence(item))
{
postfix_exp[j] = x; /* so pop all higher precendence operator and */
j++;
x = pop(); /* add them to postfix expresion */
}
push(x);
push(item); /* push current oprerator symbol onto stack */
}
Infix to postfix conversion in C
else if(item == ')') /* if current symbol is ')' then */
{
x = pop(); /* pop and keep popping until */
while(x != '(') /* '(' encounterd */
{
postfix_exp[j] = x;
j++;
x = pop();
}
}
else
{ /* if current symbol is neither operand not '(' nor ')' and nor operator */
printf("\n Invalid infix Expression.\n"); /* then it is illegal symbol */
getchar();
exit(1);
}
i++;
Infix to postfix conversion in C
item = infix_exp[i]; /* go to next symbol of infix expression */
} /* while loop ends here */
if(top>0)
{
printf("\n Invalid infix Expression.\n"); /* illegal symbol */
getchar();
exit(1);
}
if(top>0)
{
printf("\n Invalid infix Expression.\n"); /* illegal symbol */
getchar();
exit(1);
}
postfix_exp[j] = '\0'; /* add sentinel else puts() fucntion */
/* will print entire postfix[] array upto SIZE */
}
Queue – Implementation & applications
Queue

• A queue is a linear data structure that follows first in first out principle
which means the first element inserted in the queue will be removed
first from the queue
• Queue can be implemented using an array (static) or a linked list
(dynamic)
• Basic operations performed on queue are
o Enque
o Deque and
o Front
Queue

• Application of queues
o Serving requests on shared resources(CPU, printer etc.)
o Handling of interrupts
o When data is transferred asynchronously between two processes
• Complexity analysis
o Enqueue O(1)
o Dequeu O(1)
Queue implementation using array

• Implementation of queue using array uses below fields


o Queue[CAPACITY] /* Array to hold */
o CAPACITY /* Maximum size of the queue */
o Rear /* To keep track of rear index of the queue, initially it is indexed to last
element of the queue */
o Front /* To keep track of front index of the queue, from where the element
has to be removed */
o Size /* Indicates the current size of the queue */
Queue implementation using array

Enque
• Verify queue overflow by checking if (size >= CAPACITY).
• Increment rear size by 1.
• Note, that the increment should not cross array index bounds.
• Which means if suppose queue capacity is 100 and size is 5and rear is at
99 which means front will be at 95. Now when you enqueue a new
element to queue, rear must get updated to 0 instead of 100. Otherwise
array index will go beyond its bounds.
0 1 2 3 4 5 …. 95 96 97 98 99
Front Rear
Queue implementation using array

Enque

• To do so we use rear = (rear + 1) % CAPACITY;.

• Increment size of the queue by 1.


• Insert new element at the rear of queue i.e. queue[rear] = data;
Queue implementation using array
Deque
• Check queue underflow and throw error if queue is empty, if (size <= 0).
• Copy the element at front to some temporary variable.
data = queue[front];
• Increment front by 1. Similar to enqueue, the increment should not cross
array index bounds.Which means if suppose queue capacity is 100 and
size is 5 and rear is at 9 which means front will be at 99. Now when you
dequeue element from queue, front must get updated to 0 instead of
100. Otherwise array index will go beyond its bounds.
0 1 2 3 4 5 …. 95 96 97 98 99
Rear Front
Queue implementation using array

Deque

• To do so we use front = (front + 1) % CAPACITY;.


• Decrement queue size by 1.
• data is required element dequeued from queue.
Queue implementation using array
int enqueue(int data)
{
// Queue is full throw Queue out of capacity error.
if (isFull())
{
return 0;
}

// Ensure rear never crosses array bounds


rear = (rear + 1) % CAPACITY;

// Increment queue size


size++;

// Enqueue new element to queue


queue[rear] = data;

// Successfully enqueued element to queue


return 1;
}
Queue implementation using array
int dequeue()
{
int data = INT_MIN;

// Queue is empty, throw Queue underflow error


if (isEmpty())
{
return INT_MIN;
}

// Dequeue element from queue


data = queue[front];

// Ensure front never crosses array bounds


front = (front + 1) % CAPACITY;

// Decrease queue size


size--;

return data;
}
Queue using Stacks

• A queue can be implemented using two stacks.


• Let queue to be implemented be q and stacks used to implement q be
stack1 and stack2
• First stack(stack1) is the main stack being used to store the data,
• while the second stack(stack2) is to assist and store data temporarily
during various operations.
Pseudocode for enqueue:
enQueue(q, x)
1) Push the element to stack1 (Assuming Stacks is unlimited)
Pseudocode for dequeue:
deQueue(q)
1) If both stack1 & Stack 2 are empty then queue is empty
2) Else if stack2 is empty
1) Pop the element from stack1
2) Push the element to stack 2
3) Repeat 1and 2 till stack 1 becomes empty
3) Pop stack2
import java.util.Stack; public static void main(String args[]) {
public class QueueUsingStack { QueueUsingStack test = new QueueUsingStack();
private Stack<Integer> stack1 = new Stack<Integer test.enqueue(10);
>(); test.enqueue(50);
private Stack<Integer> stack2 = new Stack<Integer test.dequeue();
>(); test.enqueue(100);
public void enqueue(int element) { test.dequeue();
stack1.push(element); test.dequeue();
System.out.println(element + " inserted"); }
} }
public void dequeue() {
if(stack2.isEmpty()) { Output :
while (!stack1.isEmpty()) { 10 inserted
stack2.push(stack1.pop()); 50 inserted
} 10 removed
} 100 inserted
System.out.println(stack2.pop() + " removed"); 50 removed
} 100 removed
Trees

• A tree is a collection of nodes connected by directed (or undirected)


edges. A tree is a nonlinear data structure, compared to arrays, linked
lists, stacks and queues which are linear data structures.
• A tree can be empty with no nodes or a tree is a structure consisting of
one node called the root and zero or one or more subtrees. A tree has
following general properties:
o One node is distinguished as a root;
o Every node (exclude a root) is connected by a directed edge from exactly one
other node; A direction is: parent -> children
Terminologies
• In a tree data structure, we use the following terminologies
1. Root
In a tree data structure, the first node is called as Root Node. Every tree
must have root node. We can say that root node is the origin of tree data
structure. In any tree, there must be only one root node. We never have
multiple root nodes in a tree.
2. Edge
In a tree data structure, the connecting link between any two nodes is called
as EDGE. In a tree with 'N' number of nodes there will be a maximum of 'N-
1' number of edges.
3. Parent

In a tree data structure, the node which is predecessor of any node is


called as PARENT NODE. In simple words, the node which has branch
from it to any other node is called as parent node. Parent node can also be
defined as "The node which has child / children".
4. Child
In a tree data structure, the node which is descendant of any node is called
as CHILD Node. In simple words, the node which has a link from its parent
node is called as child node. In a tree, any parent node can have any number
of child nodes. In a tree, all the nodes except root are child nodes.
5. Siblings

In a tree data structure, nodes which belong to same Parent are called
as SIBLINGS. In simple words, the nodes with same parent are called as
Sibling nodes.
6. Leaf
In a tree data structure, the node which does not have a child is called as LEAF
Node. In simple words, a leaf is a node with no child.
In a tree data structure, the leaf nodes are also called as External Nodes.
External node is also a node with no child. In a tree, leaf node is also called as
'Terminal' node.
7. Internal Nodes
In a tree data structure, the node which has atleast one child is called
as INTERNAL Node. In simple words, an internal node is a node with atleast
one child.
In a tree data structure, nodes other than leaf nodes are called as Internal
Nodes. The root node is also said to be Internal Node if the tree has more
than one node. Internal nodes are also called as 'Non-Terminal' nodes.
8. Degree
In a tree data structure, the total number of children of a node is called
as DEGREE of that Node. In simple words, the Degree of a node is total
number of children it has. The highest degree of a node among all the
nodes in a tree is called as 'Degree of Tree‘.
9. Level
In a tree data structure, the root node is said to be at Level 0 and the children
of root node are at Level 1 and the children of the nodes which are at Level 1
will be at Level 2 and so on... In simple words, in a tree each step from top to
bottom is called as a Level and the Level count starts with '0' and incremented
by one at each level (Step).
10. Height
In a tree data structure, the total number of egdes from leaf node to a particular
node in the longest path is called as HEIGHT of that Node. In a tree, height of
the root node is said to be height of the tree. In a tree, height of all leaf nodes
is '0'.
11. Depth
In a tree data structure, the total number of edges from root node to a
particular node is called as DEPTH of that Node. In a tree, the total number of
edges from root node to a leaf node in the longest path is said to be Depth of
the tree. In simple words, the highest depth of any leaf node in a tree is said to
be depth of that tree. In a tree, depth of the root node is '0'.
12. Path
In a tree data structure, the sequence of Nodes and Edges from one node to
another node is called as PATH between that two Nodes. Length of a Path is
total number of nodes in that path. In below example the path A - B - E - J has
length 4.
13. Sub Tree
In a tree data structure, each child from a node forms a subtree
recursively. Every child node will form a subtree on its parent
node.
Tree Representations
A tree data structure can be represented in many ways.
List Representation
Left Child - Right Sibling Representation
Consider the following tree...
List Representation
• In this representation, we use two types of nodes one for representing the node with
data and another for representing only references. We start with a node with data
from root node in the tree. Then it is linked to an internal node through a reference
node and is linked to any other node directly. This process repeats for all the nodes in
the tree.
• The above tree example can be represented using List representation as follows...
Left Child - Right Sibling Representation
• In this representation, we use list with one type of node which consists of three
fields namely Data field, Left child reference field and Right sibling reference field.
Data field stores the actual value of a node, left reference field stores the address
of the left child and right reference field stores the address of the right sibling
node. Graphical representation of that node is as follows...

In this representation, every node's data field stores the


actual value of that node. If that node has left child, then left
reference field stores the address of that left child node
otherwise that field stores NULL. If that node has right sibling
then right reference field stores the address of right sibling
node otherwise that field stores NULL.
The above tree example can be represented using Left Child - Right Sibling
representation as follows...
Binary tree
Binary tree is a tree data structure in which each node has at the
most 2 children except leaf nodes.
Binary trees are useful in many computing applications especially
for efficient sorting searching techniques.
Common operations performed in binary trees are
o Insertion
o Deletion
o Traversal
There are many variants of binary trees like balanced trees,
complete trees, self balancing trees etc..
Binary tree
Tree (Creating a node)
import java.util.*;
class Node{
Node left;
Node right;
String data;

Node(String data)
{
this.data = data;
}

Node(String data, Node left, Node right)


{
this.data = data;
this.left = left;
this.right = right;
}
}
Tree (Main method)
class TreeTraversal {
public static void main(String args[])
{
Node root = createTree();
System.out.println("BFS traversal :");
BFS.traversal(root);
System.out.println();
System.out.println("DFS traversal :");
DFS.traversal(root);
}
static Node createTree()
{
Node root = new Node("A",
new Node("B", new Node ("C"), new Node("D")), new Node("E", new Node ("F"), new Node("G",
new Node ("H"),null)));
return root;
}}
Tree (BFS traversal)
class BFS{
static void traversal(Node n)
{
LinkedList<Node> tree = new LinkedList<Node>();
tree.add(n);
while(!tree.isEmpty())
{
n = tree.remove();
System.out.print(n.data+" ");
if(n.left!=null)
tree.add(n.left);
if(n.right!=null)
tree.add(n.right);
}
}
}
Tree (DFS traversal)

class DFS{
static void traversal(Node n)
{
if ( n == null)
return;
System.out.print(n.data + " ");
traversal(n.left);
traversal(n.right);
}
}
Output:
BFS traversal :
ABECDFGH
DFS traversal :
ABCDEFGH
Tree (DFS traversal)
void printPostorder(Node node)
{
if (node == null) void printPreorder(Node node)
{
return;
if (node == null)
return;
printPostorder(node.left); System.out.print(node.key + " ");

printPostorder(node.right);
printPreorder(node.left);
System.out.print(node.key + " ");
printPreorder(node.right);
} }

Output:
void printInorder(Node node)
Preorder traversal of binary tree is
{
12453
if (node == null) Inorder traversal of binary tree is
return; 42513
Postorder traversal of binary tree is
printInorder(node.left);
45231
System.out.print(node.key + " ");
printInorder(node.right);
}
Tree (DFS traversal)

• Pre-order traversal
o Print the data at the root
o Recursively print out all data in the leftmost subtree
o Recursively print out all data in the rightmost subtree
• In-order traversal
o Recursively print out all data in the leftmost subtree
o Print the data at the root
o Recursively print out all data in the rightmost subtree
• Post-order traversal
o Recursively print out all data in the leftmost subtree
o Recursively print out all data in the rightmost subtree
o Print the data at the root
Variants of trees
Binary tree is a tree data structure where a node has at most two
child node
Full binary tree is a tree in which every node has either 0 or 2 child
nodes
Balanced binary tree is a tree in which a node doesn’t have
balancing factor of not more than 1
Binary search tree is a tree which maintains the property of every
child of a given node is placed left if the value of the child node is
lesser than the parent node. A node which has a value greater than a
parent node is placed right of the parent node
Variants of trees
Self balancing tree
A tree which maintains the balancing factor after insertion or
deletion of a new node is called self balancing tree.
AVL tree
A tree which performs a sequence of rotation to maintain balancing
factor is called AVL tree
Binary Search Trees (BST)
• A data structure for efficient searching, inser-tion and deletion
• Binary search tree property
o For every node X
o All the keys in its left
subtree are smaller than
the key value in X
o All the keys in its right
subtree are larger than the
key value in X
Binary Search Trees

A binary search tree Not a binary search tree


Binary Search Trees

The same set of keys may have different BSTs


Searching BST

• If we are searching for 15, then we are done.


• If we are searching for a key < 15, then we should search in the left
subtree.
• If we are searching for a key > 15, then we should search in the
right subtree.
Searching (Find)
• Find X: return a pointer to the node that has key X, or NULL if there is
no such node

find(const double x, BinaryNode* t) const

• Time complexity: O(height of the tree)


Inorder Traversal of BST
• Inorder traversal of BST prints out all the keys in sorted order

Inorder: 2, 3, 4, 6, 7, 9, 13, 15, 17, 18, 20


findMin/ findMax

• Goal: return the node containing the smallest (largest) key


in the tree
• Algorithm: Start at the root and go left (right) as long as
there is a left (right) child. The stopping point is the
smallest (largest) element

BinaryNode* findMin(BinaryNode* t) const

• Time complexity = O(height of the tree)


Insertion

• Proceed down the tree as you would with a find


• If X is found, do nothing (or update something)
• Otherwise, insert X at the last spot on the path traversed

• Time complexity = O(height of the tree)


void insert(double x, BinaryNode*& t)
{
if (t==NULL) t = new BinaryNode(x,NULL,NULL);
else if (x<t->element) insert(x,t->left);
else if (t->element<x) insert(x,t->right);
else ; // do nothing
}
Deletion

• When we delete a node, we need to consider how we take care of the


children of the deleted node.
o This has to be done such that the property of the search tree is maintained.
Deletion under Different Cases

• Case 1: the node is a leaf


o Delete it immediately
• Case 2: the node has one child
o Adjust a pointer from the parent to bypass that node
Deletion Case 3

• Case 3: the node has 2 children


o Replace the key of that node with the minimum element at the right
subtree
o Delete that minimum element
• Has either no child or only right child because if it has a left
child, that left child would be smaller and would have been
chosen. So invoke case 1 or 2.

• Time complexity = O(height of the tree)


void remove(double x, BinaryNode*& t)
{
if (t==NULL) return;
if (x<t->element) remove(x,t->left);
else if (t->element < x) remove (x, t->right);
else if (t->left != NULL && t->right != NULL) // two children
{
t->element = finMin(t->right) ->element;
remove(t->element,t->right);
}
else
{
Binarynode* oldNode = t;
t = (t->left != NULL) ? t->left : t->right;
delete oldNode;
}
}
END OF SESSION 2

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy