Lect 7.0 Linked list and Stack

advertisement
CSI 312: Data Structures
Linked Lists, Stacks and Queues
Dr. Yousef Qawqzeh
Data Structure
• A construct that can be defined within a
programming language to store a
collection of data
– one may store some data in an array of
integers, an array of objects, or an array of
arrays
7/1/2016
Abstract Data Type (ADT)
• Definition: a collection of data together
with a set of operations on that data
– specifications indicate what ADT
operations do, but not how to implement
them
– data structures are part of an ADT’s
implementation
• Programmer can use an ADT without
knowing its implementation.
7/1/2016
Typical Operations on Data
• Add data to a data collection
• Remove data from a data collection
• Ask questions about the data in a data
collection. E.g., what is the value at a
particular location, and is x in the
collection?
7/1/2016
Why ADT
•
•
•
•
•
Hide the unnecessary details
Help manage software complexity
Easier software maintenance
Functionalities are less likely to change
Localised rather than global changes
7/1/2016
Illustration
7/1/2016
Linked Lists
Lists
• List: a finite sequence of data items
a1, a2, a3, …, an
• Lists are pervasive in computing
– e.g. class list, list of chars, list of events
• Typical operations:
–
–
–
–
–
–
–
7/1/2016
Creation
Insert / remove an element
Test for emptiness
Find an item/element
Current element / next / previous
Find k-th element
Print the entire list
Array-Based List Implementation
• One simple implementation is to use arrays
– A sequence of n-elements
• Maximum size is anticipated a priori.
• Internal variables:
–
–
–
–
Maximum size maxSize (m)
Current size curSize (n)
Current index cur
Array of elements listArray
listArray
cur
curSize
n
7/1/2016
a 1 a2 a3
an
0
n-1
1
2
unused
m
Inserting Into an Array
• While retrieval is very fast, insertion and
deletion are very slow
– Insert has to shift upwards to create gap
Example : insert(2, it, arr)
Size
arr
8
a 1 a 2 a3 a 4 a 5 a 6 a 7
a8
Step 2 : Write into gap
Size
9
8
Step 3 : Update Size
7/1/2016
Step 1 : Shift upwards
arr
a1 a2 it
a3 a4 a5 a6 a7
a8
Coding
typedef
int
int
int
} LIST
struct {
arr[MAX];
max;
size;
void insert(int j, int it, LIST *pl)
{ // pre : 1<=j<=size+1
int i;
for (i=pl->size; i>=j; i=i-1)
// Step 1: Create gap
{ pl->arr[i+1]= pl->arr[i]; };
pl->arr[j]= it;
}
7/1/2016
// Step 2: Write to gap
pl->size = pl->size + 1; // Step 3: Update size
Deleting from an Array
• Delete has to shift downwards to close gap of
deleted item
Example: deleteItem(4, arr)
size
9
arr
a1 a2 it a3
a4 a 5 a6 a7
a8
Step 1 : Close Gap
size
98
arr
a1 a2 it a3 a5 a6 a7 a8 a8
Step 2 : Update Size
7/1/2016
Not part of list
Coding
void delete(int j, LIST *pl)
{
// pre : 1<=j<=size
for (i=j+1; i<=pl->size; i=i+1)
// Step1: Close gap
{ pl->arr[i-i]=pl->arr[i]; };
// Step 2: Update size
pl->size = pl->size - 1;
}
7/1/2016
Linked List Approach
• Main problem of array is the slow deletion/insertion since it
has to shift items in its contiguous memory
• Solution: linked list where items need not be contiguous
item
next
with nodes of the form
ai
• Sequence (list) of four items < a1,a2 ,a3 ,a4 > can be
represented by:
head
represents
null
a1
7/1/2016
a2
a3
a4
Pointer-Based Linked Lists
• A node in a linked list is usually a struct
struct Node
A node
{ int item
Node *next;
}; //end struct
• A node is dynamically allocated
Node *p;
p = malloc(sizeof(Node));
7/1/2016
Pointer-Based Linked Lists
• The head pointer points to the first node
in a linked list
• If head is NULL, the linked list is empty
– head=NULL
• head=malloc(sizeof(Node))
7/1/2016
A Sample Linked List
7/1/2016
Traverse a Linked List
• Reference a node member with the ->
operator
p->item;
• A traverse operation visits each node in
the linked list
– A pointer variable cur keeps track of the
current node
for (Node *cur = head;
cur != NULL; cur = cur->next)
x = cur->item;
7/1/2016
Traverse a Linked List
The effect of the assignment cur = cur->next
7/1/2016
Delete a Node from a Linked List
• Deleting an interior/last node
prev->next=cur->next;
• Deleting the first node
head=head->next;
7/1/2016
Delete a Node from a Linked List
Deleting a node from a linked list
Deleting the first node
7/1/2016
Insert a Node into a Linked List
• To insert a node between two nodes
newPtr->next = cur;
prev->next = newPtr;
Inserting a new node
into a linked list
CSI 312
Insert a Node into a Linked List
• To insert a node at the beginning of a
linked list
newPtr->next = head;
head = newPtr;
Inserting at the beginning
of a linked list
Stacks
What is a Stack?
• A stack is a list with the restriction that
insertions and deletions can be performed in
only one position, namely, the end of the list,
called the top.
• The operations: push (insert) and pop (delete)
push(o)
pop
Top
7/1/2016
3
2
7
6
Stack ADT Interface
• The main functions in the Stack ADT are (S is the stack)
boolean isEmpty();
// return true if empty
boolean isFull(S);
// return true if full
void push(S, item);
// insert item into stack
void pop(S);
// remove most recent item
void clear(S);
// remove all items from stack
Item top(S);
// retrieve most recent item
Item topAndPop(S);
// return & remove most recent item
7/1/2016
Sample Operation
Stack S = malloc(sizeof(stack));
push(S, “a”);
s
push(S, “b”);
push(S, “c”);
d
top
a
push(S, “e”);
b
pop(S);
c
d=top(S);
pop(S);
7/1/2016
Implementation by Linked Lists
• Can use a Linked List as implementation of stack
StackLL
lst
Top of Stack = Front of Linked-List
LinkedListItr
head
a1
7/1/2016
a2
a3
a4
Code
struct Node {
int element;
Node * next;
};
typedef struct Node * STACK;
7/1/2016
More code
7/1/2016
More Code
7/1/2016
Implementation by Array
• use Array with a top index pointer as an implementation of stack
StackAr
arr
0
1
2
3
4
A
A
B
C
D E
5
top
7/1/2016
6
F
7
8
9
Code
7/1/2016
More code
7/1/2016
More code
7/1/2016
Effects
7/1/2016
Applications
• Many application areas use stacks:
– line editing
– bracket matching
– postfix calculation
– function call stack
7/1/2016
Line Editing
• A line editor would place characters read into a
buffer but may use a backspace symbol (denoted by
) to do error correction
• Refined Task
– read in a line
– correct the errors via backspace
– print the corrected line in reverse
Input
: abc_defgh2klpqrwxyz
:
abc_defg2klpwxyz
Reversed Output :
zyxwplk2gfed_cba
Corrected Input
7/1/2016
The Procedure
• Initialize a new stack
• For each character read:
– if it is a backspace, pop out last char
entered
– if not a backspace, push the char into
stack
• To print in reverse, pop out each char for
output
Input : fghryz
r
z
h
g
y
Corrected Input :
fyz
f
Reversed Output :
zyf
Stack
7/1/2016
Bracket Matching Problem
• Ensures that pairs of brackets are properly matched
• An Example:
{a,(b+f[4])*3,d+f[5]}
• Bad Examples:
7/1/2016
(..)..)
// too many closing brackets
(..(..)
// too many open brackets
[..(..]..)
// mismatched brackets
Informal Procedure
Initialize the stack to empty
For every char read
if open bracket then push onto stack
if close bracket, then
return & remove most recent item
from the stack
if doesn’t match then flag error
if non-bracket, skip the char read
Example
{a,(b+f[4])*3,d+f[5]}
[
]
([ ])
{
}
Stack
7/1/2016
Postfix Calculator
• Computation of arithmetic expressions can be efficiently
carried out in Postfix notation with the help of a stack.
Infix
Prefix
Postfix
- arg1 op arg2
- op arg1 arg2
- arg1 arg2 op
postfix
infix
(2*3)+4
2 3 * 4 +
2*3+4
2*(3+4)
7/1/2016
2 3 4 + *
Informal Procedure
Initialise stack S
For each item read.
If it is an operand,
push on the stack
If it is an operator,
pop arguments from stack;
perform operation;
push result onto the stack
Expr
2
3
4
+
*
7/1/2016
push(S, 2)
push(S, 3)
push(S, 4)
arg2=topAndPop(S)
arg1=topAndPop(S)
push(S, arg1+arg2)
arg2=topAndPop(S)
arg1=topAndPop(S)
push(S, arg1*arg2)
4
3+4=7
3
2*7=14
2
Stack
Summary
• The ADT stack operations have a lastin, first-out (LIFO) behavior
• Stack has many applications
– algorithms that operate on algebraic
expressions
– a strong relationship between recursion
and stacks exists
• Stack can be implemented using arrays
or linked lists
7/1/2016
Queues
What is a Queue?
• Like stacks, queues are lists. With a queue,
however, insertion is done at one end whereas
deletion is done at the other end.
• Queues implement the FIFO (first-in first-out)
policy. E.g., a printer/job queue!
• Two basic operations of queues:
– dequeue: remove an item/element from front
– enqueue: add an item/element at the back
dequeue
7/1/2016
enqueue
Queue ADT
• Queues implement the FIFO (first-in first-out)
policy
– An example is the printer/job queue!
enqueue(o)
dequeue()
isEmpty()
getFront()
7/1/2016
createQueue()
Sample Operation
Queue *Q;
enqueue(Q, “a”);
q
enqueue(Q, “b”);
enqueue(Q, “c”);
d=getFront(Q);
dequeue(Q);
enqueue(Q, “e”);
dequeue(Q);
7/1/2016
d
back
front
a b c e
Queue ADT interface
• The main functions in the Queue ADT are (Q is
the queue)
void enqueue(o, Q)
// insert o to back of Q
void dequeue(Q);
// remove oldest item
Item getFront(Q);
// retrieve oldest item
boolean isEmpty(Q);
// checks if Q is empty
boolean isFull(Q);
// checks if Q is full
void clear(Q);
// make Q empty
}
7/1/2016
Implementation of Queue
(Linked List)
• Can use LinkedListItr as underlying implementation of Queues
Queue
lst
addTail
LinkedList
head
tail
a1
7/1/2016
a2
a3
a4
Code
struct Node {
int element;
Node * next;
};
struct QUEUE {
Node * front;
Node * rear;
};
7/1/2016
More code
7/1/2016
More code
CELL is a list node
7/1/2016
Implementation of Queue
(Array)
• use Array with front and back pointers as implementation of
queue
Queue
arr
0
A
front
7/1/2016
1
2
3
4
5
6
B
C
D
E
F
G
7
8
9
back
Circular Array
•
To implement queue, it is best to view arrays as circular structure
0
A
1
2
3
4
5
6
B
C
D
E
F
G
7
8
9
back
front
front
0
9
Circular view of arrays.8
A
back
1
B
C
2
7
G
D
F E
3
6
5
7/1/2016
4
How to Advance
• Both front & back pointers should make advancement until they
reach end of the array. Then, they should re-point to beginning
of the array
front = adv(front);
back = adv(back);
int adv(int p)
{ int r = p+1;
if (r<maxsize) return r;
else return 0;
}
upper bound of the array
7/1/2016
Alternatively, use modular arithmetic:
int adv(int p)
{ return ((p+1) % maxsize);
}
mod operator
Sample
Queue *Q;
enqueue(Q, “a”);
Q
enqueue(Q, “b”);
enqueue(Q, “c”);
dequeue(Q);
dequeue(Q);
enqueue(Q, “d”);
enqueue(Q, “e”);
dequeue(Q);
7/1/2016
F=front
B=back
d
a
e
b
c
F
F
F
F
B
B
B
B
Checking for Full/Empty State
What does (F==B) denote?
Queue
Empty
State
size
e f c d
F
F
B
0
B
size
4
Alternative - Leave a Deliberate Gap!
No need for size field.
Full Case : (adv(B)==F)
7/1/2016
e
c d
B F
Queue
Full
State
Summary
• The definition of the queue operations
gives the ADT queue first-in, first-out
(FIFO) behavior
• The queue can be implemented by
linked lists or by arrays
• There are many applications
– Printer queues,
– Telecommunication queues,
– Simulations,
– Etc.
7/1/2016
Download