You are on page 1of 84

Engr. Pable, Lealou C.

Dynamic memory allocation the ability for a program to obtain more memory space at execution time to hold new nodes, and to release space no longer needed. How? 1. Determine the size in bytes of a structure type using the sizeof function, 2. Allocate a new area in memory of sizeof bytes using malloc, 3. Store a pointer to the allocated memory in a variable pointer.

Where: malloc() takes as an argument the number of bytes to be allocated, and returns a pointer of type void* (pointer to void) to the allocated memory. Normally used with the sizeof operator. sizeof determines the size in bytes of the structure for which memory is being allocated. free() deallocates memory.

For example: newPtr = malloc (sizeof (struct node)); - Evaluates sizeof(struct node) to determine the size in bytes of a structure of type struct node, allocates a new area in memory of sizeof(struct node) bytes, and stores a pointer to allocated memory in variable newPtr. - Note: If no memory is available, malloc returns a NULL pointer. To free memory dynamically allocated by the preceding malloc call, use the statement free(newPtr);

The following lines allocate an integer space from the memory pointed by the pointer p. int *p; p = (int *) malloc(sizeof(int));
Allocate floating point number space for a float pointer f. float *f; f = (float *) malloc(sizeof(float));

Question:What is the output of the following lines?

int *p, *q; int x; p = (int *) malloc(sizeof(int)); *p = 3; x = 6; q = (int *) malloc(sizeof(int)); *q=x; printf(%d %d \n, *p, *q);

p p x q q 6 3 6

The

following lines and the proceeding figure shows the effectiveness of the free() function. int *p, *q; p = (int *) malloc(sizeof(int)); *p = 5; q = (int *) malloc(sizeof(int)); *q = 8; free(p); p = q; q = (int *) malloc(sizeof(int)); *q = 6; printf(%d %d \n, *p, *q);

Self-referential structure contains a pointer member that points to a structure of the structure type. Example: struct node{ int data; struct node *nextPtr; /*points to a structure }; of type node/* nextPtr is referred to as a link i.e., can be used to tie a structure of type struct node to another structure of the same type. Self-referential structures can be linked together to form useful data structures such as lists, queues, stacks and trees.

Data Structure the logical and mathematical model of a particular organization of data.
Two types: Fixed data structures ex. Arrays, structs Dynamic data structures ex. Linked lists, stacks, queues, binary trees. - with sizes that may grow and may shrink during the execution time.

List a collection of related data. Two categories: 1. Linear lists a. General lists b. Stacks c. Queues 2. Non-linear lists a. Trees b. Graphs

List Implementations The C language does not provide any list structures or implementations. When we need them, we must provide the structures and functions for them. Traditionally, two data types, arrays and pointers, are used for their implementation.
The array implementation uses static structures that are determined during the compilation or while the program is running. The pointer implementation uses dynamically allocated structures known as linked lists.

Array Implementation
In an array implementation, the sequentiality of a list is maintained by the order structure of elements in the array (indexes). Although searching of an array for an individual element can be very efficient, addition and deletion of elements are complex and inefficient processes. For this reason arrays are seldom used.

A general linear list is a list in which operations, such as retrievals, insertions, changes, and deletions, can be done anywhere in the list, that is, at the beginning, in the middle, or at the end of the list

Linked list an ordered collection of data in which each element contains the location of the next element or elements. - linear collection of self-referential structures, called nodes (a structure), connected by pointer links. Two parts of a node: 1. Data - Holds the application datadata to be processed. 2. Links - Used to chain the data together.

LINKED LISTS NODE STRUCTURES

What consists a linked list? 1. root node (head), allocated on the stack (an ordinary C variable) 2. one or more records, allocated on the heap (by calling malloc) Two parts: 1. link field links to the subsequent record 2. data field[s] contain[s] the information you want to be stored in the linked list

Linked list can be maintained in sorted order by inserting each new element at the proper point in the list. Primary functions: Insert Delete isEmpty() called a predicate function it does not alter the list in any way; rather it determines if the list is empty (i.e., the pointer to the first node of the list is NULL).

Linked list - accessed via a pointer to the first node of the list; subsequent nodes are accessed via the link pointer member stored in each node.
- by convention, the link pointer in the last node of the list is set to NULL to mark the end of the list.

Insert a Node 1. Allocate memory for the new node. 2. Store the data value in the newly created node. 3. Determine the insertion point that is, the position within the list where the new data are to be placed. To identify the insertion point, we need to know only the new nodes predecessor. 4. Point the new node to its successor. 5. Point the predecessor to the new node.

POINTER COMBINATIONS FOR INSERT

INSERT NODE TO EMPTY LIST

INSERT NODE AT THE BEGINNING

INSERT NODE IN THE MIDDLE

INSERT NODE AT THE END

DELETE FIRST NODE

DELETE GENERAL CASE

LINKED LIST TRAVERSAL

is a linear list in which all additions and deletions are restricted to one end, called the top. known as the last infirst out (LIFO) data structure.
Graphical representation of a stack:
stackPtr
8 2 3

CONCEPTUAL AND PHYSICAL IMPLEMENTATION

The stacks can be implemented by the use of arrays and linked lists. One way to implement the stack is to have a data structure where a variable called top keeps the location of the elements in the stack (array) An array is used to store the elements in the stack

struct STACK{ int count; /* keeps the number of elements in the stack */ int top; /* indicates the location of the top of the stack*/ int items[STACKSIZE]; /*array to store the stack elements*/ }

initialize the stack by assigning -1 to the top pointer to indicate that the array based stack is empty (initialized) as follows: You can write following lines in the main program: : STACK s; s.top = -1; :

Alternatively you can use the following function:


void StackInitialize(STACK *Sptr) { Sptr->top=-1; }

Push an item onto the top of the stack (insert an item)

Void push (Stack *, type newItem)

Function: Adds newItem to the top of the stack. Preconditions: Stack has been initialized and is not full. Postconditions: newItem is at the top of the stack.

void push(STACK *Sptr, int ps) /*pushes ps into stack*/ { if(Sptr->top == STACKSIZE-1){ printf("Stack is full\n"); return; /*return back to main function*/ } else { Sptr->top++; Sptr->items[Sptr->top]= ps; Sptr->count++; } }

Pop an item off the top of the stack (delete an item)

type pop (STACK *)

Function: Removes topItem from stack and returns with topItem Preconditions: Stack has been initialized and is not empty. Postconditions: Top element has been removed from stack and the function returns with the top element.

int pop(STACK *Sptr) { int pp; if(Sptr->top == -1){ printf("Stack is empty\n"); return -1; /*exit from the function*/ } else { pp = Sptr->items[Sptr->top]; Sptr->top--; Sptr->count--; return pp; } }

Data Structure To implement the linked list stack, we need two different structures, a head node and a data node. Stack head Two attributes: a top pointer and a count of the number of elements in the stack. Stack data node Looks like any linked list node and contains a link pointer to other data nodes.

Stack data structure


count top

Stack Head Structure


data link

typedef struct{ int count; struct node *top; }STACK; typedef struct node{ int data; struct node *link; }STACK_NODE;

Stack Node Structure

push inserts an element in the stack. creates a new node and places it on the top of the stack. Add 1 to the stack count field To develop the insertion algorithm using a linked list, we need to analyze three different stack conditions: 1.Insertion into an empty stack 2.Insertion into a stack with data 3.Insertion into a stack when the available memory is exhausted

Streams

pop removes a node from the top of the stack, frees the memory that was allocated to the popped node, and returns the popped value. Count is adjusted by subtracting 1. If pop is successful, it returns true; if the stack is empty, it returns false.

POP Stack Example

Design for a basic stack program

Stacks can be used to reverse a sequence. For example, if a string Computers is entered by the user the stack can be used to create and display the reverse string sretupmoC as follows. The program simply pushes all of the characters of the string into the stack. Then it pops and display until the stack is empty.

#include<stdio.h> #include<stdlib.h> #define STACKSIZE 50 typedef struct{ int count; int top; char items[STACKSIZE];/*stack can contain
up to 50 characters*/

}STACK; void push(STACK *, char); char pop(STACK *);

void push(STACK *Sptr, char ps) /*pushes ps


into stack*/

{ if(Sptr->top == STACKSIZE-1){ printf("Stack is full\n"); return; /*exit from the function*/ } else { Sptr->top++; Sptr->count++; Sptr->items[Sptr->top]= ps; } }

char pop(STACK *Sptr) { char pp; if(Sptr->top == -1){ printf("\nStack is empty\n"); exit(1); /*exit from the function*/ } else { pp = Sptr->items[Sptr->top]; Sptr->top--; Sptr->count--; } return pp; }

int main() { int i; STACK s; char p, A[20]; s.top = -1; /*indicates that the stack is empty at the beginning*/ s.count=0; printf("Input the string please:\n"); gets(A); /* alternatively you can use scanf("%s",A); */ /*pushing the characters into the stack*/ for(i=0;A[i] != '\0';i++){ p = A[i]; push(&s,p); } printf("The string in reverse order is:"); /*popping and printing the string in reverse order*/ while(s.count >= 0){ p=pop(&s); printf("%c",p); } return 0; }

The strings where the reading from the reverse and forward directions give the same word are called a palindrome. For example, the string radar is an example for palindrome. Among many other techniques stack can be used to determine if a string is a palindrome or not. This is achieved by pushing all the letters of a given word into stack and checking if the letters popped are the same as the letter of the string. The following program determines if a given string is a palindrome or not?

Infix, Postfix and Prefix notations are used in many calculators. The easiest way to implement the Postfix and Prefix operations is to use stack. Infix and prefix notations can be converted to postfix notation using stack. The reason why postfix notation is preferred is that you dont need any parenthesis and there is no prescience problem.

In Postfix notation the expression is scanned from left to right. When a number is seen it is pushed onto the stack; when an operator is seen the operator is applied to the two numbers popped from the stack and the result is pushed back to the stack.
Ex: 6 5 2 3 + 8 * + 3 + * is evaluated as follows:

Scan the Infix expression left to right If the character x is an operand Output the character into the Postfix Expression If the character x is a left or right parenthesis If the character is ( Push it into the stack if the character is ) Repeatedly pop and output all the operators/characters until ( is popped from the stack.

If the character x is a is a regular operator Step 1: Check the character y currently at the top of the stack. Step 2: If Stack is empty or y=( or y is an operator of lower precedence than x, then push x into stack. Step 3: If y is an operator of higher or equal precedence than x, then pop and output y and push x into the stack. When all characters in infix expression are processed repeatedly pop the character(s) from the stack and output them until the stack is empty.

Infix Expression (a+b-c)*d(e+f)

Postfix Expression

A queue is a linear list in which data can be inserted only at one end, called the rear, and deleted from the other end, called the front. Note It is a first infirst out (FIFO) restricted data structure.

Queue Concept

Queue Operations 1. Enqueue 2. Dequeue

Enqueue inserts an element at the rear of the queue. Dequeue deletes an element at the front of the queue.

items[MAXQUEUE1]

. .

. .

.
items[2] items[1]

.
C B

items[0]

# define MAXQUEUE 50 /* size of the queue items*/


typedef struct { int front; int rear; int items[MAXQUEUE]; }QUEUE;

Initialize the queue Insert to the rear of the queue Remove (Delete) from the front of the queue Is the Queue Empty Is the Queue Full What is the size of the Queue

The queue is initialized by having the rear set to -1, and front set to 0. Let us assume that maximum number of the element we have in a queue is MAXQUEUE elements as shown below.

items[MAXQUEUE-1]

. .
. items[1] items[0]

. .

front=0 rear=-1

an item (A) is inserted at the Rear of the queue


items[MAXQUEUE
-1]

. . items[3] items[2] items[1] items[0]

. .

Front=0, Rear=0

A new item (B) is inserted at the Rear of the queue


items[MAXQUEUE
-1]

. . items[3] items[2] items[1] items[0]

. .

B A

Rear=1 Front=0

A new item (C) is inserted at the Rear of the queue


items[MAXQUEUE
-1]

. . items[3] items[2] items[1] items[0]

. . C B A
Rear=2

Front=0

A new item (D) is inserted at the Rear of the queue


items[MAXQUEUE-1] . . items[3] items[2] items[1] items[0] . . D C B A

Rear=3

Front=0

an item (A) is removed (deleted) from the Front of the queue


items[MAXQUEUE-1] . . . .

items[3]
items[2] items[1] items[0]

D
C B A

Rear=3
Front=1

Remove two items from the front of the queue.


items[MAXQUEUE-1] . . items[3] items[2] items[1] items[0] . . D C B A Rear=3 Front=2

Assume that the rear= MAXQUEUE-1


items[MAXQUEUE-1] . . items[3] items[2] items[1] items[0] X . . D C B A front=3 rear=MAXQUEUE-1

What happens if we want to insert a new item into the queue?

What happens if we want to insert a new item F into the queue? Although there is some empty space, the queue is full. One of the methods to overcome this problem is to shift all the items to occupy the location of deleted item.

Since all the items in the queue are required to shift when an item is deleted, this method is not preferred. The other method is circular queue. When rear = MAXQUEUE-1, the next element is entered at items[0] in case that spot is free.

#define MAXQUEUE 10 /* size of the queue items*/ typedef struct { int front; int rear; int items[MAXQUEUE]; }QUEUE; QUEUE q; q.front = MAXQUEUE-1; q.rear= MAXQUEUE-1;

void insert(QUEUE *qptr, char x) { if(qptr->rear == MAXQUEUE-1) qptr->rear=0; else qptr->rear++; /* or qptr->rear=(qptr->rear+1)%MAXQUEUE) */ if(qptr->rear == qptr->front){ printf("Queue overflow"); exit(1); } qptr->items[qptr->rear]=x; }

char remove(struct queue *qptr) { if(qptr->front == qptr->rear){ printf("Queue underflow"); exit(1); } if(qptr->front == MAXQUEUE-1) qptr->front=0; else qptr->front++; return qptr->items[qptr->front]; }

Conceptual and Physical Queue Implementations

Queue Data Structure

Enqueue Examples

Dequeue Examples

You might also like