Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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] <= list[1] <= … <= list[n-1] for searchnum. Return its position if found. Otherwise return -1 */ int middle; while (left <= right) { middle = (left + right)/2; switch (COMPARE(list[middle], searchnum)) { case -1: left = middle + 1; break; case 0 : return middle; case 1 : right = middle – 1; } } return -1; } 1.2. Recursive algorithms • • • • Beginning programmer view a function as something that is invoked (called) by another function • It executes its code and then returns control to the calling function. This perspective ignores the fact that functions can call themselves (direct recursion). They may call other functions that invoke the calling function again (indirect recursion). • extremely powerful • frequently allow us to express an otherwise complex process in very clear term We should express a recursive algorithm when the problem itself is defined recursively. 1.3 Data abstraction • • • • Data Type A data type is a collection of objects and a set of operations that act on those objects. • For example, the data type int consists of the objects {0, +1, -1, +2, -2, …, INT_MAX, INT_MIN} and the operations +, -, *, /, and %. The data types of C • The basic data types: char, int, float and double • The group data types: array and struct • The pointer data type • The user-defined types Abstract Data Type An abstract data type(ADT) is a data type that is organized in such a way that the specification of the objects and the operations on the objects is separated from the representation of the objects and the implementation of the operations. • We know what is does, but not necessarily how it will do it. Specification vs. Implementation • An ADT is implementation independent • Operation specification • function name • the types of arguments • the type of the results • The functions of a data type can be classify into several categories: • creator / constructor • transformers • observers / reporters 1.4 Performance analysis • • • Criteria • Is it correct? • Is it readable? • … Performance Analysis (machine independent) • space complexity: storage requirement • time complexity: computing time Performance Measurement (machine dependent) 1.4.1 Space Complexity: • • • S(P)=C+SP(I) Fixed Space Requirements (C) Independent of the characteristics of the inputs and outputs • instruction space • space for simple variables, fixed-size structured variable, constants Variable Space Requirements (SP(I)) depend on the instance characteristic I • number, size, values of inputs and outputs associated with I • recursive stack space, formal parameters, local variables, return address Example : In program 1.9, Sabc(I)=0. Example : In program 1.10, Ssum(I)=Ssum(n)=0. • Program 1.11 is a recursive function for addition. Figure 1.1 shows the number of bytes required for one recursive call. 1.4.2 Time Complexity: • • • • • • • T(P)=C+TP(I) The time, T(P), taken by a program, P, is the sum of its compile time C and its run (or execution) time, TP(I) Fixed time requirements • Compile time (C), independent of instance characteristics Variable time requirements • Run (execution) time TP • TP(n)=caADD(n)+csSUB(n)+clLDA(n)+cstSTA(n) A program step is a syntactically or semantically meaningful program segment whose execution time is independent of the instance characteristics. • Example (Regard as the same unit machine independent) • abc = a + b + b * c + (a + b - c) / (a + b) + 4.0 • abc = a + b + c Methods to compute the step count • Introduce variable count into programs • Tabular method • Determine the total number of steps contributed by each statement step per execution frequency • add up the contribution of all statements Iterative summing of a list of numbers Program 1.12: Program 1.10 with count statements (p.23) float sum(float list[ ], int n) { float tempsum = 0; count++; /* for assignment */ int i; for (i = 0; i < n; i++) { count++; /*for the for loop */ tempsum += list[i]; count++; /* for assignment */ } count++; /* last execution of for */ count++; /* for return */ • return } • Tabular Method Figure 1.2: Step count table for Program 1.10 (p.26) Iterative function to sum a list of numbers steps/execution • • Recursive summing of a list of numbers Program 1.14: Program 1.11 with count statements added (p.24) • float rsum(float list[ ], int n) { count++; /*for if conditional */ if (n) { count++; /* for return and rsum invocation*/ return rsum(list, n-1) + list[n-1]; } count++; return list[0]; } 2n+2 steps tempsum; 1.5 Asymptotic notation • • • • • • • • Complexity of c1n2+c2n and c3n • for sufficiently large of value, c3n is faster than c1n2+c2n • for small values of n, either could be faster • c1=1, c2=2, c3=100 --> c1n2+c2n c3n for n 98 • c1=1, c2=2, c3=1000 --> c1n2+c2n c3n for n 998 • break even point • no matter what the values of c1, c2, and c3, the n beyond which c3n is always faster than c1n2+c2n Definition: [Big “oh’’] • f(n) = O(g(n)) iff there exist positive constants c and n0 such that f(n) cg(n) for all n, n n0. Definition: [Omega] • f(n) = (g(n)) (read as “f of n is omega of g of n”) iff there exist positive constants c and n0 such that f(n) cg(n) for all n, n n0. Definition: [Theta] • f(n) = (g(n)) (read as “f of n is theta of g of n”) iff there exist positive constants c1, c2, and n0 such that c1g(n) f(n) c2g(n) for all n, n n0. Theorem 1.2: • If f(n) = amnm+…+a1n+a0, then f(n) = O(nm). Theorem 1.3: • If f(n) = amnm+…+a1n+a0 and am > 0, then f(n) = (nm). Theorem 1.4: • If f(n) = amnm+…+a1n+a0 and am > 0, then f(n) = (nm). Examples • f(n) = 3n+2 • 3n + 2 <= 4n, for all n >= 2, 3n + 2 = (n) 3n + 2 >= 3n, for all n >= 1, 3n + 2 = (n) 3n <= 3n + 2 <= 4n, for all n >= 2, 3n + 2 = (n) • f(n) = 10n2+4n+2 • 10n2+4n+2 <= 11n2, for all n >= 5, 10n2+4n+2 = (n2) 10n2+4n+2 >= n2, for all n >= 1, 10n2+4n+2 = (n2) n2 <= 10n2+4n+2 <= 11n2, for all n >= 5, 10n2+4n+2 = (n2) • 100n+6=O(n) /* 100n+6101n for n10 */ • 10n2+4n+2=O(n2) /* 10n2+4n+211n2 for n5 */ • 6*2n+n2=O(2n) /* 6*2n+n2 7*2n for n4 */ Example • Figure 1.9 gives the time needed by a 1 billion instructions per second computer to execute a program of complexity f(n) instructions. • Although performance analysis gives us a powerful tool for assessing an algorithm’s space and time complexity, at some point we also must consider how the algorithm executes on our machine. • This consideration moves us from the realm of analysis to that of measurement. • Example 1.22 [Worst case performance of the selection function]: • The tests were conducted on an IBM compatible PC with an 80386 cpu, an 80387 numeric coprocessor, and a turbo accelerator. We use Broland’s Turbo C compiler. 1.6 Introduction to Linear and Non Linear data structures Definition: A data structure can be defined as a way of organizing and storing data in a computer so that it can used efficiently. Data can be organized in different ways. The logical and mathematical model of a particular organization of data is called as a data structure. The choice of a particular data model depends on two considerations. • • It must be rich enough in structure to mirror the actual relationships of the data in the real world. The structure should be simple enough that one can effectively process the data when necessary. In programming, the term structure refers to scheme for organizing related pieces of information. The basic data structures include arrays, structures, stacks, queues, linked lists, trees and graphs etc.. The data structures can be categorized into • linear and • non-linear data structures. Linear data Structures: • • • Stacks Queues Linked Lists-Single Linked List, Double Linked List Non Linear Data Structures: • • Tree Graphs 1.7 Singly Linked Lists-Operations-Insertion, Deletion Linked Lists The linked list is very different type of collection from an array. Using such lists, we can store collections of information limited only by the total amount of memory that the OS will allow us to use. Further more, there is no need to specify our needs in advance. The linked list is very flexible dynamic data structure : items may be added to it or deleted from it at will. A programmer need not worry about how many items a program will have to accommodate in advance. This allows us to write robust programs which require much less maintenance. The linked allocation has the following draw backs: • • No direct access to a particular element. Additional memory required for pointers. Linked list are of 3 types: • • • Singly Linked List Doubly Linked List Circularly Linked List Singly Linked List A singly linked list, or simply a linked list, is a linear collection of data items. The linear order is given by means of POINTERS. These types of lists are often referred to as linear linked list. * Each item in the list is called a node. * Each node of the list has two fields: • Information- contains the item being stored in the list. • Next address- contains the address ti the next item in the list. * The last node in the list contains NULL pointer to indicate that it is the end of the list. Conceptual view of Singly Linked List Data Data Data Ptr Ptr Ptr Operations on Singly linked list: • • • • Creation of a node Insertions Deletions Traversing the list Creation of a node: Struct List { int data; struct List *next; }; Insertions: How do we place elements in the list: Usually, there are 4 cases we are inserted in: • at the beginning • end of the list • before a given element • after a given element 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. Inserting a node in singly linked list 1.inserting a node at the beginning of the list inserting a node at the end of the list inserting a node at position 'p' in the list Deletion of a node from a singly linked list deleting first node in singly linked list deleting last node in the singly linked list deleting node from position 'p' in the list 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 link to NULL cur->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<stdio.h> #include<stdlib.h> 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(c<pos) { prev=next; next=prev->link; 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(c<pos) { cur=next; next=next->link; 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 && i<nodeindx) { tempnode=tempnode->next; 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<stdio.h> #include<conio.h> #include<malloc.h> #include<process.h> 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;j<nodes;j++) { printf("Enter the element\n"); scanf("%d",&n); create(n); } break; case 2: show(); break; case 3: printf("Enter the element\n"); scanf("%d",&n); atbeg(n); break; case 4: exit(0); } } } int create (int number) { struct doubly *q,*temp; temp=(struct doubly*)malloc(sizeof(struct doubly)); temp->number=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<= I =< N By this definition the compiler limits the storage region to storing set of element, and the first location is individual element of array , and this called the Base Address, let’s be as 500. Base Address (501) and like for the all elements and used the index I, by its value are range 1<= I => N according to Base Index (500), by using this relation: Location ( X[I] ) = Base Address + (I-1) When the requirement to bounding the forth element (I=4): Location ( X[4] ) = 500 + (4-1) = 500 +3 = 503 So the address of forth element is 503 because the first element in 500. When the program indicate or dealing with element of array in any instruction like (write (X [I]), read (X [I] ) ), the compiler depend on going relation to bounding the requirement address. 2 Two-Dimensional Arrays The simplest form of the multidimensional array is the two-dimensional array. A twodimensionalarray is, in essence, a list of one-dimensional arrays. To declare a two-dimensionalinteger array of size x,y you would write something as follows: type arrayName [ x ][ y ]; Where type can be any valid C data type and arrayName will be a valid C identifier. A twodimensional array can be think as a table which will have x number of rows and y number of columns. A 2-dimensional array a, which contains three rows and four columns can be shown as below: Thus, every element in array a is identified by an element name of the form a[ i ][ j ], where a is the name of the array, and i and j are the subscripts that uniquely identify each element in a. 1.10.2.1 Representation of two dimensional arrays in memory A two dimensional ‘m x n’ Array A is the collection of m X n elements. Programming languages stores the two dimensional array in one dimensional memory in either of two ways-Row Major Order: First row of the array occupies the first set of memory locations reserved for the array; Second row occupies the next set, and so forth. To determine element address A[i,j]: Location ( A[ i,j ] ) =Base Address + ( N x ( I - 1 ) ) + ( j - 1 ) For example: Given an array [1…5,1…7] of integers. Calculate address of element T[4,6], where BA=900. Sol) I = 4 , J = 6 M= 5 , N= 7 Location (T [4,6]) = BA + (7 x (4-1)) + (6-1) = 900+ (7 x 3) +5 = 900+ 21+5 = 926 Column Major Order: Order elements of first column stored linearly and then comes elements of next column. To determine element address A[i,j]: Location ( A[ i,j ] ) =Base Address + ( M x ( j - 1 ) ) + ( i - 1 ) For example: Given an array [1…6,1…8] of integers. Calculate address element T[5,7], where BA=300 Sol) I = 5 , J = 7 M= 6 , N= 8 Location (T [4,6]) = BA + (6 x (7-1)) + (5-1) = 300+ (6 x 6) +4 = 300+ 36+4 = 340 3 Operations on array a) Traversing: means to visit all the elements of the array in an operation is called traversing. b) Insertion: means to put values into an array c) Deletion / Remove: to delete a value from an array. d) Sorting: Re-arrangement of values in an array in a specific order (Ascending or Descending) is called sorting. e) Searching: Arrays are used to implement mathematical vectors and matrices, as well as other kinds of rectangular tables. Many databases, small and large, consist of (or include) one-dimensional arrays whose elements are records. Arrays are used to implement other data structures, such as heaps, hash tables, deques, queues, stacks, strings, and VLists. One or more large arrays are sometimes used to emulate in-program dynamic memory allocation, particularly memory pool allocation. 1.11 Sparse matrices-array and linked representations. Sparse matrix Matrix with maximum zero entries is termed as sparse matrix. The natural method of representing matrices in memory as 2D arrays may not be suitable foe sparse matrices. One may save space by storing for only non zero entries. Each non-zero element is represented by [ row , column, non-zero value] first row represent the dimension of matrix and last column tells the number of non zero values; second row onwards it is giving the position and value of non zero number. It can be represented as: 1. Lower triangular matrix: It has non-zero entries on or below diagonal. 2. Upper Triangular matrix: It has non-zero entries on or above diagonal. 3. Tri-diagonal matrix: It has non-zero entries on diagonal and at the places immediately above or below diagonal. Two types of Sparse Matrix Representation 1. Array Representation of Sparse Matrix 2. Linked List Representation of Sparse Matrix 1. Array Representation of Sparse Matrix If most of the elements in a matrix have the value 0, then the matrix is called spare matrix. Example For 3 X 3 Sparse Matrix: | 1 0 0| | 0 0 0| | 0 4 0| 3-Tuple Representation Of Sparse Matrix: | 3 3 2| | 0 0 1| | 2 1 4| Elements in the first row represents the number of rows, columns and non-zero values in sparse matrix. First Row - | 3 3 2 | 3 - rows 3 - columns 2 - non- zero values Elements in the other rows gives information about the location and value of non-zero elements. | 0 0 1 | ( Second Row) - represents value 1 at 0th Row, 0th column | 2 1 4 | (Third Row) - represents value 4 at 2nd Row, 1st column Eample:2 0 0 0 15 0000 0900 0040 Here the memory required is 16 elements X 2 bytes = 32 bytes sparse matrix form Code: 443 0 3 15 219 324 Here the memory required is 12elements X 2 bytes = 24 bytes Program #iinclude <stdio.h> #include <stdlib.h> int count; int main() { int *data, *tuple, row, col, tot, i, j, k =0, x = 0, y = 0; printf("Enter the no of rows & columns:"); scanf("%d%d", &row, &col); tot = row * col; data = (int *) malloc(sizeof (int) * tot); for (i = 0; i < tot; i++) { if (y % col == 0 && y != 0) { y = 0; x++; } printf("data[%d][%d]:", x, y); scanf("%d", &data[i]); if (data[i]) count++; y++; } tuple = (int *) malloc(sizeof (int) * (count + 1) * 3); /* store row, column & count in 3-tuple array - in 1st row */ tuple[k++] = row; tuple[k++] = col; tuple[k++] = count; x = y = 0; for (i = 0; i < tot; i++) { if (y % col == 0 && y != 0) { y = 0; x++; } /* store row, column and non-zero val in 3 tuple */ if (data[i] != 0) { tuple[k++] = x; tuple[k++] = y; tuple[k++] = data[i]; } y++; } printf("Given Sparse Matrix has %d non-zero elements\n", count); x = y = 0; /* printing given sparse matrix */ for (i = 0; i < tot; i++) { if (y % col == 0 && y != 0) { y = 0; x++; printf("\n"); } printf("%d ", data[i]); y++; } printf("\n\n"); /* 3-tuple represenation of sparse matrix */ printf("3-Tuple representation of Sparse Matrix:\n"); for (i = 0; i < (count + 1) * 3; i++) { if (i % 3 == 0) printf("\n"); printf("%d ", tuple[i]); } printf("\n\n"); return 0; } Output Enter the no of rows & 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 100 000 040 3-Tuple representation of Sparse Matrix: 332 001 214 2. Linked List Representation Of Sparse Matrix If most of the elements in a matrix have the value 0, then the matrix is called spare matrix. Example For 3 X 3 Sparse Matrix: | 1 0 0| | 0 0 0| | 0 4 0| 3-Tuple Representation Of Sparse Matrix Using Arrays: | 3 3 2| | 0 0 1| | 2 1 4| Elements in the first row represents the number of rows, columns and non-zero values in sparse matrix. First Row - | 3 3 2 | 3 - rows 3 - columns 2 - non- zero values Elements in the other rows gives information about the location and value of non-zero elements. | 0 0 1 | ( Second Row) - represents value 1 at 0th Row, 0th column | 2 1 4 | (Third Row) - represents value 4 at 2nd Row, 1st column 3-Tuple Representation Of Sparse Matrix Using Linked List: AH - Additional Header (sparseHead) AH chead-col 0 chead - col 1 chead - col 2 +---------------+ +----------------+ +----------------+ +----------------+ | | 3 | 3 | -|-> | | 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 <stdio.h> #include <stdlib.h> /* 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