lecture 8
Download
Skip this Video
Download Presentation
Lecture #8

Loading in 2 Seconds...

play fullscreen
1 / 51

Lecture #8 - PowerPoint PPT Presentation


  • 99 Views
  • Uploaded on

Lecture #8. Abstract Data Type (ADT) Queues ADT Stacks 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. Agenda. Abstract Data Type.

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about ' Lecture #8' - waneta


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
agenda
Abstract Data Type (ADT)

Queues ADT

Stacks 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

Agenda
abstract data type example
An Abstract Data Type is a data type that is defined by the programmer, not the language.

Like any data type, it is a set of values with operations that act on those values.

Working with ADTs involves three different components:

The public interface, or specification, defines the ADT and how it is used.

The implementation, implements the ADT in code.

The client uses the ADT to perform a task.

Abstract Data Type Example
adt operations
Several classes of operations are required in order to effectively used ADT.

Constructors – used to create instances of the data type.

Destructors – used to destroy an instance of the data type

Accessors – used to access attributes of the data type. (Such as “get” functions)

Modifiers – used to modify attributes of the data type. (Such as “set” functions)

Object-oriented languages provide some of this functionality within the language. In C you must do it yourself.

ADT Operations
abstract data type adt
Data type

a set of objects + a set of operations

Example: integer

set of whole numbers

operations: +, -, x, /

Abstract data type

high-level abstractions (managing complexity through abstraction)

Encapsulation

Abstract Data Type (ADT)
encapsulation
Operation on the ADT can only be done by calling the appropriate function

no mention of how the set of operations is implemented

The definition of the type and all operations on that type can be localized to one section of the program

If we wish to change the implementation of an ADT

we know where to look

by revising one small section we can be sure that there is no subtlety elsewhere that will cause errors

We can treat the ADT as a primitive type: we have no concern with the underlying implementation

ADT  C++: class

method  C++: member function

Encapsulation
slide9
Examples

the set ADT

A set of elements

Operations: union, intersection, size and complement

the queue ADT

A set of sequences of elements

Operations: create empty queue, insert, examine, delete, and destroy queue

ADT…
pros and cons
Implementation of the ADT is separate from its use

Modular: one module for one ADT

Easier to debug

Easier for several people to work simultaneously

Code for the ADT can be reused in different applications

Information hiding

A logical unit to do a specific job

implementation details can be changed without affecting user programs

Allow rapid prototying

Prototype with simple ADT implementations, then tune them later when necessary

Loss of efficiency

Pros and Cons
examples
Examples
  • Queues
  • Stack
  • Linked list
the queue adt
The Queue ADT stores arbitrary objects

Insertions and deletions follow the first-in first-out scheme

Insertions are at the rear of the queue and removals are at the front of the queue

Main queue operations:

enqueue(object): inserts an element at the end of the queue

object dequeue(): removes and returns the element at the front of the queue

Auxiliary queue operations:

object front(): returns the element at the front without removing it

integer size(): returns the number of elements stored

boolean isEmpty(): indicates whether no elements are stored

Exceptions

Attempting the execution of dequeue or front on an empty queue throws an EmptyQueueException

The Queue ADT

Queues

queue example
Operation Output Q

enqueue(5) – (5)

enqueue(3) – (5, 3)

dequeue() 5 (3)

enqueue(7) – (3, 7)

dequeue() 3 (7)

front() 7 (7)

dequeue() 7 ()

dequeue() “error” ()

isEmpty() true ()

enqueue(9) – (9)

enqueue(7) – (9, 7)

size() 2 (9, 7)

enqueue(3) – (9, 7, 3)

enqueue(5) – (9, 7, 3, 5)

dequeue() 9 (7, 3, 5)

Queue Example

Queues

applications of queues
Direct applications

Waiting lists, bureaucracy

Access to shared resources (e.g., printer)

Multiprogramming

Indirect applications

Auxiliary data structure for algorithms

Component of other data structures

Applications of Queues

Queues

array based queue
Use an array of size N in a circular fashion

Two variables keep track of the front and rear

f index of the front element

r index immediately past the rear element

Array location r is kept empty

Q

0

1

2

f

r

Q

0

1

2

r

f

Array-based Queue

normal configuration

wrapped-around configuration

Queues

queue operations
We use the modulo operator (remainder of division)

Q

0

1

2

f

r

Q

0

1

2

r

f

Queue Operations

Algorithmsize()

return(N-f +r) mod N

AlgorithmisEmpty()

return(f=r)

Queues

example

Q

0

1

2

f

r

Q

0

1

2

r

f

Example:

Algorithmsize()

return (N-f + r) mod N

mod is the remainder of division. In C language it is % operator

16

f = 4, r = 14 , N = 17 size = (17-4+14)%17 = 27%17 = 10

f = 11, r = 4 , N = 17 size = (17-11+4)%17 = 10%17= 10

queue operations cont
Operation enqueue throws an exception if the array is full

This exception is implementation-dependent

Q

0

1

2

f

r

Q

0

1

2

r

f

Queue Operations (cont.)

Algorithmenqueue(o)

ifsize()=N 1then

throw FullQueueException

else

Q[r] o

r(r + 1) mod N

To set r to zero if r+1 reaches the end of the array

queue operations cont1
Operation dequeue throws an exception if the queue is empty

This exception is specified in the queue ADT

Q

0

1

2

f

r

Q

0

1

2

r

f

Queue Operations (cont.)

Algorithmdequeue()

ifisEmpty()then

throw EmptyQueueException

else

oQ[f]

f(f + 1) mod N

returno

applications of stacks
Direct applications

Delimiter matching

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

Applications of Stacks

Stacks

the stack adt
The Stack ADT stores arbitrary objects

Insertions and deletions follow the last-in first-out scheme

Think of a spring-loaded plate dispenser

Main stack operations:

push(object): inserts an element

object pop(): removes and returns the last inserted element

Auxiliary stack operations:

object top(): returns the last inserted element without removing it

integer size(): returns the number of elements stored

booleanisEmpty(): indicates whether no elements are stored

The Stack ADT
stack interface in java
Java interface corresponding to our Stack ADT

Requires the definition of class EmptyStackException

Different from the built-in Java class java.util.Stack

Stack Interface in Java

public interfaceStack{

public int size();

public boolean isEmpty();

public Object top()throwsEmptyStackException;

public voidpush(Object o);

public Object pop()throwsEmptyStackException;}

Stacks

exceptions
Attempting the execution of an operation of ADT may sometimes cause an error condition, called an exception

Exceptions are said to be “thrown” by an operation that cannot be executed

In the Stack ADT, operations pop and top cannot be performed if the stack is empty

Attempting the execution of pop or top on an empty stack throws an EmptyStackException

Exceptions

Stacks

array based stack
A simple way of implementing the Stack ADT uses an array

We add elements from left to right

A variable keeps track of the index of the top element

Array-based Stack

Algorithmsize()

returnt +1

Algorithmpop()

ifisEmpty()then

throw EmptyStackException

else

tt 1

returnS[t +1]

S

0

1

2

t

Stacks

array based stack cont
The array storing the stack elements may become full

A push operation will then throw a FullStackException

Limitation of the array-based implementation

Not intrinsic to the Stack ADT

S

0

1

2

t

Array-based Stack (cont.)

Algorithmpush(o)

ift=S.length 1then

throw FullStackException

else

tt +1

S[t] o

Stacks

the list adt
A sequence of zero or more elements

A1, A2, A3, … AN

N: length of the list

A1: first element

AN: last element

Ai: position i

If N=0, then empty list

Linearly ordered

Ai precedes Ai+1

Ai follows Ai-1

The List ADT
operations
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

Operations
linked lists
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

A

C

B

A

Linked Lists

Head

node

data

pointer

a simple linked list class
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

A Simple Linked List Class

class Node {

public:

double data; // data

Node* next; // pointer to next

};

a simple linked list class1
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

A Simple Linked List Class

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 class2
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

A Simple Linked List Class
inserting a new node
Node* InsertNode(int index, double x)

Insert a node with data equal to x after the index’thelements. (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

Locate index’th element

Allocate memory for the new node

Point the new node to its successor

Point the new node’s predecessor to the new node

Inserting a new node

index’th element

newNode

inserting a new node1
Possible cases of InsertNode

Insert into an empty list

Insert in front

Insert at back

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
inserting a new node2
Inserting a new node

Try to locate index’th node. If it doesn’t exist, return NULL.

Node* List::InsertNode(int index, double 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;

}

else {

newNode->next = currNode->next;

currNode->next = newNode;

}

return newNode;

}

inserting a new node3
Inserting a new node

Node* List::InsertNode(int index, double 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;

}

else {

newNode->next = currNode->next;

currNode->next = newNode;

}

return newNode;

}

Create a new node

inserting a new node4
Inserting a new node

Node* List::InsertNode(int index, double 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;

}

else {

newNode->next = currNode->next;

currNode->next = newNode;

}

return newNode;

}

Insert as first element

head

newNode

inserting a new node5
Inserting a new node

Node* List::InsertNode(int index, double 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;

}

else {

newNode->next = currNode->next;

currNode->next = newNode;

}

return newNode;

}

Insert after currNode

currNode

newNode

finding a node
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.

Finding a node

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
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
deleting a node1
Deleting a node

int List::DeleteNode(double x) {

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;

}

return 0;

}

Try to find the node with its value equal to x

deleting a node2
Deleting a node

int List::DeleteNode(double x) {

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;

}

return 0;

}

prevNode

currNode

deleting a node3
Deleting a node

int List::DeleteNode(double x) {

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;

}

return 0;

}

head

currNode

printing all the elements
void DisplayList(void)

Print the data of all the elements

Print the number of the nodes in the list

Printing all the elements

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 l ist
~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.

Destroying the list

List::~List(void) {

Node* currNode = head, *nextNode = NULL;

while (currNode != NULL)

{

nextNode = currNode->next;

// destroy the current node

delete currNode;

currNode = nextNode;

}

}

using list

6

7

5

Number of nodes in the list: 3

5.0 found

4.5 not found

6

5

Number of nodes in the list: 2

result

Using List

int main(void)

{

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
Circular linked lists

The last node points to the first node of the list

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.)

A

C

B

Variations of Linked Lists

Head

variations of linked lists1
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

C

B

Variations of Linked Lists

Head

array versus linked lists
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.

Array versus Linked Lists
ad