0% found this document useful (0 votes)
13 views75 pages

Lecture 2

Uploaded by

degagaalemayehu5
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views75 pages

Lecture 2

Uploaded by

degagaalemayehu5
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 75

Lists, Stacks and Queue

Lists
Outline
3

Abstract Data Type (ADT)


List ADT
List ADT with Array Implementation
Linked lists
Basic operations of linked lists
 Insert, find, delete, print, etc.

Variations of linked lists


 Circular linked lists
 Doubly linked lists
The List ADT
4

A sequence of zero or more elements


A1 , A 2 , A 3 , … A N
N: length of the list
A : first element
1
A : last element
N
A : position i
i
If N=0, then empty list
Linearly ordered
 Ai precedes Ai+1
 Ai follows Ai-1
Operations
5

printList: print the list


makeEmpty: create an empty list
find: locate the position of an object in a list
 list: 34,12, 52, 16, 12
 find(52)  3
insert: insert an object to a list
 insert(x,3)  34, 12, 52, x, 16, 12
remove: delete an element from the list
 remove(52)  34, 12, x, 16, 12
findKth: retrieve the element at a certain
position
Implementation of an ADT
6

Choose a data structure to represent the


ADT
 E.g. arrays, records, etc.
Each operation associated with the ADT is
implemented by one or more subroutines
Two standard implementations for the list
ADT
 Array-based
 Linked list
Array Implementation
7

Elements are stored in contiguous array


positions
Array Implementation...
8
Requires an estimate of the maximum size of
the list
 waste space
printList and find: linear
findKth: constant
insert and delete: slow
 e.g. insert at position 0 (making a new element)
 requires first pushing the entire array down one spot to
make room
 e.g. delete at position 0
 requires shifting all the elements in the list up one
 On average, half of the lists needs to be moved for
either operation
Pointer Implementation (Linked
List)
9
Ensure that the list is not stored contiguously
 use a linked list
 a series of structures that are not necessarily adjacent in
memory

 Each node contains the element and a pointer to a


structure containing its successor
the last cell’s next link points to NULL
 Compared to the array implementation,
the pointer implementation uses only as much space as is needed

for the elements currently on the list


but requires space for the pointers in each cell
Linked Lists
10

A B C 

Head
A linked list is a series of connected nodes
Each node contains at least
 A piece of data (any type)
 Pointer to the next node in the list
Head: pointer to the first node
The last node points to NULL node
A

data pointer
A Simple Linked List Class
11

We use two classes: Node and List


Declare Node class for the nodes
 data: double-type data in this example
 next: a pointer to the next node in the list

class Node {
public:
double data; // data
Node* next; // pointer to next
};
A Simple Linked List Class
12

 Declare List, which contains


 head: a pointer to the first node in the list.

Since the list is empty initially, head is set to NULL


 Operations on List

class List {
public:
List(void) { head = NULL; } // constructor
~List(void); // destructor

bool IsEmpty() { return head == NULL; }


Node* InsertNode(int index, double x);
int FindNode(double x);
int DeleteNode(double x);
void DisplayList(void);
private:
Node* head;
};
A Simple Linked List Class
13

Operations of List
 IsEmpty: determine whether or not the list is empty

 InsertNode: insert a new node at a particular position

 FindNode: find a node with a given value

 DeleteNode: delete a node with a given value

 DisplayList: print all the nodes in the list


Inserting a new node
14

 Node* InsertNode(int index, double x)


 Insert a node with data equal to x after the index’th
elements. (i.e., when index = 0, insert the node as the first element;
when index = 1, insert the node after the first element, and so on)
 If the insertion is successful, return the inserted node.
Otherwise, return NULL.
(If index is < 0 or > length of the list, the insertion will fail.)
 Steps index’th
1. Locate index’th element element

2. Allocate memory for the new node


3. Point the new node to its successor
4. Point the new node’s predecessor to the new node
newNode
Inserting a new node
15

 Possible cases of InsertNode


1. Insert into an empty list

2. Insert in front

3. Insert at back

4. Insert in middle

 But, in fact, only need to handle two cases


 Insert as the first node (Case 1 and Case 2)

 Insert in the middle or at the end of the list (Case 3

and Case 4)
Inserting a new node
Node* List::InsertNode(int index,16double x) { Try to locate
if (index < 0) return NULL; index’th node. If it
doesn’t exist,
int currIndex = 1;
Node* currNode = head; return NULL.
while (currNode && index > currIndex) {
currNode = currNode->next;
currIndex++;
}
if (index > 0 && currNode == NULL) return NULL;

Node* newNode = new Node;


newNode->data = x;
if (index == 0) {
newNode->next = head;
head = newNode;
}
else {
newNode->next = currNode->next;
currNode->next = newNode;
}
return newNode;
}
Inserting a new node
Node* List::InsertNode(int index,17double x) {
if (index < 0) return NULL;

int currIndex = 1;
Node* currNode = head;
while (currNode && index > currIndex) {
currNode = currNode->next;
currIndex++;
}
if (index > 0 && currNode == NULL) return NULL;

Node* newNode = new Node;


newNode->data = x;
if (index == 0) {
newNode->next = head; Create a new node
head = newNode;
}
else {
newNode->next = currNode->next;
currNode->next = newNode;
}
return newNode;
}
Inserting a new node
Node* List::InsertNode(int index,18double x) {
if (index < 0) return NULL;

int currIndex = 1;
Node* currNode = head;
while (currNode && index > currIndex) {
currNode = currNode->next;
currIndex++;
}
if (index > 0 && currNode == NULL) return NULL;

Node* newNode = new Node; Insert as first element


newNode->data = x;
if (index == 0) { head
newNode->next = head;
head = newNode;
}
else {
newNode->next = currNode->next; newNode
currNode->next = newNode;
}
return newNode;
}
Inserting a new node
Node* List::InsertNode(int index,19double x) {
if (index < 0) return NULL;

int currIndex = 1;
Node* currNode = head;
while (currNode && index > currIndex) {
currNode = currNode->next;
currIndex++;
}
if (index > 0 && currNode == NULL) return NULL;

Node* newNode = new Node;


newNode->data = x;
if (index == 0) {
newNode->next = head;
head = newNode; Insert after currNode
}
currNode
else {
newNode->next = currNode->next;
currNode->next = newNode;
}
return newNode;
} newNode
Finding a node
20

 int FindNode(double x)
 Search for a node with the value equal to x in the list.

 If such a node is found, return its position. Otherwise,

return 0.

int List::FindNode(double x) {
Node* currNode = head;
int currIndex = 1;
while (currNode && currNode->data != x) {
currNode = currNode->next;
currIndex++;
}
if (currNode) return currIndex;
return 0;
}
Deleting a node
21

 int DeleteNode(double x)
 Delete a node with the value equal to x from the list.
 If such a node is found, return its position. Otherwise,
return 0.
 Steps
 Find the desirable node (similar to FindNode)
 Release the memory occupied by the found node
 Set the pointer of the predecessor of the found node
to the successor of the found node
 Like InsertNode, there are two special cases
 Delete first node

 Delete the node in middle or at the end of the list


Deleting a node
int List::DeleteNode(double x)22 {
Node* prevNode = NULL;
Try to find the node with
Node* currNode = head; its value equal to x
int currIndex = 1;
while (currNode && currNode->data != x) {
prevNode = currNode;
currNode = currNode->next;
currIndex++;
}
if (currNode) {
if (prevNode) {
prevNode->next = currNode->next;
delete currNode;
}
else {
head = currNode->next;
delete currNode;
}
return currIndex;
}
return 0;
}
Deleting a node
int List::DeleteNode(double x)23 {
Node* prevNode = NULL;
Node* currNode = head;
int currIndex = 1;
while (currNode && currNode->data != x) {
prevNode = currNode;
currNode = currNode->next;
currIndex++; prevNode currNode
}
if (currNode) {
if (prevNode) {
prevNode->next = currNode->next;
delete currNode;
}
else {
head = currNode->next;
delete currNode;
}
return currIndex;
}
return 0;
}
Deleting a node
int List::DeleteNode(double x)24 {
Node* prevNode = NULL;
Node* currNode = head;
int currIndex = 1;
while (currNode && currNode->data != x) {
prevNode = currNode;
currNode = currNode->next;
currIndex++;
}
if (currNode) {
if (prevNode) {
prevNode->next = currNode->next;
delete currNode;
}
else {
head = currNode->next;
delete currNode;
}
return currIndex;
} head currNode
return 0;
}
Printing all the elements
25

void DisplayList(void)
 Print the data of all the elements

 Print the number of the nodes in the list

void List::DisplayList()
{
int num = 0;
Node* currNode = head;
while (currNode != NULL){
cout << currNode->data << endl;
currNode = currNode->next;
num++;
}
cout << "Number of nodes in the list: " << num << endl;
}
Destroying the list
26

 ~List(void)
 Use the destructor to release all the memory used by
the list.
 Step through the list and delete each node one by one.
List::~List(void) {
Node* currNode = head, *nextNode = NULL;
while (currNode != NULL)
{
nextNode = currNode->next;
// destroy the current node
delete currNode;
currNode = nextNode;
}
}
6
7 result
Using List 5
Number of nodes in the list: 3
5.0 found
27
4.5 not found
6
int main(void) 5
{ Number of nodes in the list: 2

List list;
list.InsertNode(0, 7.0); // successful
list.InsertNode(1, 5.0); // successful
list.InsertNode(-1, 5.0); // unsuccessful
list.InsertNode(0, 6.0); // successful
list.InsertNode(8, 4.0); // unsuccessful
// print all the elements
list.DisplayList();
if(list.FindNode(5.0) > 0) cout << "5.0 found" << endl;
else cout << "5.0 not found" << endl;
if(list.FindNode(4.5) > 0) cout << "4.5 found" << endl;
else cout << "4.5 not found" << endl;
list.DeleteNode(7.0);
list.DisplayList();
return 0;
}
Variations of Linked Lists
28

Circular linked lists


 The last node points to the first node of the list

A B C

Head
 How do we know when we have finished
traversing the list? (Tip: check if the pointer of
the current node is equal to the head.)
Variations of Linked Lists
29

Doubly linked lists


 Each node points to not only successor but the
predecessor
 There are two NULL: at the first and last nodes in
the list
 Advantage: given a node, it is easy to visit its
predecessor. Convenient to traverse lists backwards

 A B C 

Head
Array versus Linked Lists
30

 Linked lists are more complex to code and


manage than arrays, but they have some distinct
advantages.
 Dynamic: a linked list can easily grow and shrink in size.
 We don’t need to know how many nodes will be in the list.
They are created in memory as needed.
 In contrast, the size of a C++ array is fixed at compilation
time.
 Easy and fast insertions and deletions
 To insert or delete an element in an array, we need to copy to
temporary variables to make room for new elements or close
the gap caused by deleted elements.
 With a linked list, no need to move other nodes. Only need to
reset some pointers.
Performance
31

In the implementation of the List ADT by


means of a doubly linked list
 The space used by a list with n elements is O(n)
 The space used by each position of the list is O(1)
 All the operations of the List ADT run in O(1) time
 Operation element() of the
Position ADT runs in O(1) time
The Stack ADT
32

 The Stack ADT stores  Auxiliary stack


arbitrary objects operations:
 Insertions and deletions  object top(): returns
follow the last-in first- the last inserted
out scheme element without
 Think of a spring- removing it
loaded plate dispenser  integer size(): returns
 Main stack operations: the number of
elements stored
 push(object): inserts an
element
 boolean isEmpty():
indicates whether no
 object pop(): removes and
returns the last inserted elements are stored
element
Stack Interface in Java
33

Java interface public interface Stack {

corresponding to public int size();


our Stack ADT public boolean isEmpty();
Requires the
public Object top()
definition of throws EmptyStackException;
class public void push(Object o);
EmptyStackException
public Object pop()
throws EmptyStackException;
}
Exceptions
34

Attempting the In the Stack ADT,


execution of an operations pop and
operation of ADT top cannot be
may sometimes performed if the
cause an error stack is empty
condition, called an Attempting the
exception execution of pop or
Exceptions are said top on an empty
to be “thrown” by an stack throws an
operation that EmptyStackExcepti
cannot be executed on
Applications of Stacks
35

Direct applications
 Undo sequence in a text editor

 Chain of method calls in the Java Virtual Machine

Indirect applications
 Auxiliary data structure for algorithms
 Component of other data structures
Array-based Stack
(Implementation)
36

 A simple way of Algorithm size()


implementing the return t + 1
Stack ADT uses an
array Algorithm pop()
 We add elements if isEmpty() then
from left to right throw EmptyStackException
 A variable t keeps else
track of the index tt1
of the top element return S[t + 1]


S
0 1 2 t
Array-based Stack (cont.)
37

 The array storing the


stack elements may
become full Algorithm push(o)
 A push operation will if t = S.length  1 then
then throw a throw FullStackException
FullStackException else
 Limitation of the array- tt+1
based implementation S[t]  o
 Not intrinsic to the
Stack ADT


S
0 1 2 t
Array-based Stack (Cont.)
38

 A Stack might be Algorithm isEmpty()


empty if t<0 then return true
 top returns the else return false
element at the top
of the Stack, but Algorithm top()
does not remove if isEmpty() then
the top element. throw EmptyStackException
When the Stack is return S[t ]
empty, an error
occurs.

S
0 1 2 t
Performance and Limitations
for array-based Stack
39

Performance
 Let n be the number of elements in the stack
 The space used is O(n)

 Each operation runs in time O(1)

Limitations
 The maximum size of the stack must be
defined a priori and cannot be changed
 Trying to push a new element into a full

stack causes an implementation-specific


exception
Array-based Stack in Java
40

public class ArrayStack implements Stack{


// holds the stack elements
private Object S[ ];
// index to top element
private int top = -1;
// constructor
public ArrayStack(int capacity) {
S = new Object[capacity]);
}
Array-based Stack in Java
41

public Object pop() throws EmptyStackException{


if isEmpty()
throw new EmptyStackException
(“Empty stack: cannot pop”);
Object temp = S[top];
// facilitates garbage collection
S[top] = null;
top = top – 1;
return temp;
}
public int size() {
return (top + 1);
Array-based Stack in Java
42

public boolean isEmpty() {


return (top < 0);
}
public void push(Object obj) throws FullStackException
{
if (size() == capacity)
throw new FullStackException("Stack overflow.");
S[++top] = obj;
}
public Object top() throws EmptyStackException {
if (isEmpty())
throw new EmptyStackException("Stack is
empty.");
return S[top];
}
Parentheses Matching
43

An expression, i.e.,[(2+3)*x+5]*2.


Each “(”, “{”, or “[” must be paired with a
matching “)”, “}”, or “[”
 correct: ( )(( )){([( )])}
 correct: ((( )(( )){([( )])}
 incorrect: )(( )){([( )])}
 incorrect: ({[ ])}
 incorrect: (
Parentheses Matching
Algorithm
44

Algorithm ParenMatch(X,n):
Input: An array X of n tokens, each of which is either a grouping symbol, a
variable, an arithmetic operator, or a number
Output: true if and only if all the grouping symbols in X match
Let S be an empty stack
for i=0 to n-1 do
if X[i] is an opening grouping symbol then
S.push(X[i])
else if X[i] is a closing grouping symbol then
if S.isEmpty() then
return false {nothing to match with}
if S.pop() does not match the type of X[i] then
return false {wrong type}
if S.isEmpty() then
return true {every symbol matched}
else
return false {some symbols were never matched}
Parentheses Matching
Example 1 45

Input: () (() [()])

i Operation Stack Output


X[i]
0 ( Push ( (
1 ) Pop (
Test if ( and X[i] match? YES
2 ( Push ( (
3 ( Push ( ((
4 ) Pop ( (
Test if ( and X[i] match? YES
5 [ Push [ ([
Parentheses Matching
Example 1 46

Input: () (() [()])

i Operation Stac Outpu


X[i] k t
6 ( Push ( ([(
7 ) Pop ( ([
Test if ( and X[i] match? YES
8 ] Pop [ (
Test if [ and X[i] match? YES
9 ) Pop (
Test if ( and X[i] match? YES
Test if stack is Empty? YES TRUE
Parentheses Matching
Example 2 47

 Input: ( () [] ]()

i Operation Stack Output


X[i]
0 ( Push ( (

1 ( Push ( ((
2 ) Pop ( (
Test if ( and X[i] match? YES
3 [ Push [ ([
4 ] Pop [ (
Test if [ and X[i] match? YES
5 ] Pop (
Test if ( and X[i] match ? NO FASLE
Summary of Stack
48

 Understand the definition of Stack (basic)


 Applications
1. Parentheses (moderate)
2. Computing Spans
 Implementation of Stack is
required.
 You should be able to use stack to write
programs to solve problems
Queues
What is a queue?
• It is an ordered group of homogeneous items of
elements.
• Queues have two ends:
– Elements are added at one end.
– Elements are removed from the other end.
• The element added first is also removed first
(FIFO: First In, First Out).
Queue Specification
• Definitions: (provided by the user)
– MAX_ITEMS: Max number of items that might be on
the queue
– ItemType: Data type of the items on the queue

• Operations
– MakeEmpty
– Boolean IsEmpty
– Boolean IsFull
– Enqueue (ItemType newItem)
– Dequeue (ItemType& item)
Enqueue (ItemType newItem)
• Function: Adds newItem to the rear of the
queue.
• Preconditions: Queue has been initialized
and is not full.
• Postconditions: newItem is at rear of queue.
Dequeue (ItemType& item)
• Function: Removes front item from queue
and returns it in item.
• Preconditions: Queue has been initialized
and is not empty.
• Postconditions: Front element has been
removed from queue and item is a copy of
removed element.
Implementation issues
• Implement the queue as a circular structure.
• How do we know if a queue is full or
empty?
• Initialization of front and rear.
• Testing for a full or empty queue.
Make front point to the element preceding the front
element in the queue (one memory location will be
wasted).
Initialize front and rear
Queue is empty
now!!
rear == front
Queue Implementation
template<class ItemType> private:
class QueueType { int front;
public: int rear;
QueueType(int); ItemType* items;
QueueType(); int maxQue;
~QueueType(); };
void MakeEmpty();
bool IsEmpty() const;
bool IsFull() const;
void Enqueue(ItemType);
void Dequeue(ItemType&);
Queue Implementation (cont.)
template<class ItemType>
QueueType<ItemType>::QueueType(int
max)
{
maxQue = max + 1;
front = maxQue - 1;
rear = maxQue - 1;
items = new ItemType[maxQue];
}
Queue Implementation (cont.)

template<class ItemType>
QueueType<ItemType>::~QueueType()
{
delete [] items;
}
Queue Implementation (cont.)

template<class ItemType>
void QueueType<ItemType>::
MakeEmpty()
{
front = maxQue - 1;
rear = maxQue - 1;
}
Queue Implementation (cont.)
template<class ItemType>
bool QueueType<ItemType>::IsEmpty() const
{
return (rear == front);
}

template<class ItemType>
bool QueueType<ItemType>::IsFull() const
{
return ( (rear + 1) % maxQue == front);
}
Queue Implementation (cont.)
template<class ItemType>
void QueueType<ItemType>::Enqueue
(ItemType newItem)
{
rear = (rear + 1) % maxQue;
items[rear] = newItem;
}
Queue Implementation (cont.)
template<class ItemType>
void QueueType<ItemType>::Dequeue
(ItemType& item)
{
front = (front + 1) % maxQue;
item = items[front];
}
Queue overflow

• The condition resulting from trying to add


an element onto a full queue.

if(!q.IsFull())
q.Enqueue(item);
Queue underflow

• The condition resulting from trying to


remove an element from an empty queue.

if(!q.IsEmpty())
q.Dequeue(item);
Example: recognizing palindromes
• A palindrome is a string that reads the same
forward and backward.
Able was I ere I saw Elba
• We will read the line of text into both a stack
and a queue.
• Compare the contents of the stack and the
queue character-by-character to see if they
would produce the same string of characters.
Example: recognizing palindromes
Example: recognizing palindromes
#include <iostream.h> cout << "Enter string: " << endl;
#include <ctype.h>
while(cin.peek() != '\\n') {
#include "stack.h"
#include "queue.h“ cin >> ch;
if(isalpha(ch)) {
int main()
{ if(!s.IsFull())
StackType<char> s; s.Push(toupper(ch));
QueType<char> q; if(!q.IsFull())
char ch; q.Enqueue(toupper(ch));
char sItem, qItem; }
}
int mismatches = 0;
Example: recognizing palindromes
while( (!q.IsEmpty()) && (!s.IsEmpty()) ) {
s.Pop(sItem);
q.Dequeue(qItem);

if(sItem != qItem)
++mismatches;
}
if (mismatches == 0)
cout << "That is a palindrome" << endl;
else
cout << That is not a palindrome" << endl;
return 0;
}
Case Study: Simulation

• Queuing System: consists of servers and


queues of objects to be served.

• Simulation: a program that determines how


long items must wait in line before being
served.
Case Study: Simulation (cont.)
• Inputs to the simulation:
(1) the length of the simulation
(2) the average transaction time
(3) the number of servers
(4) the average time between job
arrivals
Case Study: Simulation (cont.)

• Parameters the simulation must vary:


(1) number of servers
(2) time between arrivals of items

• Output of simulation: average wait time.

You might also like