490 likes | 606 Views
Data Structures. Self-referential structures Dynamic memory allocation Linked lists Stacks Queues Trees. Dynamic Data Structures. Linked lists Insert & delete anywhere in the list Stacks Insert & delete at the top Used in compilers & operating systems Queues
E N D
Data Structures • Self-referential structures • Dynamic memory allocation • Linked lists • Stacks • Queues • Trees
Dynamic Data Structures • Linked lists • Insert & delete anywhere in the list • Stacks • Insert & delete at the top • Used in compilers & operating systems • Queues • Insert at back & delete from front • Used in operating systems, print spooling, & networks • Binary trees • Quick searching & sorting
Self-Referential Structure • Contains a pointer that points to another structure of the same type struct node{ int data; struct node *next; }; • Self-referential structures linked together to form dynamic data structures
Dynamic Memory Allocation • Ability of a program to use more memory space at execution time • Hold new nodes • Use function malloc to allocate memory • Release space no longer needed • Use function free to deallocate memory • Use #include <stdlib.h> header file when using malloc & free functions
Functions malloc & free • ptr = malloc(sizeof(struct node)); • sizeof(struct node) returns the size in bytes of the structure • malloc() allocates the specified number of bytes in memory • Returns a pointer to the place in memory • Returns NULL, if no more memory is available • free(ptr); • Deallocates the memory referred to by the pointer so it can be reused
Program in Memory • Code segment • Contains instructions (program code) • Data segment • Contains static data (global variables) • Stack segment • Each function call creates a stack frame • Stack frame contains local variables, etc. • Function call: push stack frame • Function exit: pop stack frame • Grows from top of memory downwards
Stack & Heap • Stack • Implicit (automatic) allocation & deallocation • Heap • Memory explicitly allocated & deallocated by the programmer using functions malloc & free • At bottom of memory & grows upwards • When the stack & the heap meet, your program is out of memory • May occur if you don’t use free function to deallocate memory
Stack & Heap Example • See HeapStack.htm • Each function call creates a “stack frame” or “activation record” that stores information about the function on the stack • Parameters • Return address • Local variables • Each malloc() function call allocates data on the heap, while free() deallocates data from the heap
Linked List • Collection of nodes (self-referential structure) • Connected by links (pointer to next node) • Pointer points to the first node • Next pointer refers to next node • Last node has a NULL next pointer • Constrained versions of linked lists • Stacks (insert & delete at the top) • Queues (insert at back & delete from front)
Linked List Example • See fig12_03.c • A program that manipulates a list of characters • Insert a character in the list in alphabetical order • Delete a character from the list
Inserting a Character • Function prototype struct listNode { char data; struct listNode *nextPtr; }; typedef struct listNode ListNode; typedef ListNode *ListNodePtr; void insert(ListNodePtr *, char );
Inserting a Character • Equivalent code void insert(ListNodePtr *, char ); //void insert( struct listNode **, char); • sPtr is a pointer to a pointer, because • the address of the list is passed to the function • and the list itself is a pointer (a pointer to its 1st element)
Inserting a Character • Calling the function ListNodePtr startPtr = NULL; //struct listNode *startPtr = NULL; . . . insert( &startPtr, item ); • startPtr contains a pointer to the beginning node of the list
Inserting a Character void insert( ListNodePtr *sPtr, char value ){ ListNodePtr newPtr; /* pointer to new node */ ListNodePtr previousPtr; /* pointer to previous node in list */ ListNodePtr currentPtr; /* pointer to current node in list */ newPtr = malloc( sizeof( ListNode ) ); /* create node */
Inserting a Character if ( newPtr != NULL ) { /* is space available */ newPtr->data = value; /* place value in node */ newPtr->nextPtr = NULL; /* node does not link to another node */ previousPtr = NULL; currentPtr = *sPtr;
Inserting a Character while ( currentPtr != NULL && value > currentPtr->data ) { /* loop to find the correct location in the list */ previousPtr = currentPtr; /* walk to ... */ currentPtr = currentPtr->nextPtr; /* ... next node */ }
Inserting a Character if ( previousPtr == NULL ) { /* insert new node at beginning of list */ newPtr->nextPtr = *sPtr; *sPtr = newPtr; } else { /* insert new node between previousPtr and currentPtr */ previousPtr->nextPtr = newPtr; newPtr->nextPtr = currentPtr; }
Deleting a Character • Function prototype struct listNode { char data; struct listNode *nextPtr; }; typedef struct listNode ListNode; typedef ListNode *ListNodePtr; void delete(ListNodePtr *, char );
Deleting a Character • Equivalent code void delete(ListNodePtr *, char ); //void delete( struct listNode **, char); • sPtr is a pointer to a pointer, because • the address of the list is passed to the function • and the list itself is a pointer (a pointer to its 1st element)
Deleting a Character char delete( ListNodePtr *sPtr, char value ){ ListNodePtr previousPtr; /* pointer to previous node in list */ ListNodePtr currentPtr; /* pointer to current node in list */ ListNodePtr tempPtr; /* temporary node pointer */
Deleting a Character if ( value == ( *sPtr )->data ) { /* delete first node */ tempPtr = *sPtr; /* hold onto node being removed */ *sPtr = ( *sPtr )->nextPtr; /* de-thread the node */ free( tempPtr ); /* free the de-threaded node */ return value; }
Deleting a Character else { previousPtr = *sPtr; currentPtr = ( *sPtr )->nextPtr; while ( currentPtr != NULL && currentPtr->data != value ) { /* loop to find the correct location in the list */ previousPtr = currentPtr; /* walk to ... */ currentPtr = currentPtr->nextPtr; /* ... next node */ }
Deleting a Character if ( currentPtr != NULL ) { /* delete node at currentPtr */ tempPtr = currentPtr; previousPtr->nextPtr = currentPtr->nextPtr; free( tempPtr ); return value; }
Stacks • Referenced by a pointer to the top element • “Push” to the stack to insert data • Allocates memory to create a new node • Places new node on top of stack • “Pop” to the stack to delete data • Removes node from top of stack • Deallocates (frees) memory • Returns the data that was stored in the node
Dynamic Stack Example • See fig12_08.c • Program that implements a stack of integers • Push an integer onto the stack • Pop a value off the stack
Dynamic Stack Program • Self-referential structure struct stackNode { int data; struct stackNode *nextPtr; }; • Use typedef to create structure synonym & pointer to structure synonym typedef struct stackNodeStackNode; typedef StackNode *StackNodePtr;
Dynamic Stack Program • Push & pop must modify the stack (so must pass a pointer) • Since stack itself is a pointer (to the top of the stack), passing the address of the stack creates a pointer to a pointer (double indirection) void push( StackNodePtr*, int ); int pop( StackNodePtr* ); int isEmpty( StackNodePtr ); void printStack( StackNodePtr ); void instructions( void );
Dynamic Stack Program • Function main int main(){ /* points to stack top */ StackNodePtr stackPtr = NULL; int choice, value; instructions(); scanf( "%d", &choice ); while ( choice != 3 ) {
Dynamic Stack Program • Function call to push value on stack switch ( choice ) { case 1: printf( "Enter an integer: " ); scanf( "%d", &value ); push( &stackPtr, value ); printStack( stackPtr ); break;
Dynamic Stack Program • Inserting a node to the top of the stack void push(StackNodePtr *topPtr,int info){ StackNodePtr newPtr; /*allocate space for the node*/ newPtr = malloc(sizeof(StackNode)); if ( newPtr != NULL ) { newPtr->data = info; newPtr->nextPtr = *topPtr; *topPtr = newPtr; } else printf("No memory available.");}
Dynamic Stack Program • Function call to pop value off stack case 2: if ( !isEmpty( stackPtr ) ) printf( "The popped value is %d.\n", pop( &stackPtr ) ); printStack( stackPtr ); break;
Dynamic Stack Program • Remove a node from top of stack int pop( StackNodePtr *topPtr ){ StackNodePtr tempPtr; int popValue; tempPtr = *topPtr; popValue = (*topPtr)->data; *topPtr = (*topPtr)->nextPtr; /*deallocate memory used by node*/ free( tempPtr ); return popValue; }
Dynamic Stack Program • Print the stack void printStack(StackNodePtrcurrentPtr){ if ( currentPtr == NULL ) printf("The stack is empty.\n\n" ); else { printf( "The stack is:\n" ); while ( currentPtr != NULL ) { printf( "%d --> ", currentPtr->data ); currentPtr = currentPtr->nextPtr;} printf( "NULL\n\n" );}}
Dynamic Stack Program • Check to see if stack is empty int isEmpty( StackNodePtr topPtr ){ return topPtr == NULL; }
Queue Program • See fig12_13.c • Insert a character into a queue • Remove a character from a queue
Queue Program • Main function QueueNodePtr headPtr = NULL; /* initialize headPtr */ QueueNodePtr tailPtr = NULL; /* initialize tailPtr */ int choice; /* user's menu choice */ char item; /* char input by user */
Inserting a Node void enqueue( QueueNodePtr *headPtr, QueueNodePtr *tailPtr, char value ){ /* insert a node at queue tail */ QueueNodePtr newPtr; /* pointer to new node */ newPtr = malloc( sizeof( QueueNode ) ); if ( newPtr != NULL ) { /* is space available */ newPtr->data = value; newPtr->nextPtr = NULL;
Inserting a Node if ( isEmpty( *headPtr ) ) { /* if empty, insert node at head */ *headPtr = newPtr; } else { ( *tailPtr )->nextPtr = newPtr; } *tailPtr = newPtr; } else { printf( "%c not inserted. No memory available.\n", value );} }
Removing a Node char dequeue( QueueNodePtr *headPtr, QueueNodePtr *tailPtr ){ /* remove node from queue head */ char value; QueueNodePtr tempPtr; value = ( *headPtr )->data; tempPtr = *headPtr; *headPtr = ( *headPtr )->nextPtr; /* if queue is empty */ if ( *headPtr == NULL ) { *tailPtr = NULL; } free( tempPtr ); return value; }
Binary Tree Program • See fig12_19.c • Insert 10 random integers into a binary tree • No duplicate values are allowed • Outputs the tree in preorder, inorder, and postorder
Binary Tree • Collection of nodes that are connected by two links (pointer to next node) • Root node - first node in the tree • Left child - first node in the left subtree • Right child - first node in the right subtree • Siblings - children of a node • Leaf node - node with no children
Binary Search Tree • Binary search tree has the following properties • No duplicate node values • All values in the left subtree are lessthan the value in its parent node • All values in the right subtree are greater than the value in its parent node • Quick to find a value • Takes 10 or less comparisons in 1000 node tree
Binary Tree Program struct treeNode { struct treeNode *leftPtr; /* pointer to left subtree */ int data; /* node value */ struct treeNode *rightPtr; /* pointer to right subtree */ }; typedef struct treeNode TreeNode; /* synonym for struct treeNode */ typedef TreeNode * TreeNodePtr; /* synonym for TreeNode* */
Binary Tree Program /* prototypes */ void insertNode( TreeNodePtr *, int ); void inOrder( TreeNodePtr ); void preOrder( TreeNodePtr ); void postOrder( TreeNodePtr );
Inserting a Node void insertNode(TreeNodePtr *treePtr,int value){ /* if tree is empty */ if ( *treePtr == NULL ) { *treePtr = malloc( sizeof( TreeNode)); /* if memory was allocated then assign data */ if ( *treePtr != NULL ) { ( *treePtr )->data = value; ( *treePtr )->leftPtr = NULL; ( *treePtr )->rightPtr = NULL; } else {printf( "%d not inserted. No memory available.\n", value ); } }
Inserting a Node else { /* tree is not empty */ /* data to insert is less than data in current node */ if ( value < ( *treePtr )->data ) { insertNode( &( ( *treePtr )->leftPtr ), value ); } /* data to insert is greater than data in current node */ else if ( value > ( *treePtr )->data ) { insertNode( &( ( *treePtr )->rightPtr ), value ); } else { /* duplicate data value ignored */ printf( "dup" ); }
Inorder Traversal void inOrder( TreeNodePtr treePtr ){ /* if tree is not empty then traverse */ if ( treePtr != NULL ) { inOrder( treePtr->leftPtr ); printf( "%3d", treePtr->data ); inOrder( treePtr->rightPtr ); } } • The numbers being placed in the tree are: • 9 10 3 6 11 1 7 • The inOrder traversal is: • 1 3 6 7 9 10 11
Preorder Traversal void preOrder( TreeNodePtr treePtr ){ /* if tree is not empty then traverse */ if ( treePtr != NULL ) { printf( "%3d", treePtr->data ); preOrder( treePtr->leftPtr ); preOrder( treePtr->rightPtr ); } } • The numbers being placed in the tree are: • 9 10 3 6 11 1 7 • The preOrder traversal is: • 9 3 1 6 7 10 11
Postorder Traversal void postOrder( TreeNodePtr treePtr ){ /* if tree is not empty then traverse */ if ( treePtr != NULL ) { postOrder( treePtr->leftPtr ); postOrder( treePtr->rightPtr ); printf( "%3d", treePtr->data ); } } • The numbers being placed in the tree are: • 9 10 3 6 11 1 7 • The postOrder traversal is: • 1 7 6 3 11 10 9