data structures - part ii

28
1 Data Structures - Part II CS215 Lecture #8

Upload: medea

Post on 05-Jan-2016

43 views

Category:

Documents


1 download

DESCRIPTION

Data Structures - Part II. CS215 Lecture #8. Stacks. Last-In-First-Out (LIFO) Stacks are often used in programming when data will need to be used in the reverse order A stack has two operations: push (places a new item at the top of the stack) pop (retrieves the top item from the stack). - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Data Structures - Part II

1

Data Structures - Part II

CS215 Lecture #8

Page 2: Data Structures - Part II

Stacks

Last-In-First-Out (LIFO) Stacks are often used in

programming when data will need to be used in the reverse order

A stack has two operations: push (places a new item at the top of

the stack) pop (retrieves the top item from the

stack)

Page 3: Data Structures - Part II

Stack Implementation

A stack can be implemented in several ways, e.g., by an array or by a linked list.

A stack pointer is a variable that identifies the beginning of the part of the array that is currently unused

A stack pointer variable, therefore, holds an address.

Page 4: Data Structures - Part II

Declaring a Stack

stack: .word 0:maxstacksize

sp: .word stack

or

stack: .word 0:maxstacksize

sp: .word

. . .

la sp, stack

sp uses the addressbound to the label stack

as the initial value (staticinitialization)

dynamic initialization

Page 5: Data Structures - Part II

Some variations to the implementation In some implementations, a stack pointer

points to the top of the stack In our sample implementation, the stack

pointer points to the next available space we can push an element into

A stack can be grown upward or downward, i.e., we can either add a value to the stack pointer or subtract a value from it when pushing an element

Page 6: Data Structures - Part II

Pushing an element unto the stack

This operation is called push.

move M[sp],x

add sp,sp,4

Page 7: Data Structures - Part II

Example 16.1

sp

initially

sp

move M[sp],20add sp,sp,4

20

Page 8: Data Structures - Part II

Example 16.2

20 5 move M[sp],5add sp,sp,4

sp

sp

move M[sp],10 add sp,sp,4

20 5 10

Page 9: Data Structures - Part II

Taking an item off the stack

This operation is called pop.

add sp,sp,-4

move x,M[sp]

Page 10: Data Structures - Part II

Example 16.3

sp

initially20 5 10

sp

add sp,sp,-4 move x,M[sp]

20 5 10

Note: popping the stack means moving back the pointer to the next available space. There is no need to explicitly delete the data. It will

get overwritten in the next push.

Page 11: Data Structures - Part II

Full and Empty Stack

SAL does not provide any form of boundary check, i.e., there is no automatic feature that detects whether an element is “pushed” beyond the stack’s capacity

A robust program must check before a push whether the stack is full.

It should also check whether the stack is empty before a pop.

Page 12: Data Structures - Part II

Example 16.4

P.187 textbook

.data

stack: .byte 0:50

sp: .word stack #static initialization

bottom: .word stack

bias: .word 48

top: .word

number: .word

digit: .word

push_error: .asciiz “Full stack failure “

pop_error: .asciiz “Empty stack failure “

Page 13: Data Structures - Part II

Example 16.4

P.187 textbook

add top,bottom,50

loop_top: rem digit,number,10

add digit,digit,bias

bge sp,top,bad_push #check if full

move m[sp],digit

add sp,sp,1

div number,number,10

bgtz number,loop_top

bad_push: puts push_error

done

Page 14: Data Structures - Part II

Example 16.5

P.187 textbook

print_it: blt sp,bottom,bad_pop #empty check

add sp,sp,-1

putc m[sp]

bgt sp,bottom,print_it

done

bad_pop: puts pop_error

done

Page 15: Data Structures - Part II

Queues

A queue is a data structure that maintains a “first-in first-out” (FIFO) ordering.

In contrast, a stack maintains a “last-in first-out” (LIFO) ordering.

A queue adds new elements at the end. An element can only be removed at the front.

This is an abstraction of the “first-come first-served” practice.

Page 16: Data Structures - Part II

Queue operations

A queue has two operations: enqueue dequeue

An enqueue operation adds new elements at the end of the queue or its tail. This is similar to the stack operation push; only that push now is done at the end of the array instead of at the front (or top).

A dequeue operation removes an element from the front of the array or its head.

Page 17: Data Structures - Part II

Implementation

A queue can be implemented using an array.

A naïve implementation will allow the enqueued data to “walk” through the array.

tailhead

Page 18: Data Structures - Part II

A circular queue

An array can be reused by allowing the enqueued data to “walk around” the array. This type of implementation is called a circular queue.

tailhead

Page 19: Data Structures - Part II

The particular implementation that will be illustrated here uses an empty element. This will simplify the check for a full or empty queue.

If the queue is empty, the dequeue operation must not return an invalid element.

If the queue is full, the enqueue operation must not destroy an element already in the queue.

Page 20: Data Structures - Part II

Adding elements (Enqueue)

To add one element, we simply add 1 to the the current value of the tail, then execute:

add address,base,tail move m[address],new_element #copy element into

array0 1

0 1 2

tailhead

B

B = blank cell

Page 21: Data Structures - Part II

Removing Elements (Dequeue)

To delete one element, add 1 to the current value of head then we execute

add address,base,head move element,m[address] #copy it to element

tailhead

0 1 2

B

0 1 2

B

Page 22: Data Structures - Part II

Detecting an Empty Queue

During a dequeue, the first thing that is done is to check whether (head == tail). If this is true, then the queue is empty.

tailhead

0 1 2

B

0 1 2

B

not empty

empty

Page 23: Data Structures - Part II

Detecting a Full Queue

Before an enqueue is done, the tail is incremented by 1. If after the increment (head == tail) then the queue is full.

0 1 2

B

0 1 2

B

tailhead

before increment

after increment

full queuedetected

Page 24: Data Structures - Part II

Making the address circular

Suppose we have the array

To make the address 4 equal to the address 0 we simply use modulo arithmetic, i.e., 4 modulo 4 = 0.

0 1 2 3 4

Page 25: Data Structures - Part II

Using modulo arithmetic maps any address to an address within the allocated space, thus preventing access to out-of-the-range addresses

Also, the modulo conveniently gives us the offset from the base address.

We need the offset from the base address to access specific elements in the queue.

Page 26: Data Structures - Part II

Example 17.1

.data

queue: .byte 0:4

queueaddr: .word

head: .word

tail: .word

linenumber: .byte

nextline: .byte

addr: .word

newline: .byte

string1: .asciiz "Which line is ringing ?"

string2: .asciiz "The next line to be answered is "

string3: .asciiz "Enqueueing line "

empty: .asciiz "No calls waiting "

full: .asciiz "ERROR: Queue is full. Exiting program. "

Page 27: Data Structures - Part II

Example 17.2

.text

__start: la queueaddr,queue

loop: puts string1

get linenumber

beq linenumber,'\n',dequeue

get newline #reads the second character

enqueue: add tail,tail,1

rem tail,tail,4 #uses modulo beq tail,head,full_queue

puts string3

put linenumber

put '\n'

add addr,queueaddr,tail

move m[addr],linenumber

b loop

Page 28: Data Structures - Part II

Example 17.3

dequeue: beq head,tail,empty_queue

add head,head,1

rem head,head,4 #uses modulo add addr,queueaddr,head

move nextline,m[addr]

puts string2

put nextline

put '\n'

b loop

empty_queue: puts empty

put '\n'

b loop

full_queue: puts full

done