Stacks

Course links

Exercise 1

Documents on the World Wide Web usually contain special strings, called tags, that serve as instructions to the browser about what the document contains, how it is structured, and how the text should be displayed. In many cases, tags occur in pairs: The opening tag marks the beginning of a region of text that constitutes some natural unit within the document structure or should be displayed in some special way, and closing tag marks the end of that region.

An opening tag is a sequence of letters and digits enclosed between a less-than character at the beginning and a greater-than character at the end. For instance, "<html>" is the opening tag for a document that contains hypertext markup, and "<title>" is the opening tag for the title of such a document. The corresponding closing tags look almost the same, but a closing tag has a slash character after the less-than character: "</html>", "</title>".

Create a new stack and name it tags. Push onto this stack the opening tag "<html>". Next, push "<head>", the tag that begins the header of a hypertext document, and then "<title>". Now pop the stack. The tag that appears is the one that must be matched first by a closing tag in order for the tags to be correctly nested. Pop the stack two more times and confirm that the stack is a ``last-in, first-out'' data structure.

Exercise 2

Netscape and other browsers use a stack of tags like this one -- a stack containing tags that must eventually be matched but have not been matched yet -- to determine whether the HTML document to be displayed is correctly constructed. Write a Scheme procedure correctly-nested? that takes a list of HTML opening and closing tags and determines whether they are correctly nested.

> (correctly-nested? '("<html>" "<head>" "<title>" "</title>" "</head>" "<body>" "<b>" "</b>" "</body>" "</html>"))
#t
> (correctly-nested? '("<html>"  "<head>" "</html>" "</head>"))
#f

Exercise 3

Some authors add a sixth operation to the definition of the stack ADT: size, which returns the number of elements in the stack. Extend the Scheme implementation of make-stack in the reading so that the stacks it constructs will accept the message :size and perform this operation when it is received.

Exercise 4

The yield of a pair structure is a list of its ``leaves'' -- the values that are contained in the pair structure but are not themselves pairs (and are not empty lists). For instance, the yield of the pair structure (((1 . 2) . 3) . (4 . (5 . 6))) is the list (1 2 3 4 5 6).

Using a stack to keep track of unfinished parts of the problem, as in today's reading, define a tail-recursive procedure called yield that takes any pair structure and returns its yield.

Exercise 5

Define a procedure called copy-stack that takes a stack as argument and returns a new stack with exactly the same contents. Note that it is not possible to do this without popping the given stack repeatedly, to recover each of its elements in turn. Make sure that your procedure restores every element that is popped from the given stack by pushing it back on again before it returns the new stack.

Exercise 6

Define a predicate called stack-equal? that takes two stacks as arguments and determines whether they contain the same elements (as tested by equal?) in the same order. Again, it is not possible to do this without popping the given stacks, so make sure that your procedure restores the elements it pops before returning.

Acknowledgements

I am indebted to Professor Henry Walker for some of the exercises in this lab.