You are on page 1of 90

List, Stack, Queue

04/17/12

List
It is about putting things in a sequence. Example: A1,A2,A3,,An

first

last

04/17/12

Find find a specified member. Insert insert a new member at a specified position. findKth return the kth element. Remove remove a specified element from list. Head return the first member. Tail return the list without its first member. Append combine 2 lists.
3

What can we do with a list

04/17/12

What if we create a list from an that an array needs us to specify its array? Do not forget
length. Find -> O(n) Because we need to search from the first element of the list. findKth O(1) We can use index to find the kth element directly. Insert and remove may take a long time Because all members may be shifted.

04/17/12

Linked list
A1 node

A2

A3

04/17/12

Find -> O(n) because we still need to start at the biginning of the list. findKth(i) -> O(i) Because we cant use array index any more.

Deletion is easier (no need to shift members) We only need to point reference over to the next node.

Linked list (cont.)

The original list


A1

A2

A3

When A2 is removed.
A1 A2 A3

04/17/12

Insertion is also similar.


The original list A1 A2

Linked list (cont 2.)


A3

After inserting x between A2 and A3.


A1 A2 A3

x
04/17/12 7

Insert -> a small problem

Inserting the first member is different from inserting others.


No other node pointing to x. Need the former A1 reference to point to x.

A1 x

A2

A3

The code needs to be different from other insertions.


04/17/12 8

We can avoid such special case.header) at the front of the list. We have a dummy node (or

With this solution, every node will have a node in front, therefore all codes will be the same.

A1 header

A2

A3

Empty list header


04/17/12 9

class ListNode { // Constructors ListNode( Object theElement ) { this( theElement, null ); }

Code: node

theElement

ListNode( Object theElement, ListNode n ) { theElement element = theElement; next = n; 04/17/12 }

Point to n.
10

// Friendly data; accessible by other package routines Object element; ListNode next; } Instance variables

04/17/12

11

List iterator

Is an object pointing to a node we are interested in. Why do we have to write this class separate from list?
We

can keep an interested node in our list anyway, right? we use iterator, we can keep a general form of list separate from any interested node.
12

Its because
If

04/17/12

Code: iterator public class LinkedListItr


{ ListNode current; /** * @param theNode any //interested position

node in the list

*/ LinkedListItr( ListNode theNode ) { current = theNode; }


04/17/12 13

/** see if current has passed the last element of the list. * @return true if current is null */ public boolean isPastEnd( ) { return current == null; } /** * @return item stored in current, or null if * current is not in a list. */ public Object retrieve( ) { return isPastEnd( ) ? null : current.element; } 04/17/12

14

/** * move current to the next position in the list. * If current is null, do nothing. */ public void advance( ) { if( !isPastEnd( ) ) current = current.next; }

04/17/12

15

Code: linked list


public class LinkedList { private ListNode header; public LinkedList( ) { header = new ListNode( null ); } public boolean isEmpty( ) { return header.next == null; }
04/17/12 16

/** make the list empty.*/ public void makeEmpty( ) { header.next = null; } /** * return iterator that points to the header node. */ public LinkedListItr zeroth( ) { return new LinkedListItr( header ); }

04/17/12

17

/* return iterator that points to the node next to header (can be null if the list is empty.)*/ public LinkedListItr first( ) { return new LinkedListItr( header.next ); } /** insert a new node following the position pointed to by p. * @param x item to be in the new node. * @param p iterator of the position before the new node. */ public void insert( Object x, LinkedListItr p ) { if( p != null && p.current != null ) p.current.next = new ListNode( x, p.current.next ); 04/17/12} 18

/** * @param x object that we want to find. * @return iterator that points to the first node that has x. *If x is not in the list, the iterator points to null. * */ public LinkedListItr find( Object x ) { /* 1*/ ListNode itr = header.next; /* 2*/ /* 3*/ /* 4*/ }
04/17/12 19

while( itr != null && !itr.element.equals( x ) ) itr = itr.next; return new LinkedListItr( itr );

/** * return iterator that points to a node before the first *node that has x. If there is no x in the list, return iterator *that points to the last node in the list. */ public LinkedListItr findPrevious( Object x ) { /* 1*/ ListNode itr = header; /* 2*/ /* 3*/ /* 4*/ }
04/17/12 20

while( itr.next != null && !itr.next.element.equals( x ) ) itr = itr.next; return new LinkedListItr( itr );

/** * remove the first node with x from the list. * @param x is the item to be removed from the list. */ public void remove( Object x ) { LinkedListItr p = findPrevious( x ); if( p.current.next != null ) //mean x is found because // p is not the last member. p.current.next = p.current.next.next; //move reference //over x }
04/17/12 21

public static void printList( LinkedList theList ) { if( theList.isEmpty( ) ) System.out.print( "Empty list" ); else { LinkedListItr itr = theList.first( ); for( ; !itr.isPastEnd( ); itr.advance( ) ) System.out.print( itr.retrieve( ) + " " ); } System.out.println( ); }
04/17/12 22

Doubly linked list


A1 A2 A3

Node has extra instance variable:


Previous : point to the node in front. This works the same way as next, but pointing in a different direction. We can search both ways. Additional time to change pointers.

04/17/12

23

Insert: doubly linked list


P

A1

A2

A3

2 4

3 1

newnode

04/17/12

24

Remove: doubly linked list

A1

A2

A3

04/17/12

25

Circular Linked list


A1 A2 A3

Last node points to the first node. no dummy node needed. We can even make it into a doubly linked list.

04/17/12 26

linked list example

Let us want to store a polynomial

a x
i =0 i

We can use array, using index i to i store the coefficient of x


a0 a1 a2

04/17/12

27

Using array to store polynomial


When adding polynomials
a0 a1 a2

a0

a1

a2

The answer comes from the addition of corresponding slots, as shown.


28

04/17/12

Using array to store polynomial (2)


multiplying two polynomial
a0 a1 a2

a0

a1

a2

Each slot multiplies every slot of the other polynomial, then all results are added. If there are many terms with 0 coefficient, there will be so many multiplication with 0. Waste of time.
04/17/12

29

Reduce the number of 0. Save space. Example: 5x75+11x125+8

use linked list instead

5 75 header

11 125

8 0

coefficient
04/17/12

Power of x
30

Skip list

A node can have more than one next pointers. The extra pointers point to other parts of the list.
8 5 2 6 122 15

In this example, every node has a pointer to next.

A node in a position that is divisible by two will also have a pointer pointing to the next node with that quality. 04/17/12 Same for a node in a position divisible by four.

31

Skip list problem

Inserting and removing an element will cause all pointers structure to be changed.
Too hard to do. Usually only the number of pointers for each level is enforced.

Example: a 20 node list.


Level 0 > 20 nodes Level 1 > 10 nodes Level 2 -> 5 nodes Level 3 -> 2 nodes

04/17/12

32

The number of nodes in the example:


Level 3 -> 2 nodes Level 2 -> 5-2 = 3 nodes Level 1 -> 10-2-3 = 5 nodes Level 0 -> 20-5-3-2 = 10 nodes

Skip list problem (cont)

When adding a new node, random a number between 1 and 20.


1 to 10 -> add the node with link level 0. 11 to 15 -> add the node with link level 1. And so on.

04/17/12

33

Put the data just viewed in front of the list, or Swap the node just viewed with a node in front, or Putting elements according to access frequency, or Use a specific ordering scheme, such as alphabetically ordered.
Good for searching. If we cannot find an element within a certain number of steps, we will know that the element is not in a list.

Self-Organizing List

04/17/12

34

Self-Organizing List(cont.)

Adam Drozdek (he has a book on data structure) found that


Putting the most recently viewed data in front of a list yields the same speed as ordering the list by data access frequency. Faster than

swapping

the node just viewed with a node in front. Using a specific ordering scheme.

04/17/12

35

Example: data of all students and all subjects taught by our university. We must be able to: Find all subjects a particular student is taking. Find all students enroll in a particular subject. We can use a 2D array to create a table of students and subjects. But there will be lots of empty spaces. A medical student and an engineering student surely enroll in different subjects. We can fix this problem by making a 2D list.
36

Multilist or Sparce Matrix

04/17/12

Student 1

Subj 1 2

04/17/12

37

B A C

graph
A A B C D E D B C D E

B E A C B D E

Sparce table

Node directory
38

04/17/12

stack

A B C

Are divided into levels. We can only insert and remove things one way. (LIFO = last in, first out) What can we do: Push put an object at the top. Pop remove the top most element. Top return the top element without removing anything.
39

04/17/12

Making a stack from list


Push = insert new object next to header. Pop = remove object next to header. If the list is originally empty, we can

Do

nothing, or throw exception.

Top = return an element in the node next to header.


40

04/17/12

Stack code

Modified from linked list For simplicity, we do not have a header in this example. We can make a stack even though we do not have header.
public class StackFromLinkedList {

private ListNode top; public StackFromLinkedList( ){ top = null; } 04/17/12

41

/** * @return always return false. */ public boolean isFull( ) { return false; } /** * @return true if stack is empty, otherwise return false. */ public boolean isEmpty( ) { return top == null; }
04/17/12 42

public void makeEmpty( ) { top = null; } /** * @return top of stack, or null if empty. */ public Object top( ) { Top does not change stack. if( isEmpty( ) ) return null; Can choose to throw exception. return top.element; }
04/17/12 43

/** * remove element on top of stack. * @exception Underflow if stack is empty. */ public void pop( ) throws Underflow { Can choose to do nothing. if( isEmpty( ) ) throw new Underflow( ); top = top.next; }

Just moving the pointer over.


04/17/12 44

/** * top() and pop() * @return popped item, or null if the stack is empty. */ public Object topAndPop( ) { Can choose to throw exception. if( isEmpty( ) ) return null; Object topItem = top.element; top = top.next; return topItem; }
04/17/12 45

/** * put new element on top of stack. * @param x element we want to put in stack. */ public void push( Object x ) { top = new ListNode( x, top ); }

New node
New top points to old top.
04/17/12

Old node

46

Stack weakness

When popped out, an element disappear forever. We need to keep elements in extra variables, or another stack.

04/17/12

47

Creating stack with array

Do not forget that we need to specify array size. Let a stack have arrayBody topIndex index of the top element. (-1 if the stack is empty.)

04/17/12

48

public class StackFromArray { private Object [ ] arrayBody; private int topIndex; static final int DEFAULT_CAPACITY = 10; public StackFromArray( ) { this( DEFAULT_CAPACITY ); }

Code: stack made from array

04/17/12

49

/** * create a stack, specifying its capacity. * @param capacity number of elements the * stack can hold. */ public StackFromArray( int capacity ) { arrayBody = new Object[ capacity ]; topIndex = -1; }

04/17/12

50

public boolean isEmpty( ) { return topIndex == -1; } public boolean isFull( ) { return topIndex == arrayBody.length - 1; } public void makeEmpty( ) { topIndex = -1; } 04/17/12

51

public Object top( ) { if( isEmpty( ) ) return null; return arrayBody[ topIndex ]; }

Can choose to throw exception.

/** * remove top element from stack. * @exception Underflow if the stack is empty. */ public void pop( ) throws Underflow Then move index { if( isEmpty( ) ) throw new Underflow( ); arrayBody[ topIndex-- ] = null; }
04/17/12

Set to null

52

/** * Remove top element from stack and return that element. * @return object on top of stack or null if the stack is

empty.
*/ public Object topAndPop( ) Can choose to throw exception. { if( isEmpty( ) ) return null; Object topItem = top( ); arrayBody[ topIndex- - ] = null; return topItem; }
53

04/17/12

/**

* put x in stack if the stack is not full * @param x object to put on top of tack. * @exception Overflow if the stack is full. */
public void push( Object x ) throws Overflow { if( isFull( ) ) throw new Overflow( ); arrayBody[ ++topIndex ] = x; } move index and then put x in.

}
04/17/12

54

Using stack (1)

Balancing check
Check bracket pair. Read program text.

If

see ( , put it in stack. If see ), pop top of stack. Print error if do not find ( in stack when reading ).

When finish, if stack is not empty -> error too.

04/17/12

55

Using stack (2)

Postfix expression (reverse polish)


[7+(8*9)+5]*10 = 7 8 9 * 5 + + 10 * We can use stack to evaluate a postfix expression:

Read

a number -> push to stack. Read an operator -> pop numbers in the stack and use the operator on the numbers. 9 8 7
04/17/12

Example: reading the first three numbers.


56

When reading * Pop two numbers, multiply. 9 8 7 Then read 5 in normally. 5 72 7 72 7

put the result back in stack.

read +, pop the top two and add them. 5 72 7 77 7

04/17/12

57

The same for the second +. 77 7 Reading 10 normally. 10 84

84 When reading *, pop the top two and * them. 10 84

840 answer

04/17/12

58

Using stack (3)

Change infix to postfix


Operand -> output it right away. operator -> keep it on stack. Keep ( on stack too. When reading )-> pop and output continuously until we find ). Lets see an example.

04/17/12

59

a+b*c+(d*e+f)*g
read a,+,b -> put a and b in output. Put + on top of stack. + ab

read * and read c -> put * on top of stack. Put c in output. * + abc

read + -> must pop equal (or more) priority operator out to output, before we push the + on top of stack. +
04/17/12

abc*+
60

new

read ( and d -> put ( into stack, waiting for ). We put d to output. ( + Then, reading * and e. * ( +

abc*+d

abc*+de + pushed in after popping equal (or more) priority operators.

Next, + and f * ( +
04/17/12

abc*+de*f
61

Next is ) -> pop everything up to (. + ( + Pop abc*+de*f+

Next are * and g -> push * into stack. Put g to output. * +

abc*+de*f+g

No more input, we pop everything on stack to output. abc*+de*f+g*+


04/17/12 62

Using stack (4)


Change infix to prefix If reading a number from input:

Put that number in our operand stack. If operator stack is empty, push it in. If the operator is (, push it in the operator stack. If the operator has more priority than the operator on top of the operator stack, push it in the operator stack. 63

If reading an operator:
1. 2.

3.

04/17/12

4.

If the operator has equal or less priority than the operator on top of the stack:

Pop an operator from the operator stack. Pop operands used by popped operators from the operand stack. Put the operator first, followed by the operands. The latest one is put first. Put the result in the operand stack.

If the operator is ), or if we cannot read from input any further, follow step 4 until the top of the operand stack becomes (. Then pop that ( out.
64

04/17/12

b+sqrt(b*x d*a*c)/ (e*a)


First, read ,b. put each one in its stack. Operand stack

Operator stack

read +. Because + has equal priority to (which is on the operator stack), we need to pop out and put - with its operand.

-b

04/17/12

65

Then read sqrt and (. Sqrt is just like a method. Therefore it has more priority than other operations. We push it in stack. We also put ( in stack.

-b

( sqrt +

Next are b, *, x. we can push all of them.

x b -b

* ( sqrt +
66

04/17/12

Next is . Because is less important than *, we must pop * out and work with it.

*bx -b

( sqrt +

Then read d, *, a. * is more important than -, therefore we can push it in stack. We can also push d and a.

a d *bx -b
04/17/12

* ( sqrt +
67

Next we read *. This time another * is on top of the stack. We then must pop stack and push result back.

*da *bx -b

* (new) ( sqrt +

Then read c and push it (no drawing this time).

04/17/12

68

Then read ). Pop stack and arrange operators and operands until we find (. Then remove (.

**dac *bx -b
Then pop out.

( sqrt + sqrt +

*bx**da -b c sqrt -b *bx**dac 04/17/12

Then read / -> less priority than sqrt. Therefore we pop sqrt to work.

/ +

69

Then read ( and e. Push them.

e sqrt *bx**dac -b

( / +
Then read * and a. Push them.

a e sqrt *bx**dac -b

* ( / +

04/17/12

70

Then read ). Pop * to work and remove the bracket.

*ea sqrt *bx**dac -b

/ +

Now we finish input reading. We then pop operators to work with operands. First, pop /.

/ sqrt *bx**dac*ea -b + -b/ sqrt *bx**dac*ea


04/17/12

Then pop +. The overall result is on the operand stack.

71

Using stack (5)

Store method call data


Local variables of a method must be stored independently, to prevent name clash with variables in other methods. Must store the return point of a method. We can create a stack to store a method data.

activation

record or stack frame

04/17/12

72

method1(){ method2(); } method2(){ method3(); } method3(){ } main (){ method1(); }


04/17/12 73

top method3s info method2s info method1s info

There is a form of recursion which wastes stack. It is called tail recursion.

Careful with method

recursive call on the last line of a method.

myAlgo(ListNode p){ if (p == null) return; //do something myAlgo(p.next); } For each call, it just call another method without. Each stack will not contain any data- a waste.
04/17/12 74

fixing tail recursion


Let compiler handle it or Write a loop instead.


myAlgo(ListNode p){ while(true){ if (p == null) return; //do something p = p.next; } }

04/17/12

75

Queue

It is a list. But we can put things in at the back only (enqueue). And we can remove things from the front only (dequeue). We can implement queue using

A modified list array

4 front

6 back

04/17/12

76

Enqueue and dequeue for queue built from array (1)

enqueue(x)
size++ back++ theArray[back] = x

dequeue()
size- front++

04/17/12

77

Enqueue and dequeue for queue built from array (2)


Be careful.
8 4 3 6 7 10

back front Cannot Enqueue even though there are spaces at the front.

Fix it by making the index go round.


8 back 4 3 6 7 front
78

10

04/17/12

Enqueue and dequeue for queue built from array (3)

when back = front-1, a queue can be either empty or full.

Therefore we have size.

Fix error when


Adding an item to a full queue. Dequeue an empty queue.

04/17/12

79

public class QueueArray{ private Object [ ] theArray; private int size; private int front; private int back; static final int DEFAULT_CAPACITY = 10; public QueueArray( ) { this( DEFAULT_CAPACITY ); } public QueueArray( int capacity ) { theArray = new Object[ capacity ]; makeEmpty( ); } 04/17/12

80

public boolean isEmpty( ) { return size == 0; } public boolean isFull( ) { return size == theArray.length; } public void makeEmpty( ) { size = 0; front = 0; back = -1; }
04/17/12 81

public Object getFront( ) { if( isEmpty( ) ) return null; return theArray[ front ]; }

Can throw exception.

/*return an item at the front of the queue, delete that item. Return null if the queue is empty.*/ public Object dequeue( ){ if( isEmpty( ) ) return null; Can throw exception. size--; Object frontItem = theArray[ front ]; theArray[ front ] = null; front = increment( front ); return frontItem; }
04/17/12 82

/** * put x at the back of queue. * @param x object to be put in the queue. * @exception Overflow if the queue is full. */ public void enqueue( Object x ) throws Overflow { if( isFull( ) ) throw new Overflow( ); back = increment( back ); theArray[ back ] = x; size++; }

04/17/12

83

/** * increment array index, allowing the index to go round *the array. * @param x array index, must be a legal index. * @return x+1, or 0 if x is the at the back of the array. */ private int increment( int x ) { if( ++x == theArray.length ) x = 0; return x; }

04/17/12

84

double-ended queue

insertFirst(Object o): put o at the front. insertLast(Object o): put o at the back. removeFirst(): remove the front element. removeLast(): remove the last element. first(): return the first element. last(): return the last element. size(): return the queue size. isEmpty(): test if the queue is empty.

04/17/12

85

stack size() isEmpty() top() push(x) pop()

double-ended queue

size() isEmpty() last() insertLast(x) removeLast()

04/17/12

86

queue size() isEmpty() getFront() enqueue(x) dequeue()

double-ended queue

size() isEmpty() first() insertLast(x) removeFirst()

04/17/12

87

Queue usage

printer
Jobs waiting at a printer can jump queue according to job priority. Supermarket queue simulation.

Used

queue simulation to decide whether to increase service size.

Call center queue.

04/17/12

88

Supermarket queue We can find an average waiting time.

payi ng
04/17/12

qu eu e
89

If customer come at time -> 30, 40, 60,110, 170 Waiting time for the 2nd customer.
Waiting time for the 3rd customer.
A11 A2 A3 D2 A4 D3 A5

1st customer paying

2nd customer paying

04/17/12

90

You might also like