Você está na página 1de 32

DATA STRUCTURES

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 { char data[10]; // data member

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

NODE newNode; NODE *newNodePtr;

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:

newNodePtr = (NODE *)malloc(sizeof(NODE));

if (newNodePtr == NULL) { /* some code to gracefully shut down pgm */ exit(EXIT_FAILURE); }

else { /* ok to proceed */ } /* memreq2.c -- 090405 (sjd) Demo malloc Note: Must be run from command line, not from IDE */

#include <stdio.h> #include <stdlib.h>

int main() { unsigned n = 0; /* number of doubles allocated, in millions */ double *dp; /* pointer to new double */

while (1) {

/* infinite loop */

printf("n = %d\n", n); dp = (double *)malloc(1000000 * sizeof(double));

if (dp == NULL) { printf("\nNo memory left after allocating %d million doubles.\n\n"); system("pause"); exit(EXIT_FAILURE); } n++; } system("pause"); return 0; }

/* memreq.c -Demo assert and malloc */

#include <stdio.h> #include <stdlib.h>

#define NDEBUG

/* uncomment to ignore assert */

#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

// llist.c -- COP2220 Example -- 040401 (sjd) // Demonstrate a linked list

#include <stdio.h>

#include <stdlib.h> #include <time.h>

struct listNode { char data; // simple data portion of node // pointer to next node

struct listNode *next; };

typedef struct listNode ListNode; // new data type

ListNode *headPtr = NULL;

// pointer to head of list

int insert( char ); int delete( char ); void showList( void );

// add node to list // remove a node list // display the list

int main( ) { char oneChar; char delChar; int k; // workspace for data // to test delete function

// loop ctl var

srand( time( NULL ) );

// seed RNG

printf( "Inserting in list:\n" );

for( k = 0; k < 10; ++k ) { oneChar = 'A' + rand() % 26; if( k == 5 ) delChar = oneChar; printf( "%c ", oneChar ); insert( oneChar ); }

// load list with 10 random chars

// save a char to test delete() // show char being inserted // insert char into list

printf( "\n\nList in order:\n" ); showList( );

// display the results

delete( delChar );

// delete the saved char

printf( "\n\nList after deleting %c:\n", delChar ); showList( );

printf( "\n\n" ); system( "pause" ); return EXIT_SUCCESS; }

int insert( char ch ) { ListNode *previousPtr = NULL; // pointer to previous node in list

ListNode *currentPtr = headPtr;

// pointer to current node in list

ListNode *newPtr = malloc( sizeof( ListNode ) ); // create node

if( newPtr == NULL ) return 0; // return error

newPtr->data = ch; newPtr->next = NULL;

// place data in node // initialize next pointer

while( currentPtr != NULL && ch > currentPtr->data ) { previousPtr = currentPtr; currentPtr = currentPtr->next; } // walk to ... // next node

if ( previousPtr == NULL ) { newPtr->next = headPtr; headPtr = newPtr; } else

// insert at head

// insert within list

{ previousPtr->next = newPtr; newPtr->next = currentPtr; } return 1; // return success

int delete( char ch ) { ListNode *previousPtr = NULL; ListNode *currentPtr = headPtr; ListNode *tempPtr; // pointer to previous node in list // pointer to current node in list

// temporary node pointer

while( currentPtr != NULL && ch != currentPtr->data ) { previousPtr = currentPtr; currentPtr = currentPtr->next; } // walk to ... // next node

if ( currentPtr != NULL ) { tempPtr = currentPtr;

// find it? // save address

if( currentPtr == headPtr ) headPtr = currentPtr->next; else

// delete head of list? // reset head

previousPtr->next = currentPtr->next;

// relink list

free( tempPtr ); return 1; }

// return memory

// return success

else return 0; } // error return

void showList( ) { ListNode *currentPtr = headPtr;

while( currentPtr != NULL ) { printf( "%c ", currentPtr->data ); currentPtr = currentPtr->next; } }

// walk the list to print

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

typedef struct movie Movie; // new data type: Movie

Movie *headPtr = NULL;

// global pointer to head of Movie list

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

puts("> Welcome to the Movie Database 1.1 <");

while ((choice = menu()) != 'Q') {

switch (choice) {

case 'A':

/** add a Movie **/

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':

/** remove a Movie **/

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':

/** Display movie list **/

if (headPtr != NULL) showList(); else puts("Movie list is empty."); break;

} // end switch } // end while

return 0; }

/* program exit */

char menu() { char choice;

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

Movie *newPtr = malloc(sizeof(Movie)); // create node

if (newPtr == NULL) return 0; // return error

strcpy(newPtr->title, m->title); newPtr->next = NULL;

// place value in title // initialize next pointer

while (currentPtr != NULL && strcmp(newPtr->title, currentPtr->title) > 0) { previousPtr = currentPtr; currentPtr = currentPtr->next; } // walk to ... // next node

if (previousPtr == NULL) { newPtr->next = headPtr; headPtr = newPtr; } else {

// insert at head

// insert within list

previousPtr->next = newPtr; newPtr->next = currentPtr; } return 1; } // return success

int delete(Movie *m) { Movie *previousPtr = NULL; Movie *currentPtr = headPtr; Movie *tempPtr; // pointer to previous node in list // pointer to current node in list

// temporary node pointer

while (currentPtr != NULL && strcmp(currentPtr->title, m->title) != 0) { previousPtr = currentPtr; currentPtr = currentPtr->next; } // walk to ... // next node

if (currentPtr != NULL) { tempPtr = currentPtr; if (currentPtr == headPtr) headPtr = currentPtr->next; else

// find it? // save address // delete head of list? // reset head

previousPtr->next = currentPtr->next; free(tempPtr); return 1; } else return 0; } // error return // return success

// relink list

// return memory

void showList( ) { Movie *currentPtr = headPtr;

while (currentPtr != NULL) { printf("%s", currentPtr->title ); currentPtr = currentPtr->next; } }

// walk the list to print

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)

stack.c (dynamic stack program) Adding a new node: push

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

// stack.c -- COP2220 Example -- 040401 (sjd) // Dynamic stack program demo

#include <stdio.h> #include <stdlib.h>

struct stackNode { int data; struct stackNode *nextPtr; };

// definition of node

typedef struct stackNode StackNode;

// StackNode is new data type

StackNode *stackPtr = NULL;

// pointer to stack

int push( const int *pushValue ); int pop( int *popValue );

// add to stack // remove from stack

int main( ) { int k; int val; // loop control // int to push/pop

puts( "Pushing values onto stack:" );

for( k = 1; k <= 10; ++k ) { val = 10 * k; push( &val ); printf( "%d ", val ); }

puts( "\n\nPopping values from stack:" );

while( pop( &k ) ) printf( "%d ", k );

printf( "\n\nEnd of run.\n" );

system( "pause" ); return 0; }

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

if( stackPtr ) { *val = stackPtr->data; stackPtr = stackPtr->nextPtr;

free( tempPtr ); return 1; } else return 0; }

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!

#include <stdio.h> #include <stdlib.h>

struct queueNode { int data; struct queueNode *nextPtr; };

// definition of node

typedef struct queueNode QueueNode;

// QueueNode is new data type

QueueNode *headPtr = NULL; QueueNode *tailPtr = NULL;

// pointer to head of queue // pointer to tail of queue

int enqueue( const int *enqueueValue ); int dequeue( int *dequeueValue );

// add to queue // remove from queue

int main( ) { int k; int val; // loop control // int to enqueue/dequeue

puts( "Enqueue values onto queue:" );

for( k = 1; k <= 10; ++k ) { val = 10 * k;

enqueue( &val ); printf( "%d ", val ); }

puts( "\n\nDequeue values from queue:" );

while( dequeue( &k ) ) printf( "%d ", k );

printf( "\n\nEnd of run.\n" ); system( "pause" ); return 0; }

int enqueue( const int *val ) { QueueNode *newPtr = malloc( sizeof( QueueNode ) ); // new node

if( newPtr ) { newPtr->data = *val; newPtr->nextPtr = NULL;

// is there a new node? // fill data portion // NULL-terminate

if( headPtr == NULL ) headPtr = newPtr; else

// if nothing in queue ... // set new head ptr // otherwise ...

tailPtr->nextPtr = newPtr;

// chain from old tail

tailPtr = newPtr; return 1; } else return 0; }

// set new tail ptr // return success

// return failure

int dequeue( int *val ) { QueueNode *tempPtr = headPtr; // temporary node pointer

if( headPtr ) { *val = headPtr->data;

// if queue is not empty ... // extract data from head node // set new head // return memory // return success

headPtr = headPtr->nextPtr; free( tempPtr ); return 1; } else return 0; }

// return failure

Você também pode gostar