4
4
https://yhyi15.github.io/teaching/DSA
1
In this Chapter, you will learn
2
Why Lists?
5
List ADT (Abstract Data Type)
template <typename E> class List {
public:
virtual void clear()=0; // clear all items
virtual void insert(E &item)=0;
virtual void append(E &item)=0;
virtual void E remove()=0;
virtual void moveToStart()=0;
virtual void moveToEnd()=0;
virtual void prev()=0;
virtual void next()=0;
virtual int length()=0;
virtual int currPos()=0;
virtual void moveToPos(int pos)=0;
virtual E getValue()=0;
};
6
List ADT Examples
8
Two physical implementations
Array-based lists
Linked lists
9
Represent a list with an array
10
Array-Based List Class (1)
template <typename E>
class Alist : public List<E> {
private:
private E *listArray; //array holding elements
private int maxSize; // max size of list
12
Array-Based List Class (3)
public void moveToPos(int pos) {
if( pos < 0 || pos >= listSize){
printf("Position out of range\n");
abort();
}
curr = pos;
}
public E getValue() {
assert( curr >= 0 && curr < listSize);
return listArray[curr];
}
13
Insert an element
14
Insert
/** Insert "it" at current position */
public void insert(E it) {
// List capacity exceeded
assert(listSize < maxSize );
for (int i=listSize; i>curr; i--)
listArray[i] = listArray[i-1];
listArray[curr] = it;
listSize++;
}
15
Append
public void append(E it) {
// Append "it“ at the end of the list
//List capacity exceeded
assert( listSize < maxSize);
listArray[ listSize ] = it;
listSize++;
}
16
Remove
/** Remove and return the current element */
public E remove() {
if ( curr < 0 || curr >= listSize)
return NULL;
E it = listArray[curr];
for(int i=curr; i<=listSize-2; i++)
listArray[i] = listArray[i+1];
listSize--;
return it;
}
17
Link Class
Dynamic allocation of new list elements.
// Singly-linked list node
template <typename E> class Link {
public:
E element; // Value for this node
Link *next; // Pointer to next node
Link(const E& elemval,
Link* nextval =NULL)
{ element = elemval; next = nextval; }
Link(Link* nextval =NULL)
{ next = nextval; }
};
18
Linked List Position-a naive approach
Curr points to the first node in the
right partition
Inserting an element is cumbersome
19
Linked List Position-A smart approach
Curr points to the last node in the
left partition
Add a head node
Eliminate special codes in the codes, such
as inserting an item in an empty list
20
The difference between array-based
lists and linked list
The memory addresses of the
elements in an array list are in
increasing order
Assume that the start address of the
array is 1,000
The addresses of elements 13, 12,
20, 8, 3 are 1,000, 1,004, 1,008,
1,012, and 1,016, respectively
The addresses of the elements
after current position increases by
4 with an insertion, if an int
varaible takes 4 bytes memory 21
The difference between array-based
lists and linked list (cont.)
The memory addresses of
the elements in a linked list
have no relationship with
their positions in the list
Allocated by the operating
system
e.g., the memory addresses of
20, 23, 12, 15 are 1,000, 940,
1076, 40
The addresses of the
elements already in the list
will not change after an 22
insertion
Linked List Class (1)
template <typename E>
class Llist : public List<E> {
private:
Link<E> * head; // pointer to list header
Link<E> * tail; // pointer to last element
Link<E> * curr; // access to current element
int cnt; // size of list
public:
//Constructors
Llist() {
curr = tail = head = new Link<E>(NULL);
cnt = 0;
}
23
Linked List Class (2)
public void clear() {
curr= head->next; //keep the head node
Link<E> *tmp;
while( curr != NULL){
tmp = curr;
curr = curr->next;
delete tmp;
}
head->next = NULL;
curr = tail = head;
cnt = 0;
}
~Llist(){
clear();
delete head; 24
}
Linked List Class (3)
public void moveToStart() { curr = head; }
public void moveToEnd() { curr = tail; }
public int length() { return cnt; }
public void next() {
if (curr != tail) { curr = curr->next; }
}
public E getValue() {
// Nothing to get;
assert(curr->next != NULL);
return curr->next->element;
}
25
Insertion
26
Insert/Append
// Insert "it" at current position
public void insert(E it) {
Link<E> *tmp = new Link<E>(it, curr->next);
curr->next = tmp;
if (tail == curr) tail = curr->next;
cnt++;
}
public void append(E it) {
tail->next = new Link<E>(it, NULL);
tail = tail->next;
cnt++;
}
27
Removal
28
Remove
/** Remove and return current element */
public E remove() {
// if no elements;
assert(curr->next != NULL);
if (tail == curr->next) tail = curr;
// tmp points to the node to be deleted
Link<E> *tmp = curr->next;
E it = tmp->element;
curr->next = tmp->next;
delete tmp;
cnt--;
return it; 29
}
Prev
/** Move curr one step left;
no change if already at front */
public void prev() {
if (curr == head) return;
Link<E> *tmp = head;
// March down list until we find the
// previous element
while (tmp->next != curr)
tmp = tmp->next;
curr = tmp;
}
30
Get/Set Position
/** Return position of the current element */
public int currPos() {
Link<E> *tmp = head;
int i;
for (i=0; tmp != curr; i++)
tmp = tmp->next;
return i;
}
/** Move down list to "pos" position */
public void moveToPos(int pos) {
// if position is out of range;
assert( pos>=0 && pos<cnt);
curr = head;
for(int i=0; i<pos; i++)
curr = curr->next; 31
}
Comparison of Implementations
Array-Based Lists:
Insertion and deletion are (n).
Prev and direct access are (1).
Array must be allocated in advance.
No overhead if all array positions are full.
Linked Lists:
Insertion and deletion are (1).
Prev and direct access are (n).
Space grows with number of elements.
Every element requires overhead.
32
Space Comparison
“Break-even” point:
DE = n(P + E);
n = DE
P+E
Solution
keep the nodes removed in a free list by
yourself, and do not call the system delete
Allocate a new node from the free list first if
there are some; otherwise, call the system new
Delete all nodes in the free list when we do not
need them
See the textbook for details
34
Doubly Linked Lists
Two pointers in each node
point to both next and previous nodes
35
Doubly linked list node
Template <typename E> class DLink{
public:
E element;
DLink* next;
DLink* prev;
//constructors
DLink(const E& it, DLink* p, DLink* n){
element = it;
prev = p; next = n;
}
//constructor
DLink(DLink* p=NULL, DLink* n=NULL){
prev = p;
next = n;
}
};
36
Doubly Linked Insert
37
Doubly Linked Insert
public void insert(E it) {
DLink<E> *tmp = new DLink<E>(it, curr,
curr->next );
curr->next = tmp;
cnt++;
}
38
Doubly Linked Remove
39
Doubly Linked Remove
public E remove() {
if (curr->next == tail) return NULL;
curr->next = tmp->next;
(tmp->next)->prev = curr;
cnt--;
delete tmp;
return it;
}
40
An application of lists -- merge sort
41
Merge Sort
43
Stacks and Queues
Stack
Array-based stack and linked stack
Some applications of stacks
Queue
Array-based queue and linked queue
An application of queues
44
Stacks
LIFO: Last In, First Out
45
Stacks
Notation:
Insert: PUSH
Remove: POP
The accessible element is called TOP.
46
Stack ADT
// Stack abtract class
template <typename E> class Stack {
public:
void clear();
};
Array-Based Stack
// Array-based stack implementation
private:
E *listArray; // Array holding elements
int size; // Maximum size of stack
Issues:
Which end is the top ?
Array[0] is the bottom and array[top-1] is the top
Where does “top” point to?
The array index for store the next pushed element
What is the cost of the operations?
(1) for each of the three operations 48
Linked Stack
// Linked stack implementation
private:
Link<E>* top; // Pointer to first elem
int size; // Count number of elems
Two operations
Push an element by inserting it at
the beginning of the list
Pop out an element by removing the
first element from the list
What is the cost of the operations?
(1)
How do space requirements compare to
the array-based stack implementation?
A fixed size array must be declared in the array
stack 49
50
Application 1 Parentheses test
51
Algorithm for the parentheses test
Input: Given a string str[] with length n
stack<char> stk;
for ( i=0; i < n; ++i ){
if( str[i] is not a parenthesis) continue;
if str[i] == ‘(‘
push str[i] into stack stk
else{ // str[i] is ‘)’
if the top char on the stack is ‘(‘
pop out the top char
else return not matched
}
}
the string is properly nested iff the stack is52
}
Subroutine calls-cont.
Subroutine calls are implemented by stacks
Each element in the stack is called as an
activation record, including return address,
parameters, and local variables
Push an element on the stack when calling a
subroutine
Pop out an element when the subroutine
finishes
See the textbook for the example of the
execution of the recursive function 54
Queues
FIFO: First in, First Out
The first arrived person will board on the
bus first
55
Queues
Notation:
Enqueue
Dequeue
First element: Front
Last element: Rear
56
Array-based Queue
57
Array-based Queue
58
Solution: Circular Queue
The next index of index (maxSize-1) is 0, which is
(maxSize-1+1)%maxSize, where % is the modulus
operator
59
Circular Queue-cont.
Enqueue
rear = (real+1)%maxSize;
Place the new element at the array with index rear
Dequeue
Serve the first element in the queue, i.e., array[front]
front=(front+1)%maxSize;
Initially
front = 0, rear = maxSize-1;
60
rear
6 7 6 7 front 6 7 front
front
5 0 5 A 0 5 A0
rear
4 1 4 1 4
B 1
C
3 2 3 2 3 2
rear
Empty queue A enqueue B, C enqueue
empty queue:(rear +1)%maxSize = front
6 7 6 7 6 7
5 A 0 5 0 5 0
4 B1 4 B 1 4 1
C front C C
3 2 3 2 front 3 2
rear rear rear
Dequeue A Dequeue B Dequeue C
front 61
6 7 6 7
5 0 5 F G
E H0
4 1 4
D I 1
C C J
2
rear 3 front 3 2 rear
front
Enqueue D,E,F,G,H,I,J
64
An application of queues
65
Conclusion
Array-based lists
Fast random access
Insertion and removal take long time
Linked lists
Slow for random access
Fast insertion and removal
Singled and doubly linked list
The notion of curr
Add head and/or tail nodes for convenient coding
Pay attention to special cases 66
Conclusion-cont.
Stacks
Two implementations, array-based and linked
stacks
Fast operation with time complexity (1)
Queues
Two implementations
Array-based circular queue
The implementation of queue with linked list is easy
Fast operation with time complexity (1)
Wide applications of stacks and queues 67