Wednesday 23 December 2020

Tree in Data Structure

 
Data Structure and Tree



Tree represents the nodes connected by edges. We will discuss binary tree or binary search tree specifically.

Binary Tree is a special datastructure used for data storage purposes. A binary tree has a special condition that each node can have a maximum of two children. A binary tree has the benefits of both an ordered array and a linked list as search is as quick as in a sorted array and insertion or deletion operation are as fast as in linked list.

Binary Tree

Important Terms

Following are the important terms with respect to tree.

  • Path − Path refers to the sequence of nodes along the edges of a tree.

  • Root − The node at the top of the tree is called root. There is only one root per tree and one path from the root node to any node.

  • Parent − Any node except the root node has one edge upward to a node called parent.

  • Child − The node below a given node connected by its edge downward is called its child node.

  • Leaf − The node which does not have any child node is called the leaf node.

  • Subtree − Subtree represents the descendants of a node.

  • Visiting − Visiting refers to checking the value of a node when control is on the node.

  • Traversing − Traversing means passing through nodes in a specific order.

  • Levels − Level of a node represents the generation of a node. If the root node is at level 0, then its next child node is at level 1, its grandchild is at level 2, and so on.

  • keys − Key represents a value of a node based on which a search operation is to be carried out for a node.

Binary Search Tree Representation

Binary Search tree exhibits a special behavior. A node's left child must have a value less than its parent's value and the node's right child must have a value greater than its parent value.

Binary Search Tree

We're going to implement tree using node object and connecting them through references.

Tree Node

The code to write a tree node would be similar to what is given below. It has a data part and references to its left and right child nodes.

struct node {
   int data;   
   struct node *leftChild;
   struct node *rightChild;
};

In a tree, all nodes share common construct.

BST Basic Operations

The basic operations that can be performed on a binary search tree data structure, are the following −

  • Insert − Inserts an element in a tree/create a tree.

  • Search − Searches an element in a tree.

  • Preorder Traversal − Traverses a tree in a pre-order manner.

  • Inorder Traversal − Traverses a tree in an in-order manner.

  • Postorder Traversal − Traverses a tree in a post-order manner.

We shall learn creating (inserting into) a tree structure and searching a data item in a tree in this chapter. We shall learn about tree traversing methods in the coming chapter.

Insert Operation

The very first insertion creates the tree. Afterwards, whenever an element is to be inserted, first locate its proper location. Start searching from the root node, then if the data is less than the key value, search for the empty location in the left subtree and insert the data. Otherwise, search for the empty location in the right subtree and insert the data.

Algorithm

If root is NULL 
   then create root node
return

If root exists then
   compare the data with node.data
   
   while until insertion position is located

      If data is greater than node.data
         goto right subtree
      else
         goto left subtree

   endwhile 
   
   insert data
	
end If      

Monday 28 September 2020

 

Trees are non-linear data structures that represent nodes connected by edges. Each tree consists of a root node as the Parent node, and the left node and right node as Child nodes.

widget

Linked List and Types of Link. Types of Linked List - Singly linked, doubly linked and circular

Linked List and Types of Link 

A linked list is a sequence of data elements, which are connected together via links. Each data element contains a connection to another data element in form of a pointer. Python does not have linked lists in its standard library. We implement the concept of linked lists using the concept of nodes as discussed in the previous chapter. We have already seen how we create a node class and how to traverse the elements of a node. In this chapter we are going to study the types of linked lists known as singly linked lists. In this type of data structure there is only one link between any two data elements. We create such a list and create additional methods to insert, update and remove elements from the list.

ListTypes of Linked List - Singly linked, doubly linked and circular.

 




In this tutorial, you will learn different types of linked list. Also, you will find implementation of linked list in C.

Before you learn about the type of the linked list, make sure you know about the Linked List Data Structure.

There are three common types of Linked List.

  1. Singly Linked List
  2. Doubly Linked List
  3. Circular Linked List

Singly Linked List

It is the most common. Each node has data and a pointer to the next node.

singly linked list
Singly linked list

Node is represented as:

struct node {
    int data;
    struct node *next;
}

A three-member singly linked list can be created as:

/* Initialize nodes */
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;

/* Allocate memory */
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));

/* Assign data values */
one->data = 1;
two->data = 2;
three->data = 3;

/* Connect nodes */
one->next = two;
two->next = three;
three->next = NULL;

/* Save address of first node in head */
head = one;

Doubly Linked List

We add a pointer to the previous node in a doubly-linked list. Thus, we can go in either direction: forward or backward.

doubly linked list
Doubly linked list

A node is represented as

struct node {
    int data;
    struct node *next;
    struct node *prev;
}

A three-member doubly linked list can be created as

/* Initialize nodes */
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;

/* Allocate memory */
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));

/* Assign data values */
one->data = 1;
two->data = 2;
three->data = 3;

/* Connect nodes */
one->next = two;
one->prev = NULL;

two->next = three;
two->prev = one;

three->next = NULL;
three->prev = two;

/* Save address of first node in head */
head = one;

Circular Linked List

A circular linked list is a variation of a linked list in which the last element is linked to the first element. This forms a circular loop.

circular linked list
Circular linked list

A circular linked list can be either singly linked or doubly linked.

  • for singly linked list, next pointer of last item points to the first item
  • In the doubly linked list, prev pointer of the first item points to the last item as well.

A three-member circular singly linked list can be created as:

/* Initialize nodes */
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;

/* Allocate memory */
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));

/* Assign data values */
one->data = 1;
two->data = 2;
three->data = 3;

/* Connect nodes */
one->next = two;
two->next = three;
three->next = one;

/* Save address of first node in head */
head = one;

Stack introduction


Stack applications in data structure 

Following are some of the important applications of a Stack data structure:


  1. Stacks can be used for expression evaluation.
  2. Stacks can be used to check parenthesis matching in an expression.
  3. Stacks can be used for Conversion from one form of expression to another.
  4. Stacks can be used for Memory Management.
  5. Stack data structures are used in backtracking problems.

 

Expression Evaluation


Stack data structure is used for evaluating the given expression. For example, consider the following expression

5 * ( 6 + 2 ) - 12 / 4


Since parenthesis has the highest precedence among the arithmetic operators, ( 6 +2 ) = 8 will be evaluated first. Now, the expression becomes 

5 * 8 - 12 / 4


* and / have equal precedence and their associativity is from left-to-right. So, start evaluating the expression from left-to-right.

5 * 8 = 40 and 12 / 4 = 3


Now, the expression becomes

40 - 3 


And the value returned after the subtraction operation is 37.

 

Parenthesis Matching


Given an expression, you have to find if the parenthesis is either correctly matched or not. For example, consider the expression ( a + b ) * ( c + d ).

In the above expression, the opening and closing of the parenthesis are given properly and hence it is said to be a correctly matched parenthesis expression. Whereas, the expression, (a + b * [c + d ) is not a valid expression as the parenthesis are incorrectly given. 


 

Expression Conversion

Converting one form of expressions to another is one of the important applications of stacks.


  • Infix to prefix
  • Infix to postfix
  • Prefix to Infix
  • Prefix to Postfix
  • Postfix to Infix
  • Postfix to Infix


stack applications  notations

 

Memory management


The assignment of memory takes place in contiguous memory blocks. We call this stack memory allocation because the assignment takes place in the function call stack. The size of the memory to be allocated is known to the compiler. When a function is called, its variables get memory allocated on the stack. When the function call is completed, the memory for the variables is released. All this happens with the help of some predefined routines in the compiler. The user does not have to worry about memory allocation and release of stack variables.


Consider the following snippet:

int main() 
{ 
   // All these variables get memory 
   // allocated on stack 
   int f; 
   int a[10]; 
   int c = 20; 
   int e[n]; 
} 


The memory to be allocated to these variables is known to the compiler and when the function is called, the allocation is done and when the function terminates, the memory is released.


Backtracking Problems


Consider the N-Queens problem for an example. The solution of this problem is that N queens should be positioned on a chessboard so that none of the queens can attack another queen. In the generalized N-Queens problem, N represents the number of rows and columns of the board and the number of queens which must be placed in safe positions on the board.


The basic strategy we will use to solve this problem is to use backtracking. In this particular case, backtracking means we will perform a safe move for a queen at the time we make the move. Later, however, we find that we are stuck and there is no safe movement for the next Queen, whom we are trying to put on the blackboard, so we have to go back.

This means we return to the queen's previous move, undo this step, and continue to search for a safe place to place this queen.


We will use the stack to remember where we placed queens on the board, and if we need to make a backup, the queen at the top of the stack will be popped, and we will use the position of that queen to resume the search for next safe location.


Hence, stacks can be used for the allocation of memory for most of the backtracking problems.




Stacks and Queues

 

Stacks and Queues

An array is a random access data structure, where each element can be accessed directly and in constant time. A typical illustration of random access is a book - each page of the book can be open independently of others. Random access is critical to many algorithms, for example binary search.

A linked list is a sequential access data structure, where each element can be accesed only in particular order. A typical illustration of sequential access is a roll of paper or tape - all prior material must be unrolled in order to get to data you want.

In this note we consider a subcase of sequential data structures, so-called limited access data sturctures.

Stacks

A stack is a container of objects that are inserted and removed according to the last-in first-out (LIFO) principle. In the pushdown stacks only two operations are allowed: push the item into the stack, and pop the item out of the stack. A stack is a limited access data structure - elements can be added and removed from the stack only at the top. push adds an item to the top of the stack, pop removes the item from the top. A helpful analogy is to think of a stack of books; you can remove only the top book, also you can add a new book on the top.

A stack is a recursive data structure. Here is a structural definition of a Stack:

    a stack is either empty or
    it consistes of a top and the rest which is a stack;
    

Applications

  • The simplest application of a stack is to reverse a word. You push a given word to stack - letter by letter - and then pop letters from the stack.
  • Another application is an "undo" mechanism in text editors; this operation is accomplished by keeping all text changes in a stack.
        Backtracking. This is a process when you need to access the most recent data element in a series of elements. Think of a labyrinth or maze - how do you find a way from an entrance to an exit?

    Once you reach a dead end, you must backtrack. But backtrack to where? to the previous choice point. Therefore, at each choice point you store on a stack all possible choices. Then backtracking simply means popping a next choice from the stack.

  • Language processing:
    • space for parameters and local variables is created internally using a stack.
    • compiler's syntax check for matching braces is implemented by using stack.
    • support for recursion

Implementation

In the standard library of classes, the data type stack is an adapter class, meaning that a stack is built on top of other data structures. The underlying structure for a stack could be an array, a vector, an ArrayList, a linked list, or any other collection. Regardless of the type of the underlying data structure, a Stack must implement the same functionality. This is achieved by providing a unique interface:

public interface StackInterface<AnyType>
{
   public void push(AnyType e);

   public AnyType pop();

   public AnyType peek();

   public boolean isEmpty();
}

The following picture demonstrates the idea of implementation by composition.

Another implementation requirement (in addition to the above interface) is that all stack operations must run in constant time O(1). Constant time means that there is some constant k such that an operation takes k nanoseconds of computational time regardless of the stack size.

Array-based implementation

    In an array-based implementation we maintain the following fields: an array A of a default size (≥ 1), the variable top that refers to the top element in the stack and the capacity that refers to the array size. The variable top changes from -1 to capacity - 1. We say that a stack is empty when top = -1, and the stack is full when top = capacity-1.

In a fixed-size stack abstraction, the capacity stays unchanged, therefore when top reaches capacity, the stack object throws an exception. See ArrayStack.java for a complete implementation of the stack class.

In a dynamic stack abstraction when top reaches capacity, we double up the stack size.

Linked List-based implementation

Linked List-based implementation provides the best (from the efficiency point of view) dynamic stack implementation.

See ListStack.java for a complete implementation of the stack class.

 

 

    

Queues

A queue is a container of objects (a linear collection) that are inserted and removed according to the first-in first-out (FIFO) principle. An excellent example of a queue is a line of students in the food court of the UC. New additions to a line made to the back of the queue, while removal (or serving) happens in the front. In the queue only two operations are allowed enqueue and dequeue. Enqueue means to insert an item into the back of the queue, dequeue means removing the front item. The picture demonstrates the FIFO access.

The difference between stacks and queues is in removing. In a stack we remove the item the most recently added; in a queue, we remove the item the least recently added.

 

 

    

Implementation

In the standard library of classes, the data type queue is an adapter class, meaning that a queue is built on top of other data structures. The underlying structure for a queue could be an array, a Vector, an ArrayList, a LinkedList, or any other collection. Regardless of the type of the underlying data structure, a queue must implement the same functionality. This is achieved by providing a unique interface.

interface QueueInterface‹AnyType>
{
   public boolean isEmpty();

   public AnyType getFront();

   public AnyType dequeue();

   public void enqueue(AnyType e);

   public void clear();
}

Each of the above basic operations must run at constant time O(1). The following picture demonstrates the idea of implementation by composition.

Circular Queue

Given an array A of a default size (≥ 1) with two references back and front, originally set to -1 and 0 respectively. Each time we insert (enqueue) a new item, we increase the back index; when we remove (dequeue) an item - we increase the front index. Here is a picture that illustrates the model after a few steps:

As you see from the picture, the queue logically moves in the array from left to right. After several moves back reaches the end, leaving no space for adding new elements

However, there is a free space before the front index. We shall use that space for enqueueing new items, i.e. the next entry will be stored at index 0, then 1, until front. Such a model is called a wrap around queue or a circular queue

Finally, when back reaches front, the queue is full. There are two choices to handle a full queue:a) throw an exception; b) double the array size.

The circular queue implementation is done by using the modulo operator (denoted %), which is computed by taking the remainder of division (for example, 8%5 is 3). By using the modulo operator, we can view the queue as a circular array, where the "wrapped around" can be simulated as "back % array_size". In addition to the back and front indexes, we maintain another index: cur - for counting the number of elements in a queue. Having this index simplifies a logic of implementation.

See ArrayQueue.java for a complete implementation of a circular queue.

Applications

The simplest two search techniques are known as Depth-First Search(DFS) and Breadth-First Search (BFS). These two searches are described by looking at how the search tree (representing all the possible paths from the start) will be traversed.

Deapth-First Search with a Stack

In depth-first search we go down a path until we get to a dead end; then we backtrack or back up (by popping a stack) to get an alternative path.

  • Create a stack
  • Create a new choice point
  • Push the choice point onto the stack
  • while (not found and stack is not empty)
    • Pop the stack
    • Find all possible choices after the last one tried
    • Push these choices onto the stack
  • Return

Breadth-First Search with a Queue

In breadth-first search we explore all the nearest possibilities by finding all possible successors and enqueue them to a queue.

  • Create a queue
  • Create a new choice point
  • Enqueue the choice point onto the queue
  • while (not found and queue is not empty)
    • Dequeue the queue
    • Find all possible choices after the last one tried
    • Enqueue these choices onto the queue
  • Return

We will see more on search techniques later in the course.

Arithmetic Expression Evaluation

An important application of stacks is in parsing. For example, a compiler must parse arithmetic expressions written using infix notation:

1 + ((2 + 3) * 4 + 5)*6

We break the problem of parsing infix expressions into two stages. First, we convert from infix to a different representation called postfix. Then we parse the postfix expression, which is a somewhat easier problem than directly parsing infix.

Converting from Infix to Postfix. Typically, we deal with expressions in infix notation

2 + 5

where the operators (e.g. +, *) are written between the operands (e.q, 2 and 5). Writing the operators after the operands gives a postfix expression 2 and 5 are called operands, and the '+' is operator. The above arithmetic expression is called infix, since the operator is in between operands. The expression

2 5 +

Writing the operators before the operands gives a prefix expression

+2 5

Suppose you want to compute the cost of your shopping trip. To do so, you add a list of numbers and multiply them by the local sales tax (7.25%):

70 + 150 * 1.0725

Depending on the calculator, the answer would be either 235.95 or 230.875. To avoid this confusion we shall use a postfix notation

70  150 + 1.0725 *

Postfix has the nice property that parentheses are unnecessary.

Now, we describe how to convert from infix to postfix.

  1. Read in the tokens one at a time
  2. If a token is an integer, write it into the output
  3. If a token is an operator, push it to the stack, if the stack is empty. If the stack is not empty, you pop entries with higher or equal priority and only then you push that token to the stack.
  4. If a token is a left parentheses '(', push it to the stack
  5. If a token is a right parentheses ')', you pop entries until you meet '('.
  6. When you finish reading the string, you pop up all tokens which are left there.
  7. Arithmetic precedence is in increasing order: '+', '-', '*', '/';

Example. Suppose we have an infix expression:2+(4+3*2+1)/3. We read the string by characters.

'2' - send to the output.
'+' - push on the stack.
'(' - push on the stack.
'4' - send to the output.
'+' - push on the stack.
'3' - send to the output.
'*' - push on the stack.
'2' - send to the output.

Evaluating a Postfix Expression. We describe how to parse and evaluate a postfix expression.

  1. We read the tokens in one at a time.
  2. If it is an integer, push it on the stack
  3. If it is a binary operator, pop the top two elements from the stack, apply the operator, and push the result back on the stack.

Consider the following postfix expression

5 9 3 + 4 2 * * 7 + *

Here is a chain of operations

Stack Operations              Output
--------------------------------------
push(5);                        5
push(9);                        5 9
push(3);                        5 9 3
push(pop() + pop())             5 12
push(4);                        5 12 4
push(2);                        5 12 4 2
push(pop() * pop())             5 12 8
push(pop() * pop())             5 96
push(7)                         5 96 7
push(pop() + pop())             5 103
push(pop() * pop())             515

Note, that division is not a commutative operation, so 2/3 is not the same as 3/2.

Saturday 26 September 2020

Flowchart In Programming

 

Flowchart In Programming

A flowchart is a diagrammatic representation of an algorithm. A flowchart can be helpful for both writing programs and explaining the program to others.


Symbols Used In Flowchart

SymbolPurposeDescription
Flowline symbol in flowchart of programmingFlow lineIndicates the flow of logic by connecting symbols.
Terminal symbol in flowchart of programmingTerminal(Stop/Start)Represents the start and the end of a flowchart.
Input/Output symbol in flowchart of programmingInput/OutputUsed for input and output operation.
Processing symbol in flowchart of programmingProcessingUsed for arithmetic operations and data-manipulations.
Decision making symbol in flowchart of programmingDecisionUsed for decision making between two or more alternatives.
On-page connector symbol in flowchart of programmingOn-page ConnectorUsed to join different flowline
Off-page connector symbol in flowchart of programmingOff-page ConnectorUsed to connect the flowchart portion on a different page.
Predefined process symbol in flowchart of programmingPredefined Process/FunctionRepresents a group of statements performing one processing task.

Examples of flowcharts in programming

1. Add two numbers entered by the user.

Flowchart to add two numbers in programming
Flowchart to add two numbers

2. Find the largest among three different numbers entered by the user.

Flowchart to find largest among three numbers
Flowchart to find the largest among three numbers.

3. Find all the roots of a quadratic equation ax2+bx+c=0

Flowchart of the roots of a quadratic equation
Flowchart to find roots of a quadratic equation

4. Find the Fibonacci series till term≤1000.

Flowchart of Fibonacci sequence in programming
Flowchart fo display the Fibonacci Series

Note: Though flowcharts can be useful writing and analysis of a program, drawing a flowchart for complex programs can be more complicated than writing the program itself. Hence, creating flowcharts for complex programs is often ignored.