Lecturenotes Module 3 BCS304
Lecturenotes Module 3 BCS304
applications
Data Structures and Application (Visvesvaraya Technological University)
In data representation, each column of a sparse matrix is represented as a circularly linked list
with a header node. A similar representation is used for each row of a sparse matrix.
Each node has a tag field, which is used to distinguish between header nodes and entry nodes.
Header Node:
• Each header node has three fields: down, right, and next as shown in figure (a).
• The down field is used to link into a column list and the right field to link into a row list.
Element node:
• Each element node has five fields in addition in addition to the tag field: row, col, down,
right, value as shown in figure(b).
• The down field is used to link to the next nonzero term in the same column and the right
field to link to the next nonzero term in the same row. Thus, if aij ≠ 0, there is a node
with tag field = entry, value = aij, row = i, and col = j as shown infigure (c).
• We link this node into the circular linked lists for row i and column j. Hence, it is
simultaneously linked into two different lists.
To represent a numRows x numCols matrix with numTerms nonzero terms, then we need max
{numRows, numCols} + numTerms + 1 nodes. While each node may require several words of
memory, the total storage will be less than numRows x numCols when numTerms is sufficiently
small.
There are two different types of nodes in representation, so unions are used to create the appropriate
data structure. The C declarations are as follows:
typedef struct {
matrixPointer down;
matrixPointer right;
tagfield tag;
union {
matrixPointer next;
entryNode entry;
} u;
} matrixNode; matrixPointer hdnode[MAX-SIZE];
2. A pointer field LLINK (FORW) which contains the location of the next node in the list
3. A pointer field RLINK (BACK) which contains the location of the preceding node in the
list
The declarations are: typedef struct node *nodePointer;
typedef struct
{
nodePointer llink;
element data;
nodePointer rlink;
} node;
newnode→rlink = node→rlink;
node→rlink→llink = newnode;
node→rlink = newnode;
}
Program: Insertion into a doubly linked circular list
Deletion from a doubly linked list
Deletion from a doubly linked list is equally easy. The function ddelete deletes the node deleted
from the list pointed to by node.
To accomplish this deletion, we only need to change the link fields of the nodes that precede
(deleted→llink→rlink) and follow (deleted→rlink→llink) the node we want to delete.
void ddelete(nodePointer node, nodePointer deleted)
{/* delete from the doubly linked list */
if (node == deleted)
printf("Deletion of header node not permitted.\n");
else {
deleted→llink→rlink = deleted→rlink;
deleted→rlink→llink = deleted→llink;
free(deleted) ;
}
Algorithms:
Insertion at the Beginning
1. START
2. Create a new node with three variables: prev, data, next.
3. Store the new data in the data variable
4. If the list is empty, make the new node as head.
5. Otherwise, link the address of the existing first node to the next variable of the new node, and assign
null to the prev variable.
6. Point the head to the new node.
7. END
Insertion at the End
1. START
Prepared by [Link] AP, Dept. of AIML
2. If the list is empty, add the node to the list and point the head to it.
3. If the list is not empty, find the last node of the list.
4. Create a link between the last node in the list and the new node.
5. The new node will point to NULL as it is the new last node.
6. END
Employee *createEmployee() {
Employee *newEmployee = (Employee *)malloc(sizeof(Employee));
if (newEmployee == NULL) {
printf("Memory allocation failed.\n");
exit(1);
}
printf("Enter SSN: ");
scanf("%s", newEmployee->ssn);
printf("Enter Name: ");
scanf("%s", newEmployee->name);
printf("Enter Department: ");
scanf("%s", newEmployee->dept);
printf("Enter Designation: ");
scanf("%s", newEmployee->designation);
printf("Enter Salary: ");
scanf("%f", &newEmployee->sal);
printf("Enter Phone Number: ");
scanf("%lld", &newEmployee->phNo);
newEmployee->prev = NULL;
newEmployee->next = NULL;
return newEmployee;
}
// Function to insert an employee at the end of the list
void insertEnd() {
Employee *newEmployee = createEmployee();
if (head == NULL) {
head = newEmployee;
tail = newEmployee;
} else {
newEmployee->prev = tail;
tail->next = newEmployee;
tail = newEmployee;
}
void deleteFront() {
if (head == NULL) {
printf("List is empty, cannot delete.\n");
} else if (head == tail) {
free(head);
head = NULL;
tail = NULL;
printf("Employee deleted from the front.\n");
} else {
Employee *temp = head;
head = head->next;
head->prev = NULL;
free(temp);
printf("Employee deleted from the front.\n");
}
}
// Function to display the status of the linked list and count the number of nodes
void displayAndCount() {
if (head == NULL) {
printf("List is empty.\n");
} else {
Employee *current = head;
int count = 0;
printf("Employee Data:\n");
while (current != NULL) {
printf("SSN: %s, Name: %s, Department: %s, Designation: %s, Salary: %.2f, Phone:
%lld\n",
current->ssn, current->name, current->dept, current->designation, current->sal,
current->phNo);
current = current->next;
count++;
}
printf("Total Employees: %d\n", count);
}
}
int main() {
int choice;
while (1) {
printf("\nMenu:\n");
printf("1. Insert at End\n");
printf("2. Delete from End\n");
printf("3. Insert at Front\n");
printf("4. Delete from Front\n");
printf("5. Display and Count\n");
printf("6. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
insertEnd();
break;
case 2:
deleteEnd();
break;
case 3:
insertFront();
break;
case 4:
deleteFront();
break;
case 5:
displayAndCount();
break;
case 6:
exit(0);
default:
1. A grounded header list is a header list where the last node contains the null pointer.
2. A circular header list is a header list where the last node points back to the headernode.
Below figure contains schematic diagrams of these header lists.
Observe that the list pointer START always points to the header node.
Below algorithm, which uses a pointer variable PTR to traverse a circular header list 1.
Begins with PTR = START→LINK (not PTR = START)
2. Ends when PTR = START (not PTR = NULL).
Algorithm: (Traversing a Circular Header List) Let LIST be a circular header list in memory.
This algorithm traverses LIST, applying an operation PROCESS to each node of LIST.
LIST is a circular header list in memory. This algorithm finds the location LOC of the node where
ITEM first appears in LIST or sets LOC = NULL.
1. Set PTR: = START→LINK
2. Repeat while PTR→INFO [PTR] ≠ ITEM and PTR ≠ START: Set PTR: =PTR→LINK.
[PTR now points to the next node.] [End of loop.]
3. If PTR→INFO = ITEM, then: Set
LOC: = PTR.
Else:
Set LOC: = NULL.
[End of If structure.]
4. Exit.
The two properties of circular header lists:
1. The null pointer is not used, and hence all pointers contain valid addresses.
2. Every (ordinary) node has a predecessor, so the first node may not require a special case.
There are two other variations of linked lists
1. A linked list whose last node points back to the first node instead of containing the null
pointer, called a circular list
2. A linked list which contains both a special header node at the beginning of the list and a
special trailer node at the end of the list
Trees
Introduction
Definition of Tree:
A tree is a finite set of one or more nodes such that
The remaining nodes are partitioned into n ≥ 0 disjoint sets T1, , Tn, where each of these sets
are called the subtrees of the root.
The tree has 13 nodes and has one character as its information. A tree is always drawn with its root at
the top. Here the node A is the root.
Binary Trees
The Abstract Data type
Definition: A binary tree is a finite set of nodes that is either empty or consists of a root and two
disjoint binary trees called the left subtree and the right subtree.
Objects: a finite set of nodes either empty or consisting of a root node, left Binary_Tree, and right
Binary_Tree.
Functions: for all bt,bt1,bt2 ∈ BinTree, item ∈ element
Boolean IsEmpty(bt) ::= if (bt == empty binary tree) return TRUE else return FALSE
return a binary tree whose left subtree is bt1, whose right subtree
BinTree MakeBT(bt1, item,bt2)
::= is bt2, and whose root node contains the data item.
BinTree Lchild(bt) ::= if (IsEmpty(bt)) return error else return the left subtree of bt.
Element Data(bt) ::= if (IsEmpty(bt)) return error else return the data in the root
node of bt.
BinTree Rchild(bt) ::= if (IsEmpty(bt)) return error else return the right subtree of bt
Each node can be partitioned to only two Each node can be partitioned to T1,T2…..Tn
disjoint subtrees disjoint subtrees
Induction Base: The root is the only node on level i = 1. Hence, the maximum number of
nodes on level i = 1 is 2 i-1 = 20 = 1.
Induction Hypothesis: Let i be an arbitrary positive integer greater than 1. Assume that the
maximum number of nodes on level i - 1 is 2i-2.
Induction Step:
The maximum number of nodes on level i - 1 is 2i-2 by the induction hypothesis.
Since each node in a binary tree has a maximum degree of 2, the maximum number of nodes
on level i is two times the maximum number of nodes on level i-1, i.e 2* 2i-2 = 2i-1
Hence Prooved
Lemma 2: [Relation between number of leaf nodes and degree-2 nodes]: For any non empty binary
tree, T, if n0 is the number of leaf nodes and n2 the number of nodes of degree 2, then n0 = n2 + 1.
Proof:
Let n1 be the number of nodes of degree one and n the total number of nodes. Since all
nodes in T are at most of degree two, we have n=n0+n1+n2 --------- (1)
If we count the number of branches in a binary tree, we see that every node except the root has
a branch leading into it.
If B is the number of branches, then n = B + 1 ---------- (2)
All branches stem out from a node of degree one or two. Thus,
B = n1 + 2n2. Hence, we obtain -- (-3)
Sum of the branches that stem out of a node(outdegree) is always equal to the sum of the
branches that stem into a node(indegree). Therefore Substitutuing eq(3) in eq(2) n=B+1
n= n1 + 2n2 +1 (4)
Subtracting Eq. (4) from Eq. (1) and rearranging terms, we get n0
= n2 + 1
Definition
Prepared by [Link] AP, Dept. of AIML
Full Binary Tree: A full binary tree of depth k is a binary tree of depth k having 2k - 1 nodes, k ≥ 0.
Example
The nodes are numbered in a full binary tree starting with the root on level 1, continuing with the
nodes on level 2, and so on. Nodes on any level are numbered from left to right.
Complete binary tree : A binary tree is complete if the number of nodes in each level i except
possibly the last level is 2i-1. The number of nodes in the last level appears as left as possible.
Example: A complete tree T11 with 11 nodes is shown below. This is not a full binary tree.
tree by replacing each empty subtree by new node and the new tree is a 2-tree . The nodes in
the original tree T are internal nodes in the extended tree and the new nodes are the external
nodes in the extended tree.
Strictly Binary Tree is a tree where every non leaf node in a binary tree has non empty left and right
subtrees. A strictly binary tree with n leaves always contain 2n-1 nodes
Example:
b. For any node n in the tree with a right descendant at level d, n must have a left son and every
left descendant of n is either a leaf at level d or has two sons
Example
Example
Leftchild Rightchild
Node Representation
With this node structure it is difficult to determine the parent of a node, If it is necessary to be able to
determine the parent of random nodes, then a fourth field, parent, may be included in the class
Preorder Traversal
• visit a node
• traverse left, and continue.
• When you cannot continue, move right and begin again or move back until you can move
right and resume."
if (ptr)
{
printf("%d",ptr→data);
preorder(ptr→leftChild);
preorder(ptr→rightChild);
}
}
Postorder Traversal
• traverse left, and continue.
• When you cannot continue, move right and traverse right as far as possible
• Visit the node
postorder(ptr→rightChild);
printf("%d",ptr→data);
}
}
Example:
Inorder Traversal: DGBAHEICF
Preorder Traversal: ABDGCEHIF
Postorder Traversal: GDBHIEFCA
Expression Tree: An expression containing operands and binary operators can be represented by a
binary tree.
Representation and traversal of expression tree
A node representing an operator is a non leaf. A node representing an operand is a leaf. The root of
the tree contains the operator that has to be applied to the results of evaluating the left subtree and the
right subtree.
When the binary expression trees are traversed preorder we get the preorder expression. When we
traverse the tree postorder we get the postorder expression . When we traverse it inorder we get the
inorder expression.
For Example : consider the traversals for the tree given above
Result = 3
One way threading: If ptr → rightChild is null, replace ptr → rightChild with a pointer to the
inorder successor of ptr. Ptr->left child remains unchanged.
Note : unless specified we consider threading corresponds to the inorder traversal. To distinguish
the threads from ordinary pointers, threads are always drawn with broken links
Example: Consider the binary tree and the corresponding threaded tree given below
Binary tree
• In Figure two threads have been left dangling: one in the left child of H, the other in the
rightchild of G.
• To avoid loose threads, a header node is assumed for all threaded binary trees.
• The original tree is the left subtree of the header node.
• An empty binary tree is represented by its header node as in figure below
t=True
f= False
The variable root points to the header node of the tree, while root → leftChild points to the start of
the first node of the actual tree.
By using the threads, we can perform an inorder traversal without making use of a stack.
• For any node, ptr, in a threaded binary tree, if ptr → rightThread = TRUE, the inorder
successorof ptr is ptr → rightChild by definition of the threads.
• Otherwise we obtain the inorder successor of ptr by following a path of left-child links
from the right-child of ptr until we reach a node with leftThread = TRUE.
Finding the inorder successor of a node: The function insucc finds the inorder successor
of anynode in a threaded tree without using a stack.
ThreadNode * insucc(ThreadNode *tree)
{
ThreadNode * temp;
temp = tree→rightChild;
if(tree→rightThread==’f’)
while(temp→leftThread==’f’)
temp =temp→leftChild;
return temp;
}