There are three primary reasons for us to be aware of the fundamental concepts underlying ADTs as we embark on the study of algorithms and data structures:
Ideally, ADTs embody the common-sense principle that we are obligated to describe precisely the ways in which we manipulate our data. The client-interface-implementation mechanism that we have considered in detail in this chapter is convenient for this task in Java, and provides us with Java code that has a number of desirable properties. Many modern languages have specific support that allows the development of programs with similar properties, but the general approach transcends particular languages—when we do not have specific language support, we adopt coding conventions to maintain the separation that we would like to have among clients, interfaces, and implementations.
As we consider an ever-expanding set of choices in specifying the behavior of our ADTs, we are faced with an ever-expanding set of challenges in providing efficient implementations. The numerous examples that we have considered illustrate ways of meeting such challenges. We continually strive to achieve the goal of implementing all the operations efficiently, but we are unlikely to have a general-purpose implementation that can do so for all sets of operations. This situation works against the principles that lead us to ADTs in the first place, because in many cases implementors of ADTs need to know properties of client programs to know which implementations of associated ADTs will perform most efficiently, and implementors of client programs need to know performance properties of various implementations to know which to choose for a particular app. As ever, we must strike a balance. In this tutorial, we consider numerous approaches to implementations for variants of fundamental ADTs, all of which have important apps.
We can use one ADT to build another. We have used the pointer and structure abstractions provided by Java to build linked lists, then we have used linked lists or the array abstraction provided by Java to build pushdown stacks, then we have used pushdown stacks to get the capability to evaluate arithmetic expressions. The ADT concept allows us to construct large systems on different layers of abstraction, from the machine-language instructions provided by the computer, to the various capabilities provided by the coding language, to sorting, searching and other higher-level capabilities provided by algorithms as discussed in Parts III and IV of this tutorial, to the even higher levels of abstraction that the various apps require, as discussed in Parts 5 through 8. ADTs are one point on the continuum of developing ever more powerful abstract mechanisms, which is the essence of using computers effectively in problem solving.