26A. Lists


Abstract data types

You have seen the Equivalence Manager. It has two conceptual parts:

  1. a type, Equiv, and

  2. an interface telling just which functions (merge and together) are provided.

There are also two implementation parts:

  1. a way of representing a thing of type Equiv, and

  2. definitions of the functions in the interface, plus a definition of a helper function, leader.

The equivalence manager is an example of an abstract data type (ADT) and its implementation. In general, an ADT has the following parts.

  1. There is a type. Let's call it T.

  2. The ADT describes what objects of type T are, at a conceptual level.

  3. The ADT also contains an interface listing functions and constants that are available for type T and saying what those functions do in conceptual terms.

An ADT implementation is a way of providing for the ADT in a program. It has two main parts.

  1. There is a representation of objects of type T that tells how those objects are stored in the memory.

  2. There are algorithms for carrying out the functions in the interface, eventually expressed in a programming language. The algorithms usually depend heavily on the data representation.

With this page, we begin to look at an ADT list of integers, an implementation of that ADT and ideas for developing algorithms.


Conceptual lists and a notation for writing lists

A list of integers is a sequence of zero or more integers. We write lists in square brackets, such as [2, 4, 6]. The order matters; the first member of [2, 4, 6] is 2, the second member is 4 and the third member is 6. There can be repetitions. For example, [1, 1, 1, 1] is a list of four integers.

List [3] is a list with one integer; it is not the same as the number 3 because it does not have the same type; 3 is a number but [3] is a list. The empty list is written [ ].


Operations on conceptual lists

We will use the following notation for working with conceptual lists. These are the operations of the ADT. Notice that all of this is at the conceptual level; it is not C++ notation.

head(L)

The head of a list is the first member of the list. For example, head([2, 4, 6, 8]) = 2 and head([5]) = 5. Notice that the parameter of head must be a list, and its result is an integer.

The empty list does not have a head, and computing head([ ]) is an error.


tail(L)

The tail of a list L is the list that you get by removing the first member of L. Here are some examples.
  • tail([2, 4, 6, 8, 10]) = [4, 6, 8, 10]

  • tail([5, 4, 3, 2]) = [4, 3, 2]

  • tail([3, 6]) = [6]

  • tail([2]) = [ ]

The tail of a list is always a list. The empty list has no tail, and computing tail([ ]) is an error.


h:t

Expression h:t is the list whose head is h and whose tail is t. Here are some examples.
2:[4, 6, 8] = [2, 4, 6, 8]
7:[1, 2] = [7, 1, 2]
8:[4] = [8, 4]
5:[ ] = [5]

Notice that the left-hand operand of : is always an integer and the right-hand operand is always a list. Expression h:t always yields a list, namely the list that you get by adding h to the beginning of list t. Don't expect it to do anything else.

By convention, operator : is right associative. That is, it is done from right to left. So

2:4:6:[ ] = 2:4:[6]
= 2:[4, 6]
= [2, 4, 6]

isEmpty(L)

Expression isEmpty(L) is true if L is an empty list.

emptyList

Constant emptyList is an empty list. (We write [ ] for it, but it is important to realize that an empty list is a key component of the abstract data type.)


Exercises

  1. What is head([3, 2, 1])? Answer

  2. What is tail([3, 2, 1])? Answer

  3. What is 9:[4, 7, 1]? Answer

  4. What is 2:[]? Answer

  5. What is tail([2])? Answer

  6. Does tail([ ]) have a value? If so, what is it? Answer

  7. Does [2, 4, 6]:8 have a value? If so, what is it? Answer