Lecture 8
This presentation is the property of its rightful owner.
Sponsored Links
1 / 51

Lecture #8 PowerPoint PPT Presentation


  • 66 Views
  • Uploaded on
  • Presentation posted in: General

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.

Download Presentation

Lecture #8

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


Lecture 8

Lecture #8


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


Lecture 8

Abstract Data Type


Abstract data types are abstraction

Abstract Data Types are Abstraction


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


Lecture 8

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


Queues

Queues


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

OperationOutputQ

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

rindex 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


Stacks

Stacks


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:

doubledata;// 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=newNode;

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=newNode;

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=newNode;

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=newNode;

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;

elsecout << "5.0 not found" << endl;

if(list.FindNode(4.5) > 0) cout << "4.5 found" << endl;

elsecout << "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


Thanks

Thanks


  • Login