0% found this document useful (0 votes)
9 views42 pages

DS (U1)

Uploaded by

special27032001
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)
9 views42 pages

DS (U1)

Uploaded by

special27032001
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/ 42

DATA STRUCTURES II IT

UNIT-I

Basics : Abstract Data Type(ADT) – introduction to data structures – representation -


implementation Stack and list: representing stack – implementation – application – balancing
symbols –conversion of infix to postfix expression – evaluating a postfix expression – recursive
function call – Linked list ADT – implementation using arrays – limitations - linked list using
dynamic variables- linked implementation of stacks – circular list – doubly linked lists
Abstract Data Types (ADTs)
 An Abstract Data Type (ADT) is a set of operations. Abstract data types are
mathematical abstractions; nowhere in an ADT's definition is there any mention of how
the set of operations is implemented. This can be viewed as an extension of modular
design.
 Objects such as lists, sets, and graphs, along with their operations, can be viewed as
abstract data types, just as integers, reals, and booleans are data types. Integers, reals, and
booleans have operations associated with them, and so do abstract data types. For the set
ADT, there are various operations as union, intersection, size, and complement.
Alternately, the two operations union and find, which would define a different ADT on
the set.
 The basic idea is that the implementation of these operations is written once in the
program, and any other part of the program that needs to perform an operation on the
ADT can do so by calling the appropriate function. If for some reason implementation
details need to change, it should be easy to do so by merely changing the routines that
perform the ADT operations. This change, in a perfect world, would be completely
transparent to the rest of the program.

Data structures

Data Structures is a means of storing a collection of data. It is the specification of the


elements of the structure, the relationship between them and the operations that may be
performed upon them.

Classification of data structures

Data structures can be classified based on the organization and the operations defined on
it.
DATA STRUCTURES II IT
UNIT-I

Linear and non-linear structure: Simple data structures can be combined in various ways
to form more complex structure. There are two kinds of complex data structure. They are linear
& non-linear, depending on the complexity of the logical relationship they represent

 Linear data structure : Stacks, queues, linear linked list, arrays

 Non- linear data structure: Tree and graph tables, sets

Data is a set of elementary items. The possible ways in which the data items are logically related

is defined by data structure .

That is , organized collection of data is called a data structure.

The programs have to follow a certain rules to access and process the structure data. And so ,

Data structure = Organised data + Allowed Operation.

These are standard data structures which are often used to form the basis for computer data
structures.
Arrays are the basic building blocks for more complex data structures.
Classifications:
Data structures

Linear Non Linear

Linear Data Structures:

Items are arranged in Linear sequence like an array.

Eg. Arrays ,Linked list ,Stacks ,Queues.


Non Linear data Structures:
Data Items are not in sequence.
Eg. Tree, Graph
DATA STRUCTURES II IT
UNIT-I

Data structures are classified depending on the area of applications. Of them few data structures are
there which are frequently used almost in all applications areas.

Fundamental Data
Structures

Linear Data Non Linear Data


Structures Structures

LINKED TREES GRAPHS TABLES SETS


ARRAYS STACKS QUEUES
LISTS

STACK
 A stack is an ordered collection of data items.

 New data items may be inserted or deleted in a stack.

 But these insertion (PUSH) and deletion (POP) operation can be done only at one end
called the top of the stack.

 Top is a pointer which always point to the top of the stack.


QUEUES:
A queue is an ordered collection of items from which items may be deleted at one end called the
front, and into which items may be inserted at the other end called rear of the queue.
Example:
Front
A B C
Rear
In this example, A is at the front of the queue and C is at the rear. An element has been deleted
from the front of the queue. i.e.,
Front
DATA STRUCTURES II IT
UNIT-I

B C
Rear
and items can be inserted at the rear of the queue. i.e.,
Front
B C D
Rear
The first element inserted into a queue is the first element to be removed. For this reason, a
queue is sometimes called a FIFO list. (First In First Out)
Operations involved in a queue:
1. Create a queue.
2. Check whether a queue is empty.
3. Check whether the queue is full.
4. Add item at the rear queue.
5. Remove item from front of queue.
6. Read the front of queue.
7. Print the entire queue.
 In the single linked list each link has single link to the next node.
 It is otherwise called as linear linked list.
 It contains the head pointer which holds the address of the first node.
 Using head pointer only we can access entire linked list.
 The below diagram shows the single linked

 In single linked list we can traverse in one direction from head to null.
 We cant move in reverse direction i.e. from null to head.
 Link field of last node have the null pointer indicates the end of the list.

Operations In Single Linked List:


 We can insert and delete the node in a single linked list.

Inserting The Node Into A Single Linked List:


DATA STRUCTURES II IT
UNIT-I

Consider the linked list:


TREE: is defined as a finite set of one or more nodes such that
 there is one specially designated node called ROOT and
 the remaining nodes are partitioned into a collection of sub-trees of the root each of
which is also a tree.

Example LEVEL
0
A

B C 1

D E F G 2

H I J 3

NODE: stands for item of information.

The nodes of a tree have a parent-child relationship. The root does not have a parent ; but each
one of the other nodes has a parent node associated to it . A node may or may not have children
is called a leaf node or terminal nodes.

GRAPH

DEFINING GRAPH:

A graphs g consists of a set V of vertices (nodes) and a set E of edges (arcs). We write G=(V,E).
V is a finite and non-empty set of vertices. E is a set of pair of vertices; these pairs are called as
edges . Therefore,
V(G).read as V of G, is a set of vertices and E(G),read as E of G is a set of edges.

An edge e=(v, w) is a pair of vertices v and w, and to be incident with v and w.

A graph can be pictorially represented as follows,

2 3

4
DATA STRUCTURES II IT
UNIT-I

FIG: Graph G
We have numbered the graph as 1,2,3,4. Therefore, V(G)=(1,2,3,4) and
E(G) = {(1,2),(1,3),(1,4),(2,3),(2,4)}.

TABLE
A symbol table is a set of locations containing a record for each identifier with fields for the
attribute of the identifier. A symbol table allows us to find the record fro each identifier
(variable) and to store or retrieve data from that record quickly.

STACKS
A stack is an ordered collection of data items into which new items may be inserted or from
which items may be deleted at one end, called the top of the stack.
Stack can be represented formally as

Top B
A
The restriction on a stack implies that the last element to be inserted into the stack will be the
first to be removed. For this reason, stack is also referred to as Last In First Out (LIFO) lists.
Basic Operation On A Stack: -
The basic operations on a stack are as follows:
1.Create a stack
2.Push an element onto a stack (if not full)
3.Pop an element from a stack (if not empty)
4.initialize a stack
5. Print the entire stack
6. read a stack top (without removing it and if not empty)
Implementation:
Stack can be implemented as one of the following data structures:
 Array
DATA STRUCTURES II IT
UNIT-I

 Linked list
Now let us see about array implementation, linked list implementation may be explained later.

Array Implementation: -
The simplest way to represent a stack is by using one dimensional array. One end of the array is
the fixed bottom of the stack while the top of the stack constantly shifts as items are popped and
pushed. Thus another field is needed to keep track of the current position of the top of the stack.

A stack in C may therefore of the stack as a structure containing two objects:


* An array to hold the elements of the stack and
* an integer to indicate the position of the current stack top within the array.
Example: # define STACKSIZE 100
struct stack
{ int top;
int items [STACKSIZE];
};
Once this has been done, an actual stack s may be declared as
struct stack s;
In this example, STACKSIZE is set to 100 to indicate that the stack can contain 100 elements
from 0... 99 and also that data type of the elements need not be an integer. It may be of float or
any other data type.
The identifier top must always be declared as an integer. If its value of s.top is 4, then we have
five elements on the stack s.item [0], s.item [1], s.item [2], s.item [3], s.item [4]. When the stack
is popped, the value of s.top is changed to 3 to indicate that there are only 4 elements on the
stack and s.item [3] is the top element.

On the other hand, if a new object is pushed onto the stack, the value of s.top must be increased
by 1 i.e., from 4 to 5 and the new object is inserted into the position s.item [5].

OPERATIONS:
DATA STRUCTURES II IT
UNIT-I

Empty Operation:
Empty stack contains no elements can be initialized by -1 i.e., s.top = -1.
Implementation:

int empty (struct stack *ps)


{
if (ps -> top == -1)
return (TRUE);
else
return (FALSE);
}
Once this function exists, the statement implements a test for the empty stack
if (empty (&s))
/* Stack is empty */
else
/* Stack is not empty */
Here, we are passing the address of the structure to the function. So the condition empty (&s)
implies that we are checking the condition s.top == -1.

POP OPERATION:-
POP operation removes an element from the stack. An attempt to pop an element from the stack,
when the array is empty, causes an underflow. Pop operation involves:
1. Check whether the array is empty before attempting to pop another element. If so
halt execution.
2. Decrement the top pointer.
3. Pop the element from the top of the stack.
ALGORITHM:
Variables used:
S  Array to hold elements
TOP Denotes the top element in the stack
DATA STRUCTURES II IT
UNIT-I

Function POP(S,TOP)
1. [Check for underflow on stack]
If TOP = 0
Then Write(‘STACK UNDERFLOW ON POP’)
Take action in response to underflow
Exit
2. [Decrement pointer]
TOP  TOP – 1
3. [Return former top element of stack]
Return(S[TOP + 1])

Implementation
int pop (struct stack *ps)
{
if (empty (ps))
{cout << "Stack underflow";
exit (1);
}
return ps -> items [ps -> top - -]);
}
Here, if the stack is not empty, the top element of the stack is retained as the returned value. This
element is then removed from the stack by the expression ps-> top - -.

For example, consider there are 88 items on the stack. When the pop is called, ps -> top equals
87 i.e., items are numbers from 0. 87. The value of ps -> items [87] is returned and the value
of ps -> top is changed to 86. Here, ps -> items [87] still retains its old value i.e., the array ps ->
items remains unchanged by the call to pop. However, the stack is modified, since it now
contains only 87 elements rather than 88.
If the pop function is called with an empty stack, the function prints the error message stack
underflow and execution halts.

PUSH OPERATION:
Push operation inserts an element onto the stack. Stack is a dynamic structure that is
DATA STRUCTURES II IT
UNIT-I

constantly allowed to grow and shrink and thus changes its size. But now we represented the
stack by means of array. An attempt to push an element onto the stack, when the array is full,
causes an overflow. Push operation involves:
1. Check whether the array is full before attempting to push another element. If so halt
execution.
2. Increment the top pointer.
3. Push the element onto the top of the stack
ALGORITHM:
Variables used:
S  Array to hold elements
N  Total no of elements
TOP  Denotes the top element in the stack
X  The element to be inserted at the top of a stack
Procedure PUSH(S,TOP,X)
1. [Check for stack overflow]
If TOP>N
then Write('STACK OVERFLOW')
Return
2. [Increment TOP]
TOP TOP+1
3. [Insert element]
S[TOP]  X
4. [Finished]
Return
Implementation:
void push (struct stack *ps, int x)
{
if (ps -> top == STACKSIZE-1)
{
cout <<"Stack overflow");
exit (1);
DATA STRUCTURES II IT
UNIT-I

}
else
ps -> item [++ (ps -> top)] =
x; return;
}
Here, ps -> top always points to the top element of the stack. So, if to push operation is
called, the top element position will be incremented, and there value of x will be stored using
ps ->item [++ (ps -> top).

For example, if ps -> top = 87 and push is called, ps -> top will be changed to 88 and the new
element will be stored in ps -> item [88] i.e., as 89 the element in an array.

If maximum size of an array is 88, and when push is called, first ps -> top value will be tested
whether it is equivalent to 87. If it is so, further we cannot push an element into the stack and
therefore, error message will be displayed.

READ STACK TOP


This operation returns the top element of the stack without removing it from the stack.

Implementation
int stacktop (struct stack *ps)
{
if (empty (ps))
{
cout <<"Stack underflow");
exit (1);
}
else
return (ps -> items [ps -> top]);
}
This operation involves:
1. If the stack is empty, print a warning message and halt execution.
2. Read the top element from the stack and return to the calling program.
Difference between pop operation and stack top operation is, here we didn't decrement
DATA STRUCTURES II IT
UNIT-I

ps-> top to point to the next element as the top element. Top element remains the same.
APPLICATIONS OF STACKS:
Two applications of stacks are :
(i) RECURSION
(ii) COMPILATION OF INFIX EXPRESSIONS
(i) RECURSION:-
Recursion is the name given to the technique of defining a set or a process in terms of itself.
The factorial function, whose domain is the natural numbers, can be recursively defined as
FACTORIAL(N) = 1, if N = 0
N * FACTORIAL(N-1), otherwise
Here FACTORIAL(N) is defined in terms of FACTORIAL(N-1), which in turn is defined in
terms of FACTORIAL(N-2), etc., until finally FACTORIAL(0) is reached, whose value is given
as “one”.

A procedure that contains a procedure call to itself, or a procedure call to a second procedure
which eventually causes the first procedure to be called, is known as a recursive procedure.
Conditions to be satisfied by recursive procedure
First, each time a procedure calls itself (either directly or indirectly), it must be “nearer,” in
some sense, to a solution. In the case of the factorial function, each time that the function calls
itself, its argument is decremented by “one,” so the argument of the function is getting smaller.
Second, there must be a decision criterion for stopping the process or computation. In the case
of the factorial function, the value of n must be zero.

The general algorithm model for any recursive procedure contains the following steps:
1. [Prologue] Save the parameter, local variables, and return address.
2. [Body] If the base criterion has been reached, then perform the final computation and go
to step 3; otherwise the partial computation and go to step 1
3. [Epilogue] Restore the most recently saved parameters, local variables, and return
address. Go to this return address.
DATA STRUCTURES II IT
UNIT-I

(ii) EXPRESSIONS: -
Usual algebraic notation is often termed infix notation. Here, the arithmetic operator appears
between the two operands to which it is being applied.

There are two alternate notations for expressing the expression. These are prefix and postfix
expressions.
Example: A + B INFIX
+ A B PREFIX
A B + POSTFIX
The prefixes "pre -", "post -" and "in -" refer to the relative position of the operator with respect
to the two operands. In prefix notation, the operator precedes the two operands, in postfix
notation, the operator follows the two operands and in infix notation, the operator is between the
operands.

To understand the expression, we must first decide the order of evaluation of an expression. In C
language, the operator with highest priority is evaluated first. Each operator is given certain
priority.
Priority of arithmetic operators in C:

* / High
+ - Low
If the expression consists of more than one operator at the same level, then it follows left
associativity rule. I.e., operator at left most will be done first and so evaluated from left to right.
Example:
A+B*C
Here, first B * C will be evaluated and then added with the value of A. In case, if we want to
evaluate A + B first i.e., if we want to override the rules, the expression should be parenthesized.
Such expressions are always evaluated with the innermost parenthesized expression first. i.e.,
(A + B) * C
DATA STRUCTURES II IT
UNIT-I

CONVERSION OF INFIX TO POSTFIX / PREFIX EXPRESSION: -


The following three steps are to be carried out to convert the infix expression to postfix
expression.
1. Completely parenthesize the infix expression to specify the order of all the operations.
2. Move each operator to the space held by its corresponding right parenthesis.
3. Remove all parentheses.
Example:
Consider the following expression. A/B*C+D*E-A*C
1. Completely parenthesizing this expression yields
((((A / B) * C) + (D * E)) - (A * C))
2. Moving each operator to its corresponding right parenthesis, we obtain
((((A / B) * C) + (D * E)) – (A* C))
3. Removing all parentheses, we are left with postfix form
AB/C*DE*+AC*-
In a similar way, the conversion algorithm for infix to prefix specifies that, after completely
parenthesizing the infix expression with order of priority in mind, we move each operator to its
corresponding left parenthesis. Applying the method to A / B * C + D * E - A * C gives us
((((A / B) * C) + (D * E)) – (A* C)) and finally the prefix form: - + * / A B C * D E * A C

The importance of postfix and prefix notations in arithmetic expressions is that these notations
are completely free of parenthesis. Consequently an expression in postfix / prefix is in unique
form.
Consider an example in infix expression:
Z=A*B/C+D
Z = (A * B) / C + D
Z = ((A * B) / C) + D
Even though expressions are written in different forms, the result will be the same. The process
of collapsing such different expressions into one unique form is called parsing the expression,
and frequently used method of parsing relies heavily upon stacks.
DATA STRUCTURES II IT
UNIT-I

In the design of compliers, this passing of an expression into postfix form is crucial because
having a unique form for an expression greatly simplifies its evaluation.
Thus, in handling an argument statement, a complier must:
1. Parse it into postfix form.
2. Apply an evaluation algorithm to the postfix form.
Implementation:
To implement the conversion of infix expression to postfix form, the three step procedure is not
enough. Instead we'll use an algorithm that has its essential data structures:

1.A string INFIX containing the infix expression


2.A stack opstk, which may contain:
- All arithmetic operators
- Parenthesis " (“ and “) "
- Null character " \0 "
3.A string POSTFIX containing the final postfix expression.
The description of the algorithm is as follows:
1.Define a function PRIORITY, which takes an operator, parentheses, or ' \o ' as its
argument and returns an integer as described in the table below.
Character * / + - ( ) \0
Returned
value 2 2 1 1 0 0 0
3. Push ' \o ' out OPSTACK as its first entry
4. Read the next character CH from the INFIX string
5.Test CH and:
- If CH is an operand, append it to the POSTFIX string
- If CH is a left parenthesis, then push CH onto the stack
- If CH is a right parenthesis. then pop entries from stack and append them to
POSTFIX until a left parenthesis is popped. Discard both left and right parentheses.
- If CH is ' \o ', pop all entries that remain on the stack and append them to the
POSTFIX string
DATA STRUCTURES II IT
UNIT-I

- Otherwise, pop from the stack and append to the POSTFIX string , whose STACK
- PRIORITY is greater than or equal to the INFIX - PRIORITY of CH. Then stack
CH.
6. Repeat step (4) and (5) until CH becomes ' \o ‘.
CH OPSTACK POSTFIX COMMENT
1 Push ' \o '
2 A Reach ch
3 A Append CH to Postfix
4 * Read CH
5 * \0 STACK Ch
6 B Read CH
7 AB Append CH to Postfix
8 + Read CH
Pop *, Append * to postfix,
9 AB* Push CH
10 ( Read ch
11 (+ \0 Push ch
12 C Read CH
13 AB * C Append CH to Postfix
14 0 Read CH
15 - (+ \0 push ch
16 D Read CH
17 AB * CD Append CH to Postfix
18 / read CH
19 / - (+ \0 push ch
20 E Read CH
21 AB * CDE Append CH to Postfix
22 ) Read CH
DATA STRUCTURES II IT
UNIT-I

Pop & Append to postfix


23 + \0 AB * CDE /- until (reached
24 \0 Read CH
AB * CDE / - Pop & Append to rest of
25 + \0 stack to ch
FIG: Translation of the infix expression A * B + (C-D/E) using the algorithm in the text.

EVALUATING POSTFIX EXPRESSION:


Once the expression has been parsed into postfix form, another stack can be used to evaluate
postfix expression.

As an example, consider the postfix expression, AB*CDE/-+ \0


Let us suppose that A,B,C,D and E are the symbols used associated with values
Symbol value
A 5
B 3
C 6
D 8
E 2
To evaluate such an expression, we repeatedly read characters from the postfix expression. If the
character read is an operand, push the value associated with it onto the stack. If it is an operator,
pop two values from the stack, apply the operator to them and push the result back on the stack.
The process is illustrated in the following figure.
Read A Read B Read * Read C

3 6
5 5 15
15
Read D Read E Read / Read- Read+ Read \0

2
8 8 4
d by Page 17
6 . D.Mal
6 hy6(AP RGCE
2 17
15 15 15 15
DATA STRUCTURES II IT
UNIT-I

End of postfix expression.


Answer is on top of stack.
FIG: Evaluation of AB*CDE/-+\0.
Implementation:
Data Structures Used:
1. A stack opndstk is used to hold the operands.
2. A string containing the postfix expression.
Description:
1.Make OPNDSTK sd empty
2.Read c
3.Test c and
- if it is an operand,push the value on stack.
- Otherwise,pop top two entries/operands from the stack and apply the operator just
read. Then stack the value.
1. Repeat steps 2 and 3 until ‘\0’ reaches and pop the final value from the stack.
C Opnd1 Opnd2 Value Opndstk
6 6
2 6,2
3 6,2,3
+ 2 3 5 6,5
- 6 5 1 1
3 6 5 1 1,3
8 6 5 1 1,3,8
2 6 5 1 1,3,8,2
/ 8 2 4 1,3,4
+ 3 4 7 1,7
DATA STRUCTURES II IT
UNIT-I

* 1 7 7 7
\0 –pop_stack and return the value
FIG: Evaluating the POSTFIX expression: 623+-382/+*
Since input values are read as characters, we have to convert the operand characters to numbers
and the operator characters to operation.
For example, we have to find a method for converting the character ‘5’ to the number 5 and the
character ‘+’ to the addition operation. To convert a single digit character x in c ,the expression
x-’0’ yields the numerical value of that digit.

And then we have to write the function that accepts the character representation of an operator
and two operands as input parameters and returns the value of the expression obtained by
applying the operator to the operands.
LINKED LISTS:
DRAWBACKS OF ARRAY IMPLEMENTATIONS OF A LIST:
1. Memory storage space is wasted; very often the list is much shorter than the array size
declared.
2. List cannot grow in its size beyond the size of the declared array if required during program
execution.
3. Operations like insertion and deletion at a specified location in a list requires a lot of
movement of data, therefore, leading to inefficient and line consuming algorithms.
LIST LIST

LIST (0) BLUE LIST (0) BLUE


(1) RED (1) RED
(2) YELLOW (2) YELLOW
GREEN
(3) ORANGE (3) ORANGE
WHITE
(4) (4) PINK
(5) (5)
(6) (6)

FIG(1) FIG(2)
DATA STRUCTURES II IT
UNIT-I

If we want to insert data if the data GREEN is to be WHITE


between GREEN and declared ,other data items
ORANGE, the data ORANGE ORANGE,WHITE AND PINK
is to be moved down. are to be moved up one position.

ADVANTAGES:
1. The primary advantage of linked lists over arrays is that linked lists can grow and shrink during
their lifetime (ie) maximum size ned not be known in advance.
2. They provide quick access to any item in the list which increases the efficiency of rearranging
data items.

Pointers are capable of representing a much more complex relationship between elements of a
structure than a linear order. The use of pointers or links to refer to elements of a data structure
implies that elements which are logically adjacent need not be physically adjacent in memory.
This type of allocation is called linked allocation.

Now, let us see how to represent data structures by linked allocation. Under this, a list has been
defined to consist of an ordered set of elements which may vary in number.

SINGLY / LINEAR LINKED LIST:


In a sequential representation , suppose that the items were implicitly ordered, that is, each item
contained within itself the address of the next item, such an implicit ordering gives rise to a data
structure known as a Linear linked list or Singly linked list which is shown in figure:
INFO NEXT INFO NEXT INFO NEXT
HEAD
NULL

node node TAIL node


FIG:linear linked list.
DATA STRUCTURES II IT
UNIT-I

Each node consists of two fieds,


- information field called INFO that holds the actual element on the list and
- a pointer pointing to next element of the list called LINK ,ie. It holds the address of the
next element.
The name of a typical element is denoted by NODE. Pictorially, the node structure is given as
follows:
NODE
INFO LINK

It is assumed that an available area of storage for this node structure consists of a stack of
available nodes,as shown below:

AVAIL

.
.
.
DATA STRUCTURES II IT
UNIT-I

Here, the pointer variable AVAIL contains the address of the top node in the stack. The head
and tail are pointers pointing to first and last element of the list repectively. For an empty list the
head and tail have the value NIL. When the list has one element, the head and tail point to the
same.
OPERATIONS:
INSERTION IN A LIST:
Inserting a new item,say ‘x’ ,into the list has three situations:
1. Insertion at the front of the list
2. Insertion in the middle of the list or in the order
3. Insertion at the end of the list

INSERTION AT FRONT:
Algorithms for placing the new item at the beginning of a linked list:
1. Obtain space for new node
2. Assign data to the item field of new node
3. Set the next field of the new node to point to the start of the list
4. Change the head pointer to point to the new node.

Return(NEW)
Step 1:
FIRST 20 30 40 NULL
NEW

Step 2:
FIRST 20 30 40 NULL
NEW 10
Step 3:

FIRST 10 20 30 40 NULL

Algorithm for inserting the new node x between the two existing nodes, say N1 and N2( or
DATA STRUCTURES II IT
UNIT-I

in order):
1. Set space for new node x
2. Assign value to the item field of x
3. Search for predecessor node n1 of x
4.Set the next field of x to point to link of node n1(node N2)
5.Set the next field of N1 to point to x.
Function INSORD(X, FIRST)
Step 1:
FIRST 20 30 40 NULL
NEW

Step 2:
FIRST 20 30 40 NULL
NEW 25

SAVE

Step 3:

25 FIRST 20 30 40 NULL

SAVE

Step 4:

FIRST 20 25 30 40 NULL

Algorithms for inserting an item at the end of the list:


1.Set space for new node x
2.Assign value to the item field of x
3.Set the next field of x to NULL
DATA STRUCTURES II IT
UNIT-I

4.Set the next field of N2 to point to x


Step 1:
FIRST 20 30 40 NULL
NEW

Step 2:
FIRST 20 30 40 NULL
NEW 50 NULL

SAVE

Step 3:

FIRST 20 30 40
NEW 50 NULL
SAVE
Step 4:

FIRST 20 30 40 50 NULL

Note that no data is physically moved, as we had seen in array implementation. Only the
pointers are readjusted.

DELETING AN ITEM FROM A LIST:


Deleting a node from the list requires only one pointer value to be changed, there we have
situations:
1.Deleting the first item
2.Deleting the last item
3.Deleting between two nodes in the middle of the list.
Algorithms for deleting the first item:
1. If the element x to be deleted is at first store next field of x in some other variable y.
DATA STRUCTURES II IT
UNIT-I

2. Free the space occupied by x


3. Change the head pointer to point to the address in y.
Algorithm for deleting the last item:
1.Set the next field of the node previous to the node x which is to be deleted as NULL
2.Free the space occupied by x

Algorithm for deleting x between two nodes N1 and N2 in the middle of the list:
1. Set the next field of the node N1 previous to x to point to the successor field N2 of the node x.
2.Free the space occupied by x.
LIST
 The general list is of the form a1, a2, a3, . . . , an. The size of this list is n.
 For any list except the null list, ai+l follows (or succeeds) ai (i < n) and that ai-1 precedes
ai (i > 1). The first element of the list is a1, and the last element is an.
 The position of element ai in a list is i.
 Some popular operations are print_list and make_null, which do the obvious things; find,
which returns the position of the first occurrence of a key; insert and delete, which
generally insert and delete some key from some position in the list; and find_kth, which
returns the element in some position (specified as an argument).
 If the list is 34, 12, 52, 16, 12, then find(52) might return 3; insert(x,3) might makes the
list into 34, 12, 52, x, 16, 12 (if we insert after the position given); and delete(3) might
turn that list into 34, 12, x, 16, 12.
Simple Array Implementation of Lists
 Obviously all of these instructions can be implemented just by using an array. Even if the
array is dynamically allocated, an estimate of the maximum size of the list is
required. Usually this requires a high over-estimate, which wastes considerable
space. This could be a serious limitation, especially if there are many lists of unknown
size.
 An array implementation allows print_list and find to be carried out in linear time, which
is as good as can be expected, and the find_kth operation takes constant time. However,
DATA STRUCTURES II IT
UNIT-I

insertion and deletion are expensive. For example, inserting at position 0 (which
amounts to making a new first element) requires first pushing the entire array down
one spot to make room, whereas deleting the first element requires shifting all the
elements in the list up one, so the worst case of these operations is O(n). On average,
half the list needs to be moved for either operation, so linear time is still required. Merely
building a list by n successive inserts would require quadratic time.
 Because the running time for insertions and deletions is so slow and the list size
must be known in advance, simple arrays are generally not used to implement lists.
Comparison of Methods
Which is the best? A pointer-based or array-based implementation of lists. Often the
answer depends on which operations intended to perform, or on which are performed most
frequently. Other times, the decision rests on how long the list is likely to get. The principal
issues to consider are the following.
1. The array implementation requires us to specify the maximum size of a list at compile
time. If a bound cannot be put on the length to which the list will grow, probably choose
a pointer-based implementation.
2. Certain operations take longer in one implementation than the other. For example,
INSERT and DELETE take a constant number of steps for a linked list, but require time
proportional to the number of following elements when the array implementation is used.
Conversely, executing PREVIOUS and END require constant time with the array
implementation, but time proportional to the length of the list if pointers are used.
3. If a program calls for insertions or deletions that affect the element at the position
denoted by some position variable, and the value of that variable will be used later on,
then the pointer representation cannot be used. As a general principle, pointers should be
used with great care and restraint.
4. The array implementation may waste space, since it uses the maximum, amount of space
independent of the number of elements actually on the list at any time. The pointer
implementation uses only as much space as is needed for the elements currently on the
DATA STRUCTURES II IT
UNIT-I

list, but requires space for the pointer in each cell. Thus, either method could wind up
using more space than the other in differing circumstances.

LINKED LISTS

 In order to avoid the linear cost of insertion and deletion, ensure that the list is not stored
contiguously, since otherwise entire parts of the list will need to be moved. Figure shows
the general idea of a linked list.

A linked list

Linked list with actual pointer values

 The linked list consists of a series of structures, which are not necessarily adjacent in
memory. Each structure contains the element and a pointer to a structure containing its
successor. We call this the next pointer. The last cell's next pointer points to NULL - this
value is defined by C and cannot be confused with another pointer. ANSI C specifies that
as zero.
 A pointer variable is just a variable that contains the address where some other data is
stored. Thus, if p is declared to be a pointer to a structure, then the value stored in p is
interpreted as the location, in main memory, where a structure can be found. A field of
that structure can be accessed by pfield_name, where field_name is the name of the field.
DATA STRUCTURES II IT
UNIT-I

 Figure 2 shows the actual representation of the list in the Figure 1. The list contains five
structures, which happen to reside in memory locations 1000, 800, 712, 992, and 692
respectively. The next pointer in the first structure has the value 800, which provides the
indication of where the second structure is. The other structures each have a pointer that
serves a similar purpose.
 Of course, in order to access this list, it is necessary to know where the first cell can be
found. A pointer variable can be used for this purpose. It is important to remember that a
pointer is just a number.

Deletion from a linked list

Insertion into a linked list

 To execute print_list(L) or find(L,key), pass a pointer to the first element in the list and
then traverse the list by following the next pointers.
 This operation is clearly linear-time, although the constant is likely to be larger than if an
array implementation were used.
 The find_kth operation is no longer quite as efficient as an array implementation;
find_kth(L,i) takes O(i) time and works by traversing down the list in the obvious manner.
 The delete command can be executed in one pointer change. Once an element is deleted,
the pointer of its previous element should be made to point to the next element.
DATA STRUCTURES II IT
UNIT-I

 The insert command requires obtaining a new cell from the system by using an malloc
call (more on this later) and then executing two pointer maneuvers. The dashed line
represents the old pointer.

Problems encountered
 First of all, there is no really obvious way to insert at the front of the list from the
definitions given.
 Second, deleting from the front of the list is a special case, because it changes the start of
the list; careless coding will lose the list.
 A third problem concerns deletion in general. Although the pointer moves above are
simple, the deletion algorithm requires us to keep track of the cell before the one that we
want to delete.

Linked list with a header

 It turns out that one simple change solves all three problems. Keep a sentinel node, which
is sometimes referred to as a header or dummy node.
 To avoid the problems associated with deletions, write a routine find_previous, which
will return the position of the predecessor of the cell that is to be deleted. If a header is
used, then if the first element in the list is to be deleted, find_previous will return the
position of the header.

Structure Definition

typedef struct node *node_ptr;


struct node
{
element_type element;
node_ptr next;
DATA STRUCTURES II IT
UNIT-I

};
typedef node_ptr list;
typedef node_ptr position;

Empty list with header

Function to test whether a linked list is empty


The function is_empty () makes the L->next ( L is the header) to point to null in case the
list is empty.
int is_empty ( )
{
return list_head -> next == null;
}

Function to test whether current position is the last in a linked list


This function accepts a position ‘p’ in the list and checks whether the position is the last
position in the list. It returns TRUE if the p->next =NULL.

int is_last( )
{
return ( list_head -> next == null);
}

Find routine
The find() returns the position of a given element in a list. It compares the value of x with
each and every element in the nodes after the header. In case they do not match, the pointer is
DATA STRUCTURES II IT
UNIT-I

advanced to the next position until P=NULL. In case if there is a match, the position of the
element is returned.
template < class Etype >
int list < E type > :: find ( const Etype & x)
{
node * p;
for ( p= list_head -> next ; p! = Null; p = p-> next)
{
if ( p-> Element == x )
{
current_pos = p;
return 1;
}
return 0;
}

Deletion routine for linked lists


To delete an element from the list, the position of the previous element is obtained by
calling the findprevious() function. The necessary pointer changes are made as shown in the
figure. The element is removed from the list and the memory allocated to the element is freed.
(deallocated)

template < class Etype >


int list <Etype> :: Remove ( cont Etype & x )
{
node * cell_to_delete;
if (find_previous (x) )
cell_to_delete = current_pos -> Next
current_pos -> Next = cell_to_delete -> Next
DATA STRUCTURES II IT
UNIT-I

delete cell_to_delete;
return 1;
}
Return 0;
}

Find_previous - the find routine for use with delete


The find_previous() returns the position of the previous element in a list. It compares the
value of x with each and every element in the nodes after the header. In case they do not match,
the pointer is advanced to the next position until p=NULL. In case if there is a match, the
position of the previous element is returned.
template < class Etype >
int list < Etype > :: Find previous ( const Etype & x )
{
node * p;
for ( p = list_head; p -> Next! = Null; p = p ->Next )
if ( p -> Next -> Element == x)
{
current_pos = p;
return 1;
}
return 0;
}

Insertion routine for linked lists


To insert an element into the list, the position after which the element is to be inserted
should be provided. To insert an element, memory is allocated using malloc. The necessary
pointer changes are made as shown in the figure.
template < class Etype>
DATA STRUCTURES II IT
UNIT-I

int list < Etype > :: Insert ( const Etype & x )


{
Node * p = New node (x, current_pos -> Next )
if ( p == Null )
error (“ out of space “);
else
{
current_pos -> Next = p;
current_pos = current-pos -> next;
}
}

With the exception of the find and find_previous routines, all other operations coded take
O(1) time. This is because in all cases only a fixed number of instructions are performed, no
matter how large the list is. For the find and find_previous routines, the running time is O(n) in
the worst case, because the entire list might need to be traversed if the element is either not found
or is last in the list. On average, the running time is O(n), because on average, half the list must
be traversed.

DOUBLY LINKED LIST

In the singly linked list ,we traverse the list in one dimension .In many application it is
required to traverse a list in both direction .This 2 way traverse a list in both direction .This 2
way traverse can be realised by maintaining 2 link fields in each node instead of one .Each
element of a doubly linked list structure has three fields
-data value
-a link to its successor
-a link to its predecessor
The predecessor link is called left link the successor link is known as right link
DATA STRUCTURES II IT
UNIT-I

Thus the traversal of the list can be in any direction. such a structure is shown in following
figure:

null data next ptr null data next ptr null data next ptr

Head Tail
INSERTION OF A NODE:
To insert a node into a doubly linked list to the right of a specified node ,we have to consider
several case ,these are as follow:
1. If the list is empty,insert a new node and make left and right link of new node to be set
to nil.

2. If there is a predecessor and a successor to the given node .In such a case need to
readjust link of the specified node and its successor node.

 It is convenient to traverse lists backwards. Add an extra field to the data structure,
containing a pointer to the previous cell. The cost of this is an extra link, adds to the
space requirement and also doubles the cost of insertions and deletions because there are
more pointers to fix.
DATA STRUCTURES II IT
UNIT-I

 On the other hand, it simplifies deletion, because you no longer have to refer to a key by
using a pointer to the previous cell; this information is now at hand. Figure shows a
doubly linked list.

Structure Definition
Each node contains three fields. First field is data and there are two pointers next and
previous.
Struct node
{
elementtype element;
ptrtonode *next,*previous;
};
typedef node_ptr list;

Function to check whether the list is empty or not


The function is_empty () makes the header->next to point to null in case if the list is
empty.

int is_empty ( )
{
return list_head -> next == null;
}

Function to check whether the element is in the last position


This function accepts a position P in the list and checks whether the position is the last
position in the list. It returns TRUE if the P->next =NULL.

int is_last( )
{
DATA STRUCTURES II IT
UNIT-I

return ( list_head -> next == null);


}

Find the position of the element


The find() returns the position of a given element in a list. It compares the value of x with each
and every element in the nodes after the header. In case they do not match, the pointer is
advanced to the next position until P=NULL. In case if there is a match, the position of the
element is returned.
Find the position of the previous element
The findprevious() returns the position of the previous element in a list. It compares the
value of x with each and every element in the nodes after the header. In case they do not match,
the pointer is advanced to the next position until P=NULL. In case if there is a match, the
position of the previous element is returned.

template < class Etype >


int list < Etype > :: Find previous ( const Etype & x )
{
node * p;
for ( p = list_head; p -> Next! = Null; p = p ->Next )
if ( p -> Next -> Element == x)
{
current_pos = p;
return 1;
}
return 0;
}
DATA STRUCTURES II IT
UNIT-I

Find the position of the next element


The findnext() returns the position of the next element in a list. It compares the value of x
with each and every element in the nodes after the header. In case they do not match, the pointer
is advanced to the next position until P=NULL. In case if there is a match, the position of the
next element is returned.
position findnext (element type x, list L)
{
position P;
P=L;
while(P->next!=NULL && P->next->element!=x)
{
P=P->next;
}
return P->next;
}

Insert an element
To insert an element into the list, the position after which the element is to be inserted
ahould be provided. To insert an element, memory is allocated using malloc. The necessary
pointer changes are made as shown in the figure.

template < class Etype>


int list < Etype > :: Insert ( const Etype & x )
{
Node * p = New node (x, current_pos -> Next )
if ( p == Null )
error (“ out of space “);
else
{
DATA STRUCTURES II IT
UNIT-I

current_pos -> Next = p;


current_pos = current-pos -> next;
}
}
Delete
To delete an elemnt from the list, the position of the previous element is obtained by
calling the findprevious() function. The necessary pointer changes are made as shown in the
figure. The element is removed from the list and the memory allocated to the element is freed.
(deallocated)
template < class Etype >
int list <Etype> :: Remove ( cont Etype & x )
{
node * cell_to_delete;
if (find_previous (x) )
cell_to_delete = current_pos -> Next
current_pos -> Next = cell_to_delete -> Next
delete cell_to_delete;
return 1;
}
Return 0;
}
DATA STRUCTURES II IT
UNIT-I

CIRCULAR LINKED LIST

 A popular convention is to have the last cell keep a pointer back to the first. This can be
done with or without a header (if the header is present, the last cell points to it), and can
also be done with doubly linked lists (the first cell's previous pointer points to the last
cell).
 The next pointer of the last element points to the header, if the header is present. If not, it
simply points to the first element.
Structure Definition
Each node contains two fields. Every last node points the header.
Function to check whether the list is empty or not
The function is_empty() makes the L->next to point to L in case if the list is empty.
Function to check whether the element is in the last position
This function accepts a position P in the list and checks whether the position is the last
position in the list. It returns TRUE if the P->next =L.
Find the position of the element
The find() returns the position of a given element in a list. It compares the value of x with
each and every element in the nodes after the header. In case they do not match, the pointer is
advanced to the next position until P=L, the header. In case if there is a match, the position of the
element is returned
Find the position of the previous element
The findprevious() returns the position of the previous element in a list. It compares the
value of x with each and every element in the nodes after the header. In case they do not match,
the pointer is advanced to the next position until P=HEADER. In case if there is a match, the
position of the previous element is returned.
Insert
To insert an element into the list, the position after which the element is to be inserted
ahould be provided. To insert an element, memory is allocated using malloc. The necessary
pointer changes are made as shown in the figure.
DATA STRUCTURES II IT
UNIT-I

Delete
To delete an element from the list, the position of the previous element is obtained by
calling the findprevious() function. The necessary pointer changes are made as shown in the
figure.

LINKED STACKS:
The operation of adding an element to the front of a linked list is quite similar to that of pushing
an element onto a stack. A stack can be accessed only through its top element, and a list can be
accessed only from the pointer to its first element. Similar, the operation of removing the first
element from a link list is analogous to popping a stack.

In both cases the only accessible item of collection is removed from that collection, and the
next item becomes immediately accessible. The First node of the list is the top of the stack.

Available free memory spaces can be thought of as a finite pool of empty nodes existing
initially.The most natural form from this pool to take that of a linked together by the next field in
each node.This pool cannot be accessed by the programmer except through the memory
allocation functions and free function.For eg:malloc function remove the first node from the list
where as free return a mode to the front of the list.

The list of available node is called the available list.


The advantage of the list implementation of the stack is that of all stacks being used by a
program can share the same available list.
DATA STRUCTURES II IT
UNIT-I

When any stack needs a node ,it can obtain it from the single variable list.when any stack no
longer needs no node ,it returns the node to that same available list.As long as the total amount of
spaces needed by all stack at any onetime is less then the amount of space initially available to
them all ,each stack is available to grow and shrink to any size . No space has been preallocated
to any single stack and stack is using the space that is does not need .
ALGORITHM :

struct linked_stack
{
int info;
struct linked_stack * next;
}

PUSH :
void push ( int item )
{
stack = ( node *) malloc (size of (node) );
stack -> info = item;
stack -> next = top;
top = stack;
}

POP :
void pop (* node )
{
node * temp;
if ( top == Null )
{
DATA STRUCTURES II IT
UNIT-I

cout << “ stack empty “;


temp = top
free ( top );
top = top -> next;
return ( temp );
}
}

You might also like