Data Structures through C Syllabus: UNIT- I Basic concepts- Algorithm Specification-Introduction, Recursive algorithms, Data Abstraction Performance analysis- time complexity and space complexity, Asymptotic Notation-Big O, Omega and Theta notations, Introduction to Linear and Non Linear data structures. Singly Linked Lists-Operations-Insertion, Deletion, Concatenating singly linked lists, circularly linked lists- Operations for Circularly linked lists, Doubly Linked Lists- Operations- Insertion, Deletion. Representation of single, two dimensional arrays, sparse matricesarray and linked representations.

1.1 Algorithm Specification • •



An algorithm is a finite set of instructions that accomplishes a particular task. Criteria • Input: Zero or more quantities that are externally supplied • Output: At least one quantity is produced • Definiteness: Clear and unambiguous • Finiteness: Terminate after a finite number of steps • Effectiveness: Instruction is basic enough to be carried out A program does not have to satisfy the finiteness criteria.



Example 1.1 [Selection sort]: • From those integers that are currently unsorted, find the smallest and place it next in the sorted list. i [0] [1] [2] [3] [4] 30 10 50 40 20 0 10 30 50 40 20 1 10 20 40 50 30 2 10 20 30 40 50 3 10 20 30 40 50



Example 1.2 [Binary search]: [0] [1] [2] [3] 8 14 26 30 left 0 4 4 0 0

right 6 6 4 6 2

middle 3 5 4 3 1

[4] 43

[5] 50

list[middle] : searchnum 30 < 43 50 > 43 43 == 43 30 > 18 14 < 18

[6] 52

2 2 2 26 > 18 2 1 • Searching a sorted list while (there are more integers to check) { middle = (left + right) / 2; if (searchnum < list[middle]) right = middle - 1; else if (searchnum == list[middle]) return middle; else left = middle + 1; }

int binsearch(int list[], int searchnum, int left, int right) { /* search list[0] 0, then f(n) = (nm).

Examples • f(n) = 3n+2 • 3n + 2 = 2, 3n + 2 = (n) 3n + 2 >= 3n, for all n >= 1, 3n + 2 = (n) 3n = n2, for all n >= 1, 10n2+4n+2 = (n2) n2 link=NULL Step 5: Assign new node to first & last node first=cur last=cur Step 6: If the list is not empty call insert function insert () Step 7 : Stop 2. Algorithm for Inserting a new node: Step 1 : Initialize count c to 1 Step 2 : Create inserting node cur=(struct node*)malloc(sizeof (struct node)); Step 3: Read the content of node Step 4: Read the position of insertion Step 5: Inserting in first position Check if the pos=1 and first!=NULL cur->link=first; first=cur; Step 6: Inserting in a given position next=first; repeat the steps a to c until c < pos • prev=next; • next=prev->link; • c++; cur->link=prev->link; prev->link=cur; Step 7 : Stop In the algorithm, first, the memory for a new node is available or not is checked out. Here avail is a pointer to the available memory. If it is NULL then there is no memory. Otherwise a new node is created from available memory and it is stored in new. The new contains the address of the new node and avail moves forward to point to next available memory location. In the info field of new, x is stored and the link field of new points to the first element address of the list. Now, new becomes the pointer to the whole list. This can be shown as:

(a)

(b) First is having value of 100, means it is Pointing the 100 th memory location. The node at 100th location is having info as 10 and containing the address 200 of the next node. The second node at 200th location, contains 20 and address 300 of the next node. At,300th memory location, the node contains info as 30 and its link field is NULL. That means it is no more having any nodes. That is, the list is having 3 nodes with a starting address of 100. Now, we created another node new that is having the address of 50 and its info is 40 and its link field is NULL. After the call to insertbeg( ) function the list will look like.

The insertbeg( ) function, inserts a node by storing the address of the first node of list in the link field of new and making the new address as the pointer to the list. The algorithm for inserting an element at the end of the list: Procedure insertend(x, first) begin if avail = null then /* Checking for memory availability */ write (‘ Availability Stack underflow’); return(first); else /* Obtaining the next free node */ new ¬ avail; /* Removing free node from available memory */ avail ¬ link(avail) info(new) ¬ x /* Initializing the fields of new node */ link(new) ¬ NULL if first = NULL then /* Is the list empty? */ return(new); Save ¬ first /* Searching the last node */ Repeat while link (Save) ¹ NULL Save ¬ link(Save) /* Setting the link field of last node to new */ Link (Save) ¬ new return (first) end;

The Pictorial Representation:

(a)

(b)

(c)

(d) first (100) address is stored in Save to go through the end of the list, after reaching to the last node, set the address of new node in the link field of last node. Inserting in the middle: In this process, the address of first is stored in Save to go to the particular node at which the insertion is to be done. After reaching the particular node, set the link to point to new node, and set the link of new node to connect the remaining nodes. ALGORITHM: The algorithm for inserting an element in the middle of a list: Procedure insertmid(x, first) begin if avail = NULL then write (‘ Availability Stack Underflow’); return (first) else /* Obtain the address of next free node */ new ¬ avail avail ¬ link(avail) /* Removing free node */ info(new) ¬ x /* Copying Information into new node */ if first = NULL then /* Checking whether the list is empty */ link(new) ¬ NULL /* list is empty*/ return(new) /* if the new data precedes all other in the list */

if info(new) £ info(first) then link(new) ¬ first return(new) /* initialise temporary Pointer */ Save ¬ first Repeat while link(Save) ¹ NULL and Info(link(Save)) £ info(new) Save ¬ link(Save) /* Search for predecessor of new data */ link(new) ¬ link(Save) /* Setting the links of new and its Predecessor*/ link(Save) ¬ new return(first) end

(a)

(b)

(c)

(d)

(e)

Deleting a node in a single linked list: Deletion can be done in 3 ways: 1. Deleting an element in the beginning of the list. 2. Deleting in the middle and 3. Deleting at the end. The algorithms for deleting an element in the list: Procedure: If the linked list is empty then write underflow and return Repeat Step 3 while the end of the list has not been reached and the node has not been found. Obtain the next node in the list and record its predecessor node. If the end of the list has been reached then write node not found and return. delete the node from the list. Return the node to the availability area.

Algorithm for Deleting a node: Step 1 : Initialize count c to 1 Step 2 : Read the position for deletion Step 3 : Check if first=NULL print list is empty Step 4 : If the list contains single element Check if pos=1 and first->link=NULL print deleted element is first->data Step 5 : Assign first to NULL first=NULL; Step 6 : If the list contains more than one element and to delete first element if pos=1 and first->link!=NULL cur=first; first=first->link; cur->link=NULL; print deleted element is cur->data free(cur) Step 7 : If the list contains more than one element and to delete an element at given position next=first; repeat the steps a to c until c < pos a. cur=next; b. next=next->link; c. c++; cur->link=next->link; next->link=NULL; print deleted element is next->data free(next); Step 8 : Stop

In the algorithm, it first checks whether the list is empty, if it is empty it prints underflow message. Otherwise, it initializes a temporary pointer to first. Until the Predecessor of x node found, the temporary pointer is moved forward. If it reaches the end of the list, without finding the node of address x, it flashes an error message, stating ‘node not found’. If x is the first address, then first node is deleted and now first points to second node. Otherwise it sets the links so that it deletes the node of address x. The original list is:

1. If x = 100 (First node)

(a)

(b) The node which is 100th memory address will be added to free space (ii)

if x = 200

(a)

(b)

(c) (iii)

if x = 300 (Last node)

(a)

(b) Traversing the List: This includes, visiting the node and printing the data of that node one at a time and moving forward until it reaches end of the list. (i.e., link becomes NULL) Algorithm for Displaying a node: Step1 : Check if first node is NULL print list is empty Step2: If first node is not NULL then cur=first; repeat the steps a to b until cur!=NULL a . print cur->data b . cur=cur->link; Step3 : Stop Applications Linked Lists: The main Applications of Linked Lists are It means in addition/subtraction /multipication.. of two polynimials. Eg:p1=2x^2+3x+7 and p2=3x^3+5x+2 p1+p2=3x^3+2x^2+8x+9 * In Dynamic Memory Management In allocation and releasing memory at runtime. *In Symbol Tables in Balancing paranthesis * Representing Sparse Matrix

C program to implement singly linked list #include #include void create(); void insert(); void delete(); void display(); struct node

{ int data; struct node*link; }; struct node *first=NULL,*last=NULL,*next,*prev,*cur; void create() { if(first==NULL) { cur=(struct node*)malloc(sizeof (struct node)); printf("\n enter the data:"); scanf("%d",&cur->data); cur->link=NULL; first=cur; last=cur; } else insert(); } void insert() { int pos,c=1; cur=(struct node*)malloc(sizeof (struct node)); printf("\n enter data"); scanf("%d",&cur->data); printf("\n enter the position"); scanf("%d",&pos); if( (pos==1) && (first!=NULL)) { cur->link=first; first=cur; } else { next=first; while(clink; c++; } if(prev==NULL) printf("\n invalid position\n"); else { cur->link=prev->link; prev->link=cur; } } } void delete() { int pos,c=1; printf("\n enter position:"); scanf("%d",&pos); if(first==NULL)

printf("\n list is empty \n"); else if(pos==1&&first->link==NULL) { printf("\n deleted element is%d \n ",first->data); free(first); first=NULL; } else if(pos==1&&first->link!=NULL) { cur=first; first=first->link; cur->link=NULL; printf("\n deleted element is%d \n",cur->data); free(cur); } else { next=first; while(clink; c++; } cur->link=next->link; next->link=NULL; printf("\n deleted element is %d \n",next->data); free(next); } } void display() { if(first==NULL) printf("\n list is empty"); else { cur=first; while(cur!=NULL) { printf("%d-->",cur->data); cur=cur->link; } } } void main() { int ch; printf("\n\n singly linked list"); do { printf("\n1.create\n2.delete\n3.display\n4.exit"); printf("\n enter your choice"); scanf("%d",&ch); switch(ch) {

case 1: create(); display(); break; case 2: delete(); display(); break; case 3: display(); break; case 4: exit(0); default:printf("invalid choice"); exit(0); } } while(1); }

1.8 Circularly linked lists- Operations for Circularly linked lists Circularly Linked List A circularly linked list, or simply circular list, is a linked list in which the last node is always points to the first node. This type of list can be build just by replacing the NULL pointer at the end of the list with a pointer which points to the first node. There is no first or last node in the circular list. Advantages: • • •

Any node can be traversed starting from any other node in the list. There is no need of NULL pointer to signal the end of the list and hence, all pointers contain valid addresses. In contrast to singly linked list, deletion operation in circular list is simplified as the search for the previous node of an element to be deleted can be started from that item itself.

The functions to insert and delete elements to/from the circular list can be written as follows: int insert(CLinkedList *clist, int data) { struct Node *node, *tempnode; node = (struct Node*) malloc(sizeof(struct Node)); node->dataw=data; node->next=NULL; if(!clist->Head) { clist->Head=node; node->next=Head; return 1; } tempnode=slist->Head; while(tempnode->next!=Head) tempnode=tempnode->next; tempnode->next=Head;

return 1; } int delete(CLinkedList *clist, int nodeindx) { int i=1; struct Node *tempnode, *prevnode, *nextnode; if(!clist->Head) return 0; tempnode=slist->Head; while(tempnode->next!=Head && inext; i++; } if(i==nodeindx) { free((void *)tempnode); return 1; } return 0; }

1.9 Doubly Linked Lists- Operations- Insertion, Deletion. DOUBLY LINKED LIST A singly linked list has the disadvantage that we can only traverse it in one direction. Many applications require searching backwards and forwards through sections of a list. A useful refinement that can be made to the singly linked list is to create a doubly linked list. The distinction made between the two list types is that while singly linked list have pointers going in one direction, doubly linked list have pointer both to the next and to the previous element in the list.

Lptr Lptr Lptr

Info Info Info

Rptr Rptr Rptr

The main advantage of a doubly linked list is that, they permit traversing or searching of the list in both directions. Operations on Doubly linked list: • • • •

Creation of a node Insertions Deletions Traversing the list

A Doubly Linked List (DLL) contains an extra pointer, typically called previous pointer, together with next pointer and data which are there in singly linked list.

Following is representation of a DLL node in C language. /* Node of a doubly linked list */ struct node { int data; struct node *next; // Pointer to next node in DLL struct node *prev; // Pointer to previous node in DLL }; Following are advantages/disadvantages of doubly linked list over singly linked list. Advantages over singly linked list 1) A DLL can be traversed in both forward and backward direction. 2) The delete operation in DLL is more efficient if pointer to the node to be deleted is given. In singly linked list, to delete a node, pointer to the previous node is needed. To get this previous node, sometimes the list is traversed. In DLL, we can get the previous node using previous pointer. Disadvantages over singly linked list 1) Every node of DLL Require extra space for an previous pointer. It is possible to implement DLL with single pointer though. 2) All operations require an extra pointer previous to be maintained. For example, in insertion, we need to modify previous pointers together with next pointers. For example in following functions for insertions at different positions, we need 1 or 2 extra steps to set previous pointer.

Insertion A node can be added in four ways 1) At the front of the DLL 2) After a given node. 3) At the end of the DLL 4) Before a given node. 1.Insertion at the front of list

2.Insertion in the middle of the list

3.Insertion at the end of the list

Deletion Write a function to delete a given node in a doubly linked list. (a) Original Doubly Linked List

(a) After deletion of head node

(a) After deletion of middle node

(a) After deletion of last node

ALGORITHM : Initialize the first and last nodes with NULL values struct node *first=NULL,*last=NULL,*next,*prev,*cur; 1. Algorithm creating a new node: Step 1: if the list is empty then first==NULL Step 2: Create a new node cur=(struct node*) malloc (sizeof (struct node)); Step 3: Read the content of node Step 4: Assign new node left and right links to NULL cur->left=NULL; cur->right=NULL; Step 5: Assign new node to first & last node first=cur last=cur Step 6: If the list is not empty call insert function insert () Step 7 : Stop 2. Algorithm for Inserting a new node: Step 1 : Initialize count c to 1 Step 2 : Create inserting node cur=(struct node*)malloc(sizeof (struct node)); Step 3: Read the content of node Step 4: Read the position of insertion Step 5: Inserting in first position Check if the pos=1 and first!=NULL cur->right=first; cur->left=NULL; first=cur; Step 6: Inserting in a given position next=first; repeat the steps a to c until c < pos • prev=next; • next=prev->right;

• c++; prev->right=cur; cur->right=next; Step 7 : Stop

3. Algorithm for Deleting a node: Step 1 : Initialize count c to 1 Step 2 : Read the position for deletion Step 3 : Check if first=NULL print list is empty Step 4 : If the list contains single element Check if pos=1 and first->right=NULL print deleted element is first->data Step 5 : Assign first to NULL first=NULL; Step 6 : If the list contains more than one element and to delete first element if pos=1 and first->right!=NULL cur=first; first=first->right; cur->right=NULL; print deleted element is cur->data free(cur); Step 7 : If the list contains more than one element and to delete an element at given position next=first; repeat the steps a to c until c < pos • cur=next; • next=next->right; • c++; cur->right=next->right; next->right=NULL; next->left=NULL; print deleted element is next->data free(next); Step 8 : Stop 4. Algorithm for Displaying a node: Step1 : Check if first node is NULL print list is empty Step2: If first node is not NULL then cur=first; repeat the steps a to b until cur!=NULL a . print cur->data b . cur=cur->right; Step3 : Stop

Creation of a node: Struct DList { int data; struct DList *Lptr;

struct DList *Rptr; }; Insertions: How do we place elements in the list ? Deletions: Removing an element from the list, without destroying the integrity of the list itself. Traversing the list: Assuming we are given the pointer to the head of the list, how do we get the end of the list. C program to implement doubly linked list #include #include #include #include struct doubly { int number; struct doubly *p,*next; }*first; int main() { int create(int); int show(void); void atbeg(int); int option,nodes,n,j; clrscr(); while(1) { clrscr(); printf("\n 1.Create List"); printf("\n 2.Display List"); printf("\n 3.Insert at begining"); printf("\n 4.Exit"); printf("\n Enter Your Choice\n"); scanf("%d",&option); switch(option) { case 1: printf("Enter Number Of Nodes\n"); scanf("%d",&nodes); for(j=0;jnumber=number; temp->next=NULL; if(first==NULL) { temp->p=NULL; first->p=temp; first=temp; } else { q=first; while(q->next!=0) q=q->next; q->next=temp; temp->p=q; } return 0; } int show() { struct doubly *q; if(first==NULL) { printf("List is empty\n"); return 0; } q=first; printf("\n List is..\n"); while(q!=NULL) { printf("%d",q->number); q=q->next; } printf("\n"); getch(); return 0; } void atbeg(int j) { struct doubly *temp; temp=(struct doubly*)malloc(sizeof(struct doubly)); temp->p=NULL; temp->number=j;

temp->next=first; first->p=temp; first=temp; }

1.10 Representation of single & two dimensional arrays C programming language provides a data structure called the array, which can store a fixed-size sequential collection of elements of the same type. An array is used to store a collection of data, but it is often more useful to think of an array as a collection of variables of the same type. Instead of declaring individual variables, such as number0, number1, ..., and number99, you declare one array variable such as numbers and use numbers[0], numbers[1], and ..., numbers[99] to represent individual variables. A specific element in an array is accessed by an index. All arrays consist of contiguous memory locations. The lowest address corresponds to the first element and the highest address to the last element. The array may be categorized into – · One dimensional array · Two dimensional array · Multidimensional array 1 Representation of One-Dimensional Array In Pascal language we can define array as VAR X: array [ 1 … N] of integer {or any other type}. That’s means the structure contains a set of data elements, numbered (N), for example called (X), its defined as type of element, the second type is the index type, is the type of values used to access individual element of the array, the value of index is 1 | | 0 | -|-> | | 1 | -|-> | | 2 |N | +---------------+ +----------------+ +----------------+ +----------------+ | | | v rhead -row 0 v (node) + +----------------+ +------------------+ | | | 0 | -|-> |0row| 0col | 1 | + +----------------+ +------------------+ | | | NULL | NULL| + v rhead - row1 +------------------+ | +----------------+ + | | 1 |N| | +----------------+ + | | v rhead-row2 v (node) +----------------+ +--------------------+ | N | 2 | -|-------------------------->| 2row | 1col | 4 | +----------------+ +--------------------+ | NULL | NULL| +---------------------+

Example2:

Linked List Representation of Sparse Matrix

Program: #iinclude #include /* structure to store data */ struct node { int row, col, val; struct node *right, *down; }; /* structure of column head */ struct chead { int col; struct chead *next; struct node *down; }; /* structure of row head */ struct rhead { int row; struct rhead *next; struct node *right; }; /* structure of additional head */ struct sparsehead { int rowCount, colCount; struct rhead *frow; struct chead *fcol; }; /* main node */ struct sparse { int row, *data; struct node *nodePtr; struct sparsehead *smatrix; struct rhead **rowPtr; struct chead **colPtr; }; int count = 0; /* Establish row and column links */ void initialize(struct sparse *sPtr, int row, int col) { int i; sPtr->rowPtr = (struct rhead **) calloc(1, (sizeof (struct rhead) * row)); sPtr->colPtr = (struct chead **) calloc(1, (sizeof (struct chead) * col)); for (i = 0; i < row; i++) sPtr->rowPtr[i] = (struct rhead *) calloc(1, sizeof (struct rhead)); for (i = 0; i < row - 1; i++) { sPtr->rowPtr[i]->row = i; sPtr->rowPtr[i]->next = sPtr->rowPtr[i + 1]; } for (i = 0; i < col; i++) sPtr->colPtr[i] = (struct chead *) calloc(1, sizeof (struct chead));

for (i = 0; i < col - 1; i++) { sPtr->colPtr[i]->col = i; sPtr->colPtr[i]->next = sPtr->colPtr[i + 1]; } /* update additional head information */ sPtr->smatrix = (struct sparsehead *) calloc(1, sizeof (struct sparsehead)); sPtr->smatrix->rowCount = row; sPtr->smatrix->colCount = col; sPtr->smatrix->frow = sPtr->rowPtr[0]; sPtr->smatrix->fcol = sPtr->colPtr[0]; return; } /* input sparse matrix */ void inputMatrix(struct sparse *sPtr, int row, int col) { int i, n, x = 0, y = 0; n = row * col; sPtr->data = (int *) malloc(sizeof (int) * n); for (i = 0; i < n; i++) { if (y != 0 && y % col == 0) { x++; y = 0; } printf("data[%d][%d] : ", x, y); scanf("%d", &(sPtr->data[i])); if (sPtr->data[i]) count++; y++; } return; } /* display sparse matrix */ void displayInputMatrix(struct sparse s, int row, int col) { int i; for (i = 0; i < row * col; i++) { if (i % col == 0) printf("\n"); printf("%d ", s.data[i]); } printf("\n"); return; } /* create 3-tuple array from input sparse matrix */ void createThreeTuple(struct sparse *sPtr, struct sparse s, int row, int col) { int i, j = 0, x = 0, y = 0, l = 0; sPtr->row = count; sPtr->data = (int *) malloc(sizeof (int) * (sPtr->row * 3)); for (i = 0; i < row * col; i++) { if (y % col == 0 && y != 0) { x++; y = 0;

} if (s.data[i] != 0) { sPtr->data[l++] = x; sPtr->data[l++] = y; sPtr->data[l++] = s.data[i]; } y++; } return; } /* insert element to the list */ void insert(struct sparse *sPtr, int row, int col, int val) { struct rhead *rPtr; struct chead *cPtr; struct node *n1, *n2; struct sparsehead *smat = sPtr->smatrix; int i, j; /* update node values */ sPtr->nodePtr = (struct node *) malloc(sizeof (struct node)); sPtr->nodePtr->row = row; sPtr->nodePtr->col = col; sPtr->nodePtr->val = val; /* get the row headnode */ rPtr = smat->frow; /* move to corresponding row */ for (i = 0; i < row; i++) rPtr = rPtr->next; /* traverse the nodes in current and locate new node */ n1 = rPtr->right; if (!n1) { rPtr->right = sPtr->nodePtr; sPtr->nodePtr->right = NULL; } else { while (n1 && n1->col < col) { n2 = n1; n1 = n1->right; } n2->right = sPtr->nodePtr; sPtr->nodePtr->right = NULL; } /* get the column head node */ cPtr = sPtr->smatrix->fcol; /* move to corresponding column (1/2/3..) */ for (i = 0; i < col; i++) cPtr = cPtr->next; /* * traverse the node in current column and locate * new node in appropriate position

*/ n1 = cPtr->down; if (!n1) { cPtr->down = sPtr->nodePtr; sPtr->nodePtr->down = NULL; } else { while (n1 && n1->row < row) { n2 = n1; n1 = n1->down; } n2->down = sPtr->nodePtr; sPtr->nodePtr->down = NULL; } return; } /* create list for 3-Tuple representation */ void createList(struct sparse *sPtr) { int i, j = 0; for (i = 0; i < sPtr->row; i++) { insert(sPtr, sPtr->data[j], sPtr->data[j + 1], sPtr->data[j + 2]); j = j + 3; } return; } /* Display data from linked list of 3-Tuple*/ void displayList(struct sparse s) { struct node *n; int row = s.smatrix->rowCount, i; for (i = 0; i < row; i++) { n = s.rowPtr[i]->right; if (n) { while (n->right) { printf("%d %d %d\n", n->row, n->col, n->val); n = n->right; } if (n->row == i) { printf("%d %d %d\n", n->row, n->col, n->val); } } } printf("\n"); } int main() { struct sparse input, output; int row, col; printf("Enter the rows and columns:"); scanf("%d%d", &row, &col); initialize(&input, row, col); initialize(&output, row, col); inputMatrix(&input, row, col); printf("Given Sparse Matrix has %d non-zero elements\n", count); printf("Input Sparse Matrix:\n");

displayInputMatrix(input, row, col); printf("\n\n"); createThreeTuple(&output, input, row, col); createList(&output); printf("3-Tuple representation of the given sparse matrix:\n"); printf("%d %d %d\n", output.smatrix[0].rowCount, output.smatrix[0].colCount, count); displayList(output); return 0; } Output: ( Linked List Representation of Sparse Matrix) /$ ./a.out Enter the rows and columns:3 3 data[0][0] : 1 data[0][1] : 0 data[0][2] : 0 data[1][0] : 0 data[1][1] : 0 data[1][2] : 0 data[2][0] : 0 data[2][1] : 4 data[2][2] : 0 Given Sparse Matrix has 2 non-zero elements Input Sparse Matrix: 100 000 040 3-Tuple representation of the given sparse matrix: 3 3 2 0 0 1 2 1 4