Escolar Documentos
Profissional Documentos
Cultura Documentos
Prerequisite: Basic programming knowledge. Algorithm Analysis : Pseudo code, The Abstract Data Type, A Model for an Abstracts Data Type ( Article 1.1-4 of Text 1) Searching : Linear List Searching , Linear Search C Algorithms, Hashed List Searches, Collision Resolution. (Article 2.1 to 2.4 of Text 1) Linear Lists: Linear List Concepts, Linked List, Linked List Algorithms, Processing a Linked List Linear Applications, Complex Linked List Structures, Building a Linked List -c implementation, Linked List Abstract Data Type. Stacks: Basic Stack Operations, Stack-Linked List Implementation, Stack Application, ADTLinked List Implementation, Array Implementation Of Stack, ADT-Array Implication. (Article 4.1 4.7 of Text 1) Queue: Queue Operations, Queue-Linked List Implementation, Queuing Theory, Queue Applications, Categorizing Data-C Implementation, Queue-Linked List Implementation, Queues Array Implementation. (Article 5.1 5.7 of Text 1) Trees: Binary Tree Concepts, Binary Trees, Binary Tree Travels, Expression Trees, General Trees. (Article 7.1 7.5 of Text 1) Search Trees: Binary search Trees, AVL trees: Multiway Trees ; B-Tree Simplified B-Tree, B-Tree variations. (Article 8.1 8.2 to 10.1 10.4 of Text 1) Graphs: Terminology, operations, Graph Storage Structures, Graph Algorithms, Abstract Data Type (Article 12.1 12.4 of Text 1) Sorting : general sort concepts Insertion sorts, selection sorts, exchange sorts. (Article 11.1 11.4 of Text 1)
Data Structures Text Book: Richard F. Gilberg, Behrouz A. forouzan, data Structures : A Pseudo code Approach with C Thomson Asia Pvt.Ltd,2002.
Linear Lists: Linear List Concepts, Linked List, Linked List Algorithms, Processing a Linked List Linear Applications, Complex Linked List Structures, Building a Linked List -c implementation, Linked List Abstract Data Type.
Objectives To be able to allocate and free memory dynamically for data objects To be able to form linked data structures using pointers and self-referential structures To be able to create and manipulate linked lists, queues, stacks, and binary trees To understand various important applications of linked data structures
Introduction We have looked at static data structures: arrays and structs These data structures remain the same size (in memory) during program execution Now will look at dynamic data structures that can grow and shrink during execution Trade-off is that less memory is required, but execution is slower
Dynamic data structures can be implemented as self-referential structures linked lists, queues, stacks and trees This is a hard topic: lots of pointer manipulation
Self-referential Structures o o A self-referential structure is a data organization of nodes A single node contains two member: a data member (of any type: scalar, array or structure) a pointer member that contains the address of the next node For example, consider this definition:
struct node *nextPtr; // ptr to next node }; The node structure contains both a data member and a pointer to the next node structure (hence, self-referential)
o o
nextPrt of first node points to next node nextPtr of last node = NULL The data structure itself consists of one or more nodes, "linked" by pointers
Dynamic Memory Allocation The data structure itself grows or shrinks as nodes are added or removed
The operating system maintains a pool of free (unallocated) memory from which bytes of memory can be provided to an application, or to which an application can return unused memory; this process is called dynamic memory allocation
In C, the function malloc is used to request memory, and free to return it (both are in stdlib.h); its prototype: void *malloc(size_t size) The argument is the number of bytes requested (size_t is implementation dependent, but usually unsigned int); malloc returns a dimensionless "pointer to void" to the requested memory, which should be cast to the correct type before assignment; if no memory is available, NULL is returned Requesting memory from the OS can be accomplished like this:
struct node *newNodePtr; ... newNodePtr = (struct node *)malloc(sizeof(struct node)); Returning memory to the OS:
free(newNodePtr); o o free takes as an argument a pointer to the node to be returned make sure you only free memory that has been allocated with malloc typedef shorthand for self-referential data structures:
o because a program that uses these structures repeatedly declares new instances of the nodes and pointers to them, using a typedef is often useful: typedef struct node NODE; o with this typdefs, new nodes and pointers to them can be declared with: // node // pointer to a node
Always check the return value of malloc!! If it is NULL, the OS was unable to provide the space requested, and you cannot proceed with normal processing You can check the return value directly, like this:
else { /* ok to proceed */ } /* memreq2.c -- 090405 (sjd) Demo malloc Note: Must be run from command line, not from IDE */
int main() { unsigned n = 0; /* number of doubles allocated, in millions */ double *dp; /* pointer to new double */
while (1) {
/* infinite loop */
if (dp == NULL) { printf("\nNo memory left after allocating %d million doubles.\n\n"); system("pause"); exit(EXIT_FAILURE); } n++; } system("pause"); return 0; }
#define NDEBUG
#include <assert.h>
int main() { unsigned n = 0; /* number of doubles allocated */ double *dp; /* pointer to new double */
while (1) {
/* infinite loop */
printf("n = %d\n", n); dp = (double *)malloc(1000000 * sizeof(double)); assert(dp != NULL); n++; } system("pause"); return 0; }
Linked Lists A linked list is a linear collection of nodes, connected by pointer links
Data is stored in a linked list dynamically - each node is allocated as needed Nodes are not (necessarily) contiguous, like elements of an array The stored data can be of any type Separate pointer (usually called headPtr or startPtr) points to first node in the list
List is initially empty; this is indicated by NULL be assigned to headPtr Two primary operations on linked lists are insert and delete Inserting a new node - insert
o 1. 2. o 1. 2. 3. o
Its arguments are: address of pointer to head node of list (sPtr) the data to be inserted in the list (newData) need three pointers to nodes: newPtr (address of new node to be inserted) prevPtr (pointer to node before insertion point) currPtr (pointer to node after insertion point) Algorithm:
begin insert( sPtr, newData ) request memory for newNode newPtr = address of newNode if ( newPtr != NULL ) newNodeData = newData nextPtr of new node = NULL prevPtr = NULL
currPtr = sPtr while ( currentPtr != NULL AND newData > curNodeData ) prevPtr = currPtr currPtr = nextPtr of current node endwhile if ( prevPtr == NULL ) nextPtr of new node = address of headNode headNode pointer = address of newNode else nextPtr of previous node = newPtr nextPtr of newNode = currPtr endif else display error message endif return o o 1. 2. o 1. 2. 3. o Deleting a node - delete its arguments are: address of pointer to head node in list (sPtr) data to be deleted from list (delData) need three pointers to nodes: tempPtr (temporary pointer to node) prevPtr (pointer to node before deletion point) currPtr (pointer to node at deletion point) Algorithm:
begin delete( sPtr, delData) if ( delData = data in head node ) tempPtr = address of head node pointer to head node = nextPtr of head node release memory pointed to by tempPtr else prevPtr = address of head node currPtr = nextPtr of head node while ( currPtr != NULL AND current node data != delData ) prevPtr = currPtr currPtr = nextPtr of current node endwhile if ( currPtr != NULL ) tempPtr = address of current node nextPtr of previous node = nextPtr of current node release memory pointed to by tempPtr endif endif return
#include <stdio.h>
struct listNode { char data; // simple data portion of node // pointer to next node
int main( ) { char oneChar; char delChar; int k; // workspace for data // to test delete function
// seed RNG
for( k = 0; k < 10; ++k ) { oneChar = 'A' + rand() % 26; if( k == 5 ) delChar = oneChar; printf( "%c ", oneChar ); insert( oneChar ); }
// save a char to test delete() // show char being inserted // insert char into list
delete( delChar );
int insert( char ch ) { ListNode *previousPtr = NULL; // pointer to previous node in list
while( currentPtr != NULL && ch > currentPtr->data ) { previousPtr = currentPtr; currentPtr = currentPtr->next; } // walk to ... // next node
// insert at head
int delete( char ch ) { ListNode *previousPtr = NULL; ListNode *currentPtr = headPtr; ListNode *tempPtr; // pointer to previous node in list // pointer to current node in list
while( currentPtr != NULL && ch != currentPtr->data ) { previousPtr = currentPtr; currentPtr = currentPtr->next; } // walk to ... // next node
previousPtr->next = currentPtr->next;
// relink list
// return memory
// return success
// moviedb.c -- COP2220 Example -- 040401 (sjd), 090405 (sjd) // Operating and maintaining a linked list
#include <stdio.h>
#include <stdlib.h>
struct movie { char title[40]; struct movie *next; }; // title of movie // pointer to next node
int insert(Movie *); int delete(Movie *); void showList(void); char menu(void); int getline(char *, int);
// add new movie to Movie list // remove a movie from Movie list // display the movie list // prompt user for next action // input string
int main() { int choice; Movie oneMovie; extern Movie *headPtr; // user choice // workspace for a Movie // global head pointer
switch (choice) {
case 'A':
puts("Movie title to add?"); getline(oneMovie.title, sizeof(oneMovie.title)); if (insert(&oneMovie)) puts("Movie added to list."); else puts("No memory. Movie not added."); break;
case 'R':
if(headPtr != NULL) { puts("Movie title to delete?"); getline(oneMovie.title, sizeof(oneMovie.title)); if (delete(&oneMovie)) puts("Movie deleted."); else puts("Movie title not found."); } else puts("Movie list is empty."); break;
case 'D':
return 0; }
/* program exit */
printf( "\n < [A]dd, [R]emove, [D]isplay, [Q]uit\r"); do { printf("? "); choice = toupper(getchar()); while (getchar() != '\n') ; } while(!strchr("ARDQ", choice)); // flush the buffer
return choice; }
/* getline: read a line into s, return length */ int getline(char s[], int lim) { int c, i;
for (i = 0; i < (lim - 1) && (c = getchar()) != EOF && c != '\n'; ++i) s[i] = c; if (c == '\n') { s[i] = c; ++i; } s[i] = '\0'; /* null-terminate the string */ return i; }
int insert(Movie *m) { Movie *previousPtr = NULL; Movie *currentPtr = headPtr; // pointer to previous node in list // pointer to current node in list
while (currentPtr != NULL && strcmp(newPtr->title, currentPtr->title) > 0) { previousPtr = currentPtr; currentPtr = currentPtr->next; } // walk to ... // next node
// insert at head
int delete(Movie *m) { Movie *previousPtr = NULL; Movie *currentPtr = headPtr; Movie *tempPtr; // pointer to previous node in list // pointer to current node in list
while (currentPtr != NULL && strcmp(currentPtr->title, m->title) != 0) { previousPtr = currentPtr; currentPtr = currentPtr->next; } // walk to ... // next node
previousPtr->next = currentPtr->next; free(tempPtr); return 1; } else return 0; } // error return // return success
// relink list
// return memory
Stacks o o o A stack is a constrained type of linked list New nodes are added and removed only from the top (LIFO) Stacks used extensively in systems software to handle interrupts pass data between programs/modules to evaluate expressions
o o o
Requirements: stackPtr pointer contains address of node at top of stack link in each node points to next node last node in stack has link pointing to NULL Two primary functions: push (add node to stack) and pop (remove node from stack)
1. 2.
required parameters are: stackPtr (pointer to top of stack) newData (data to be added to stack) needs one pointer to new node: newPtr Algorithm:
begin push( stackPtr, newData ) request memory for newNode newPtr = address of newNode if ( newPtr != NULL ) newNode data = newData newNode nextPtr = stackPtr stackPtr = newPtr else display error message endif return o Remove node from stack top: pop required argument is address of stackPtr (pointer to top of stack) returns data of node popped (popValue) Note: assumes stack is not empty!! (not called if isEmpty(stackPtr) needs workspace tempPtr (pointer to node)
Algorithm:
begin pop( stackPtr ) tempPtr = stackPtr popValue = top node data stackPtr = top node nextPtr deallocate space for top node return popValue
// definition of node
// pointer to stack
for( k = 1; k <= 10; ++k ) { val = 10 * k; push( &val ); printf( "%d ", val ); }
int push( const int *val ) { StackNode *newPtr = malloc( sizeof( StackNode ) ); // new node
if( newPtr ) { newPtr->data = *val; newPtr->nextPtr = stackPtr; stackPtr = newPtr; return 1; } else return 0; }
int pop( int *val ) { StackNode *tempPtr = stackPtr; // temporary node pointer
Queues o o o A queue is another constrained version of a linked list Nodes only removed from head of the queue, added to tail (FIFO) Typical applications are in scheduling processes, print spooling, data transmission Requirements: headPtr contains address of first node in queue tailPtr contains address of last node in queue link in each node in queue points to next node, last node points to NULL
Two primary functions: enqueue (add node to tail) and dequeue (remove node from head of the queue) Here is enqueue:
Here is dequeue:
o o 1. 2. 3.
queue.c (operating and maintaining a queue) Initialization: headPtr and tailPtr set to NULL (empty queue) Adding new node - enqueue arguments required are: address of headPtr address of tailPtr value to be added (newData) need pointer to new node: newPtr Algorithm:
begin enqueue( headPtr, tailPtr, newData ) request memory for newNode newPtr = address of newNode if ( newPtr != NULL ) newNode data = newData newNode nextPtr = NULL if ( queue is empty ) headPtr = address of newNode else tailNode nextPtr = address of newNode
tailPtr = address of newNode endif else display error message endif return o 1. 2. Removing a node - dequeue required parameters are: address of headPtr address of tailPtr need working space for tempPtr to node and return_value Algorithm:
begin dequeue( headPtr, tailPtr ) return_value = headNode data temPtr = address of headNode headPtr = address of next node if ( headPtr is NULL ) tailPtr = NULL endif deallocate headNode return return_value // queue.c -- COP2220 Example -- 040401 (sjd) // Dynamic queue program demo // queue is now empty!
// definition of node
int enqueue( const int *val ) { QueueNode *newPtr = malloc( sizeof( QueueNode ) ); // new node
tailPtr->nextPtr = newPtr;
// return failure
int dequeue( int *val ) { QueueNode *tempPtr = headPtr; // temporary node pointer
// if queue is not empty ... // extract data from head node // set new head // return memory // return success
// return failure