0% found this document useful (0 votes)
115 views

Week02 Lesson 01 Abstract Data Types M

This document provides an introduction to abstract data types (ADTs). It defines abstraction as focusing on general concepts that apply across different concrete instances. Data abstraction hides implementation details and exposes only essential properties and operations. An abstract data type specifies operations without specifying implementation. Examples given are integers, which can be implemented differently on different systems but expose common operations, and mobile phone services, which are abstracted via an interface. The key points are that ADTs specify logical properties independently of physical representation and allow programming to higher-level concepts.

Uploaded by

Adhil Fairooz
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
115 views

Week02 Lesson 01 Abstract Data Types M

This document provides an introduction to abstract data types (ADTs). It defines abstraction as focusing on general concepts that apply across different concrete instances. Data abstraction hides implementation details and exposes only essential properties and operations. An abstract data type specifies operations without specifying implementation. Examples given are integers, which can be implemented differently on different systems but expose common operations, and mobile phone services, which are abstracted via an interface. The key points are that ADTs specify logical properties independently of physical representation and allow programming to higher-level concepts.

Uploaded by

Adhil Fairooz
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

LESSON 01 – ABSTRACT DATA TYPES

Introduction
This is the first lesson of the course. In this lesson we will begin our journey in the valley of Data
Structures, by setting foot on Abstract Data Types.

Learning outcome:

Upon successful completion of this lesson, you would be able to understand abstract data
types. Thus you should be able to
• Describe what abstraction is
• Define abstract data types and describe their uses

1.1 Abstraction

In ordinary use the word “abstract” means something not quite real, something not distinct or
clear, but in science there is a more precise definition to the word “abstract”. An abstraction is a
separation of relevant from the irrelevant; more specifically, it is focusing on the general concepts
that apply to different but concrete instances.

In arithmetic, you have learned that one plus two is equal to three (1 + 2 = 3). As shown in the
knowingly or unknowingly you have used the above abstract concept to deduce any results like
two planes plus one planes is equal to three planes.

Figure 2.1 -a
+ =
Figure 2.1 - b

What we see if not what we have to understand here is that the fact that the rule of addition applies
to birds and to cars is completely irrelevant to the rule itself. We can apply the rule of addition any
instance/object in real world. Thus, a single abstraction can be the base of many instances and an
abstraction usually evolves after having experienced some of its real instances but it is not a must.
Before we conclude let us consider another example. We know that there are no perfect circles,
but we know that the circumference of an imaginary, perfect circle with radius r is 2πr. This
abstraction applies to bicycle tyres, planetary objects and many more. Now we will learn how this
concept of abstraction can be applied to programming models.

1.2 Data abstraction

Data abstraction hides the details of data representation in order to make the datatype easier to
work with. It involves creation of data that separate the interface from implementation, so the
programmer or user only has to understand the interface especially the commands to use, but not
how the internal structure of the data represented and how it has been implemented.
For an example think about smart phones. User does not need to know how the phone access the
internet or how does it take photographs, how data is stored in the phone etc… Instead mobile
phone users are provided with an interface that hide details of these the services. Thus, all these
services can be accessed by learning commands on the interface of the mobile phone. For an
instance accessing internet user can simply click on an icon on the interface. This idea is shown
in the following figure.

How mobile phone


accesses the
internet?

Black box
Hence, these services are abstracted from the interface making the phone is easy to use. Thus,
these service were in a black box to a mobile user.
More formally we can say that, data abstraction asks that you think in terms of what you can do
to a collection of data independently of how you do it. Thus, it is the process of isolating
implementation details and extracting only essential property from an entity.

What is the abstraction of computer programs?


The programming model is comprised of the data and algorithms. Thus, abstraction in program
can be presented in two different ways: data abstraction and function abstractions. As we have
learnt above, data abstraction focuses on what operations are needed by the data and function
abstraction focuses on the purpose of a function i.e. what the function should do.

1.3 Abstract Data Types

The definition of ADT only mentions what operations are to be performed but not how these
operations will be implemented. It does not specify how data will be organized in memory and
what algorithms will be used for implementing the operations. It is called “abstract” because it
gives an implementation independent view. The process of providing only the essentials and
hiding the details is known as abstraction.

Abstract data type (ADT) is a data type whose properties (domain and
operations) are specified independently of any particular implementation

Do you know that the manner or the method in which data types are implemented is irrelevant to
how they are used in client programs? Let us see what this means. Just what is an integer? Integers
are physically represented in different ways on different computers. In the memory of one
machine, an integer may be a binary-coded decimal. In a second machine, it may be a sign and-
magnitude binary. Moreover, in a third one, it may be represented in two’s-complement binary
notation. Although you may not be familiar with these terms, that has not stopped you from using
integers, has it? Figure 2.2 shows some different representations of an integer.
Figure 2.2: The decimal equivalents of an 8-bit binary number

The way that integers are physically represented determines how the computer manipulates them.
As a Java programmer, however, you do not usually get involved at this level; you simply use
integers. All you need to know is how to declare an int type variable and what operations are
allowed on integers: assignment, addition, subtraction, multiplication, division, and modulo
arithmetic.

Consider the statement

distance = rate * time;

Here distance, rate and time are variables, representing real numbers. Now will understand the
concept behind this statement. The concept of multiplication does not depend on whether the
operands are, say, integers or real numbers, despite the fact that integer multiplication and floating-
point multiplication may be implemented in very different ways on the same computer. Computers
would not be very popular if every time we wanted to multiply two numbers we had to get down
to the machine-representation level. Nevertheless, we do not have to: Java has provided the int
data type for us, hiding all the implementation details and giving us just the information we need
to create and manipulate data of this type.

More formally, we say that Java has encapsulated integers for us. Think of the capsules
surrounding the medicine you get from the pharmacist when you are sick. You do not have to
know anything about the chemical composition of the medicine inside to recognize the big blue-
and-white capsule as your antibiotic or the little yellow capsule as your decongestant. Data
encapsulation means that the physical representation of a program’s data is hidden by the
language. The programmer using the data does not see the underlying implementation, but deals
with the data only in terms of its logical picture - its abstraction.
Data Encapsulation - is the separation of the representation of data from the applications
that use the data at a logical level; a programming language feature that enforces information
hiding

However, if the data are encapsulated, how can the programmer get to them? That is where we
want operations. Operations must be provided to allow the programmer to create, access, and
change the data.

Let us look at the operations Java provides for the encapsulated data type int. First of all, you can
create variables of type int using declarations in your program. Then you can assign values to
these integer variables by using the assignment operator and perform arithmetic operations on
them using +, -, *, /, and %. Figure 2.3 shows how Java has encapsulated the type int in a nice
neat black box.

Figure 2.3: A black box representing an integer data type

The point of this discussion is that you have been dealing with a logical data abstraction of integer
since the very beginning. The advantages of doing so are clear: you can think of the data and the
operations in a logical sense and can consider their use without having to worry about
implementation details. The lower levels are still there - they are just hidden from you.

We can achieve two goals with this type of design.


1. reduce complexity through abstraction and
2. protect our data abstraction through encapsulation
We refer to the set of all possible values (the domain) of an encapsulated data “object,” plus the
specifications of the operations that are provided to create and manipulate the data, as an abstract
data type (ADT for short). The abstract data type can also be viewed as a theoretical construct that
serves as an ideal for later implementations. The abstraction details both the kind of data that it
describes and also the operations that that may be performed and applied to it in order to capture
the complete nature of the new data type. Each implementation of the abstract data type will pave
way for a concrete data type.

In effect, all the Java built-in (primitive) types are ADTs meaning that a Java programmer can
declare variables of those types without understanding the underlying implementation. The
programmer can initialize, modify, and access the information held by the variables using the
provided operations.

An ADT gives us the opportunity to focus entirely on the behaviour of the data type without having
to worry about its implementation and thus lead to providing a precise definition of such data type.
By doing so, the essential differences existing among data types can be distinguished.

Examples for ADTs


Let us consider two data types that you are familiar with: Bag and Set. We can define their ADTs
as follows,
ADT: Bag - It is a collection of object

Bags are containers – they hold things. Fundamental operations with all bags are;

 Put something in – add(item)


 Take an item out – remove(item)
 Take everything out – clear()
 Count how many things are in it – getFrequencyOf(item)
 See if it is empty – isEmpty()
 Check to see if something is in it – contains(item)
 Count the items in it – getCurrentSize()
 Look at all the contents – display()
A Bag is a collection of objects. void
add(Object object)
Postcondtion: the given object is in this bag.
boolean contains(Object object)
Returns: true if and only if (iff) the given object is in this bag.
Postcondition: this bag is unchanged. Object
getFirst()
Returns: an element of this bag.
Postcondition: this bag is unchanged.
Object getNext()
Returns: some element of this bag other than those already returned by the last call to
getFirst() and subsequent calls to getNext(); if all elements have been accessed by
that previous sequence of calls, then null is returned.
Postcondition: this bag is unchanged.
boolean remove(Object object)
Returns: true iff this bag is changed.
Precondition: the object is in this bag.
integer size()
Returns: the number of elements in this bag.
Postcondition: this bag is unchanged.

Figure: 2.4: An abstract data type for a typical Bag container

ADT: Set

Set ADT is an unordered collection of elements with no duplicates.


A Set is a collection of unique objects. boolean
add(Object object)
Returns: true iff this set is changed.
Precondition: the object is not in this set.
Postcondtion: the given object is in this set. boolean
contains(Object object)
Returns: true iff the given object is in this set.
Postcondition: this set is unchanged.
Object getFirst()
Returns: an element of this set.
Postcondition: this set is unchanged.
Object getNext()
Returns: some element of this set other than those already returned by the last call to
getFirst() and subsequent calls to getNext(); if all elements have been accessed by
that previous sequence of calls, then null is returned.
Postcondition: this set is unchanged.
boolean remove(Object object)
Returns: true iff this set is changed.
Precondition: the object is in this set.
Postcondition: the given object is not in this set.
integer size()
Returns: the number of elements in this set.
Postcondition: this set is unchanged.

Figure: 2.4: An abstract data type for a typical Set container

Both are containers with only a single difference between them. A Bag may contain duplicate
elements on the other hand a Set will not allow duplicate objects. Apart from that, they are both
unstructured and unordered collections.

The two ADTs identify two transformer methods (mutator operations) viz. add and remove and
four observer methods (accessor operations) namely contains, getFirst, getNext and size.

Transformer (Mutator) – is a method Observer (Accessor) – is a method


(operation) that changes the internal state (operation) that returns an observation on
of the object. the state of the object.
The easiest way to identify observer methods is by their postconditions that the objects, containers
in this instance remain unchanged.
If you look carefully, you will be able to observe that the four observer methods are the same for
our two ADTs Bag and Set. Only the two transformers add and remove are different, let us see
how.
If we presume that overflow is prevented, the add operation described in the ADT Bag will insert
any object/element even if the insertion is a duplicate. However, it will not be the case with a set.
Since a set cannot hold duplicate objects/elements the add transformer in the ADT Set will fail if
we try to insert an object which is already in the set. In other words for the add operation to succeed
a condition should be satisfied: the object to be added must not be in the set of consideration.
Nonetheless if the adding is successful the add method for a set will return true indicating that the
insertion was made. In contrast the add method for a bag will not return anything since it is not
bound to fail.
Can you explain the difference between the two mutators remove in the ADT Bag and ADT Set?

Check whether your explanation is correct.

ADT Bag ADT Set

remove operation We cannot guarantee that the It can be assured that the
removed object/element is no removed object/element is no
longer in a bag, for the bag longer in a set, for it cannot
may contain duplicate objects have duplicate objects and
and hence no postcondition. hence a postcondition
guaranteeing the same.

Further there is a precondition for both transformers, remove. The condition is obvious; you cannot
remove any object or element that is not contained either in a bag or a set.
It is important to note that,

Precondition – is a condition that is assumed to be true before the operation begins.


Postcondition – is a condition that is guaranteed to be true after the operation ends.

One of the advantages of ADTs is that they can be used in algorithms. Let’s write an algorithm
that removes all instances of an object/element from a bag.
Algorithm 2.1: Remove All Instances of an Object/Element from a Bag
Input: a Bag b; an object x
Output: the number of objects removed.
Postcondition: the Bag b contains no x objects.
1. Let n be the integer 0.
2. If b.contains(x) is false, then return n.
3. b.remove(x).
4. Add 1 to n.
5. Go to step 2.

This algorithm uses the contains method at step 2 to check whether the object x is in the bag
considered. If no such object is in the bag, the algorithm will terminate returning 0 indicating that
0 number of elements were removed. Otherwise, at step 3 the object x is removed using the remove
method. At step 4 the value of n is incremented by 1 (n keeps track of the number of objects
removed). Steps 2 – 5 constitutes a loop that will find all the instances of object x and remove
them each one by one. The loop terminates at step 2 when all the instances of the object have been
removed. For example, if b is bag containing six oranges, ten apples, three avocados and two
lemons, and if x is avocado, then the above algorithm would remove the three avocados from the
bag and yield number three (3) as the output. How many times would the loop composed of steps
2 – 5, run? It is clear that the loop would iterate for three times in this particular instance.
We were able to completely specify the above algorithm without having to worry about the
implementation of the operations contains and remove. This is the power of an ADT. You only
have to know what you can do with the data type; in our example, what you can do with a bag.

1.4 Concrete Data Types


An abstraction is meaningless if it does not have concrete realizations. A concrete data type is an
implementation of an ADT in a particular programming language from which real objects can be
created and manipulated of that data type. In Java, the realization of the concrete data type would
be as follows:

With Java, an ADT can be translated into an interface, which can then be implemented as a class.
Let us now see how our Bag ADT can be translated or realized in Java.
Listing 2.1: An Interface for our Bag ADT

public interface Bag {


public void add(Object object);
public Boolean contains(Object object);
public Object getFirst();
public Object getNext();
public boolean remove(Object object);
public int size();
}

The interface gives an overview of the nature of the bag. It describes the method prototypes. For
example, the remove method takes an Object as an argument and will return a boolean value as
the output. An interface does not contain method implementations. In order to create a bag object
we have to first define a bag class that implements the bag interface. We will use the simple array
data structure (which you will learn in the next lesson) to implement the bag interface.
Listing 2.2: The Bag interface implemented as An ArrayBag or rather as an array

public class ArrayBag implements Bag {


private Object[] objects = new Object[1000];

// Creates a bag in the form of an array that can store up to 1000


// objects
private int size, i;

public void add(Object object) {


objects[size++] = object;
}

public boolean contains(Object object) {


for(int i = 0; i < size; i++) {
if (objects[i] == object) {
return true;
}
}
return false;
}
public Object getFirst() {
i = 0;
return objects[i++];
}
public Object getNext() {
if (i < size)
return objects[i++];
else
return null;
}

public boolean remove(Object object) {


for(int i = 0; i < size; i++) {
if(objects[i] == object) {
System.arraycopy(objects, i + 1, objects, i, size - i -1);
objects[--size] = null;
return true;
}
}
return false;
}

public int size() {


return size;
}

The line “public class ArrayBag implements Bag” indicates that the class

ArrayBag is implementing the Bag interface. Consider the line,

private Object[] objects = new Object[1000];

It defines an array called “objects” that can contain thousand objects. The integer variable
“size” keeps track of the number of objects or elements in the array. Note that all the operations
or methods described in the Bag interface are materialized or implemented in the class ArrayBag
accordingly. You can create an ArrayBag object with a statement like,

Bag bagOfFruits = new ArrayBag();

With the above statement an array of Obejct type will be created that can accommodate thousand
objects and it will be labeled bagOfFruits.

Then you can add elements or objects to your bagOfFruits with the add method. For example,
you can add an apple, a lemon and an avocado to the bag with the following code segment.

bagOfFruits.add(“Apple”); bagOfFruits.add(“Lemon”);
bagOfFruits.add(“Avocado”);

Index: 0 1 2 …
Contents

Position: 1 2 3

The above statements will add the String objects “Apple”, “Lemon” and “Avocado” to the
array. After adding objects, you can check whether an object is inside our bag. The method
contains will check whether a particular object is contained within the bag and if the object
provided as the argument is in the array, bagOfFruits the method contains will return true and
if not it will return false. If we assume that there is atleast one lemon and no oranges in the bag.

bagOfFruits.contains(“Lemon”); // will return true


bagOfFruits.contains(“Orange”); // will return false

The getFirst method will output the first object in the array and the getNext method will fetch the
subsequent items of the array.
The remove method will eliminate a given object from the array. The method will search through
the array starting from the first element and if a match is found it will be removed by shifting all
the array elements that follow, back one position. Of course, the size of the array will also be
decreased by one. To achieve this we use the predefined method arraycopy provided in Java.
The method takes into consideration five arguments in the following order.

arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

The two Object arguments src and dest specify the array to copy from and the array to copy
to. The three int arguments srcPos, destPos and length specify the starting position in the
source array, the starting position in the destination array, and the number of array elements to
copy, respectively.
for(int i = 0; i < size; i++) {
if(objects[i] == object) {
System.arraycopy(objects, i + 1, objects, i, size - i -1);
objects[--size] = null;
return true;
}
}
The above code fragment will do the trick for us. Assume that the object to be removed is found
at the “n” th position of the array. If objects[0] is equal to the item to be removed then n is
equal to one (1 = 0 + 1). If objects[1] is equal to the item to be removed then n is equal to two
(2 = 1 + 1). Understandably, if objects[i] is equal to the item to be removed then n is equal to
i + 1. Assuming that the object or the element to be removed is equal to objects[i], the
arguments for the arraycopy method is clear.

src = objects
= i+1
srcPos
dest = objects

destPos = i (the desired object is removed by replacing it with the object


succeeding it)

length = size – (i + 1) = size – i – 1

Note that the source (src) object and the destination (dest) object is the same.

Index: 0 1 2 … … i i+1 … …
Contents

Position: 1 2 3 i+1 i+2 … …

The statement,

bagOfFruits.remove(“Orange”); // bagOfFruits[i] == “Orange” would

yield the following:


Index: 0 1 2 … … i i+1 … …
Contents

Position: 1 2 3 i+1 i+2 … …

The size method will return the number of objects or elements in the array.

Now let us develop a test driver class to check whether our Bag ADT and its ArrayBag
implementation are working. In the test program, we will first create a reference to Bag objects
and then add some fruits. Next, we will use the methods to observe and manipulate our bag.
Listing 2.3: A test driver class to check the Bag ADT and its implementation ArrayBag

public class TestBagADT {


public static void main(String[] args) {
Bag bagOfFruits = new ArrayBag();

// Add friuts to the bag


bagOfFruits.add("Lemon"); bagOfFruits.add("Apple");
bagOfFruits.add("Apple");
bagOfFruits.add("Apple");
bagOfFruits.add("Orange");
bagOfFruits.add("Avocado"); bagOfFruits.add("Lemon");
bagOfFruits.add("Apple");
bagOfFruits.add("Orange"); bagOfFruits.add("Apple");
bagOfFruits.add("Apple");
bagOfFruits.add("Orange");
bagOfFruits.add("Orange"); bagOfFruits.add("Apple");
bagOfFruits.add("Avocado");
bagOfFruits.add("Apple"); bagOfFruits.add("Apple");
bagOfFruits.add("Apple");
bagOfFruits.add("Orange");
bagOfFruits.add("Avocado");
bagOfFruits.add("Orange");

// Get the number of fruits in the bagOfFruits


System.out.println("There are " + bagOfFruits.size() + " fruits in the bag.");

// Print the first object/element in the bag


System.out.println("The first element in the bag is: " + bagOfFruits.getFirst());

// Print the next element in the bag


System.out.println("The next element in the bag is: " + bagOfFruits.getNext());

// Check whether there are apples in the bag


System.out.println("There is an apple in the bag. It is " +
bagOfFruits.contains("Apple") + ".");

// Check whether there are pears in the bag


System.out.println("There is a pear in the bag. It is " +
bagOfFruits.contains("Pear") + ".");

// Print the contents of the bag


printBag(bagOfFruits);
// Remove an orange from the bag
bagOfFruits.remove("Orange");

System.out.println("The contents of the bag after removing the


orange.");
// Print the contents of the bag
printBag(bagOfFruits);

// Remove all apples from the bag


int numberOfApplesRemoved = removeAll("Apple", bagOfFruits);
System.out.println(numberOfApplesRemoved + " apples were removed from the bag.");

System.out.println("The contents of the bag after removing all the apples.");


// Print the contents of the bag
printBag(bagOfFruits);

// Add a Pear
bagOfFruits.add("Pear");

System.out.println("Contents in the bag after adding a pear.");


// Print the contents of the bag
printBag(bagOfFruits);
}

// A client method that will print the contents of the bag


public static void printBag(Bag bag) {
Object x = bag.getFirst();
int i = 1;
System.out.println("The contents are:");
while (x != null) {
System.out.println("Element "+ i++ + ": " + x);
x = bag.getNext();
}
}
// A client method that will remove all instances of an object/element
public static int removeAll(Object object, Bag bag) {
int n = 0;
while(bag.remove(object))
++n;
return n;
}

Try to predict the outcome of the program without running it. It would be something like,

There are 21 fruits in the bag.


The first element in the bag is: Lemon
The next element in the bag is: Apple
There is an apple in the bag. It is true.
There is a pear in the bag. It is false.

The contents are:


Element 1: Lemon
Element 2: Apple
Element 3: Apple
Element 4: Apple
Element 5: Orange
Element 6: Avocado
Element 7: Lemon
Element 8: Apple
Element 9: Orange
Element 10: Apple
Element 11: Apple
Element 12: Orange
Element 13: Orange
Element 14: Apple
Element 15: Avocado
Element 16: Apple
Element 17: Apple
Element 18: Apple
Element 19: Orange
Element 20: Avocado
Element 21: Orange
The contents of the bag after removing the orange.
The contents are:
Element 1: Lemon
Element 2: Apple
Element 3: Apple
Element 4: Apple
Element 5: Avocado
Element 6: Lemon
Element 7: Apple
Element 8: Orange
Element 9: Apple
Element 10: Apple
Element 11: Orange
Element 12: Orange
Element 13: Apple
Element 14: Avocado
Element 15: Apple
Element 16: Apple
Element 17: Apple
Element 18: Orange
Element 19: Avocado

Element 20: Orange


10 apples were removed from the bag.
The contents of the bag after removing all the apples.
The contents are:
Element 1: Lemon
Element 2: Avocado
Element 3: Lemon
Element 4: Orange
Element 5: Orange
Element 6: Orange
Element 7: Avocado
Element 8: Orange
Element 9: Avocado
Element 10: Orange
Contents in the bag after adding a pear.
The contents are:
Element 1: Lemon
Element 2: Avocado
Element 3: Lemon
Element 4: Orange
Element 5: Orange
Element 6: Orange
Element 7: Avocado
Element 8: Orange
Element 9: Avocado
Element 10: Orange
Element 11: Pear
We have defined two client methods in our test driver program, viz., printBag and removeAll.
Note that it is neither a member of the Bag interface nor its implementations’ ArrayBag. Both
the methods use the Bag interface as a Java type.

With this, we conclude our lesson.

Activity 1.1
Define a Counter ADT. An instance of this type would be an object like a hand held counter
device for counting things like cars in a parking lot. The object stores a single nonnegative
integer (the current count). It can be incremented, it can be reset to zero and its current value
can be read at any time. Specify an ADT and translate it into a Java interface.

Summary

In this lesson, you learned what a data type is, what “abstraction” is and what an Abstract Data
Type (ADT) is and how we can build concrete data types from ADTs. In the next lesson, you
will learn about basic ADTs called ARRAYS and linked lists.

You might also like