Week02 Lesson 01 Abstract Data Types M
Week02 Lesson 01 Abstract Data Types M
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.
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.
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.
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.
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.
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.
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.
Bags are containers – they hold things. Fundamental operations with all bags are;
ADT: Set
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.
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,
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.
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
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
The line “public class ArrayBag implements Bag” indicates that the class
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,
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.
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
Note that the source (src) object and the destination (dest) object is the same.
Index: 0 1 2 … … i i+1 … …
Contents
The statement,
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
// Add a Pear
bagOfFruits.add("Pear");
Try to predict the outcome of the program without running it. It would be something like,
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.