# Class 30: The Design of Lists

Back to Data Structures. On to Discussion of Exam 2.

Held Friday, October 15, 1999

Overview

Today we will consider the design of a particular data structure: the list. Surprisingly, there are a number of perspectives on lists.

Notes

• The exam is due today, at the start of class.
• Extra credit (2 points): For each problem, indicate about how much time you spent on the problem.

Contents

Summary

• The design of lists
• A data-oriented perspective
• A function-oriented perspective
• Some other design issues
• An implementation of Scheme-like lists
• Due:

## Lists

• Lists are among the simplest of data structures.
• Like arrays, they are used for collecting data. That is, lists can be used to store and retreive data.
• In effect, a list is an linearly-organized collection of information.
• Every nonempty list has a unique first element.
• Every nonempty list has a unique last element.
• Every element except the last has a unique successor.
• Each element except the first has a unique predecessor.
• Note that this is a data-oriented description of lists. Is there also a function-oriented description of lists?
• Suprisingly, different computer scientists have very different views of the operations lists might provide and the meanings of those operations.
• For example, some expect that the elements in the list stay in the same order after different operations. Others don't.
• That's nothing compared to the Lisp vs. everything else controversy.

### Scheme-Like Lists

• Let us begin our consideration of the functions for lists by viewing lists from the Scheme perspective.
• What are the core list functions? These are the ones I've come up with:
• `cons`: Create a list, given a head and a tail.
• `car` and `head`: Get the first element of the list.
• `cdr` and `tail`: Get all but the first element of the list.
• `setcar!` (boo! hiss!): Change the first element of the list.
• `setcdr!` (boo! hiss!): Change the rest of the list.
• Everything else can be built with these five.
• How might we phrase these in Java? Note that they correspond fairly closely to the methods we would expect to see for a class with two fields (`head` and `tail`).
• `cons` is the constructor.
• `car` and `cdr` get the two fields.
• `setcar!` and `setcdr!` set the two fields.
• Here's how we might write this in Java:
```
/**
* A simple implementation of lists, similar to the lists provided
* by languages like Scheme and LISP.  Created as an example for
* CSC152.
*
* @author Samuel A. Rebelsky
* @version 1.0 of October 1999
*/
public class SchemeList {
// +--------+--------------------------------------------------
// | Fields |
// +--------+

/** The first element in the list. */

/** The remainder of the list. */
protected SchemeList tail;

// +--------------+--------------------------------------------
// | Constructors |
// +--------------+

/** Build a new list with specified head and tail. */
public SchemeList(Object head, SchemeList tail) {
this.tail = tail;
} // SchemeList(Object, SchemeList)

// +-----------------------------------------------------------
// | Extractors |
// +------------+

/**
* Get the head of the list.
* Pre: The list is initialized and nonempty.
* Post: Returns the first element of the list.
* Post: Does not modify the list.
*/

/**
* Get the tail of the list.
* Pre: The list is initialized and nonempty.
* Post: Returns all but the first element of the list (as a list).
* Post: Does not modify the list.
*/
public SchemeList tail() {
return this.tail;
} // tail()

// +-----------+-----------------------------------------------
// | Modifiers |
// +-----------+

/**
* Set the first element of the list to newHead.
* Pre: The list is initialized.
* Post: The remainder of the list is not modified.
*/

/**
* Set the remainder of the list to newTail.
* Pre: The list is initialized.
* Post: Subsequent calls to tail return newTail (until the
*   tail is updated again).
* Post: The head of the list is not modified.
*/
public void setTail(SchemeList newTail) {
} // setTail(SchemeList)

} // class SchemeList

```
• To create the list `(a b c)`, we might write
```    SchemeList c = new SchemeList("c", null);
SchemeList bc = new SchemeList("b", c);
SchemeLists abc = new SchemeList ("a", bc);
```
• We could also write the following (a more abbreviated form)
```    SchemeList abc =
new SchemeList("a",
new SchemeList("b",
new SchemeList("c",
nil)));
```
• Note that these differ from Scheme lists in one fundamental respect: Scheme lists can take any type (not just lists) as the second parameter to the constructor.
• Because these are also Java objects, we might want to consider how to add a `toString` method.
• There are also a number of common operations we might want to support, such as `map`, `length`, `member`, .....

### Lists as Collections

• There are also other ways to think about lists in terms of functions.
• For example, we might think about lists that more closely resemble the collection interface.
• What are possible operations?
• We won't include all of these, but they're some to consider.
• Creation of new, empty, lists.
• Should we specify the type of elements?
• Should we specify the capacity?
• Insertion of elements in the list.
• Where?
• Deletion of elements from the list.
• Where?
• Determine size of the list.
• Test emptiness of the list.
• Is this just related to the size?
• Test containment of objects in the list.
• Modification of elements in the list.
• Is this just insertion and deletion?
• Iteration of the list
• Stepping through the elements, perhaps as in `map`.
• As we design various kinds of lists, we may choose different subsets of these operations, and fill in more details.

### Kinds of Lists

• There are a number of different ``kinds'' of lists, relating, in part, to the way in which the user thinks of using them, adding to them, and getting elements from them.
• We'll consider three different ones. After a high-level overview, we'll return to each in more detail.
• The simplest lists simply provide the linear structure, but with no user control over that structure. The user can add and delete elements, but not determine where added elements go in the list (or what happens during deletion).
• The list cannot rearrange itself unless elements are added or removed.
• We add some complexity and usefulness by giving the user some control over where elements go in the list. Such lists might be called sequenced lists.
• The simplest control is simply to say ``new elements go at the end/front, and elements never change position''.
• We might also add a ``current'' element and insert before or after it.
• We might also impose a predetermined order (a ``sort order'') on the list and require that it be iterated in that order.
• Insertion and deletion ensure that the sort order is maintained.

### Lists vs. Arrays

• Both lists and arrays provide mechanisms for collecting information.
• Unlike arrays, lists do not necessarily guarantee constant time access to each element. (No matter what form of list you consider.)
• However, lists do (usually) guarantee constant time insertion of elements at a few places in the list.
• Some list implementations guarantee constant time insertion at the front of the list.
• Some list implementations guarantee constant time insertion at the end of the list.
• Some list implementations provide a ``current element'' (also called a cursor) and guarantee constant time insertion after/before the current element.

### Design Issues

• Before we implement lists, we need to consider a number of other issues related to the design of lists.
• There are a number of ways in which we can implement lists, and these implementations govern the cost of the various operations.
• Most programmers expect that insertion and testing for emptiness are constant time operations. Certain kinds of deletion are also constant time (e.g., delete the first element).
• There are a number of hidden issues to consider when designing implementations.
• We might speak about sharing of sublists.
• For example, when we ask for the `tail` of a list and then modify that tail, do we modify the original list?
• Here's one example in Java form
```   // Assume l is the list (aardvark zebra bison chipmunk)
SchemeList lprime = l.tail();
```
• Here's a similar example that might have different results (at least in terms of our understanding of what modifications mean). Note that it includes some ``obvious'' methods that are not yet part of the `SchemeList` class.
```  // Assume l is the list (aardvark zebra bison chipmunk)
SchemeList lprime = l.tail();
lprime.remove("bison");
out.println(l.contains("bison"));
```
• In designing our implementations, we will need to consider tradeoffs between efficiency, memory usage, simplicity of implementation, and ambiguity.

## History

Tuesday, 10 August 1999

• Created as a blank outline.

Friday, 15 August 1999

• Filled in the details. Some were taken from the previous outline (introductory section on lists). Some were created anew (Scheme-like lists).
• Reorganized material taken from previous outline and updated examples.
• Added introductory notes and such.

Back to Data Structures. On to Discussion of Exam 2.

Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.