Create Presentation
Download Presentation

Download Presentation
## ITB001 Problem Solving and Programming Lecture 8

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -

**ITB001Problem Solving and ProgrammingLecture 8**Faculty of Information Technology Queensland University of Technology**Aims of this lecture**• This lecture further illustrates the notion of data abstraction with three important examples, tables, trees and tagged data • Tables introduce some of the basic operations needed to maintain databases • Trees are a commonly-used recursive data structure for sorting data • Tagged data items allow different representations of data values to coexist**References**• Concrete Abstractions: An Introduction to Computer Science Using Scheme, page 532 and Sections 8.1, 8.2 and 9.3 • Structure and Interpretation of Computer Programs, Sections 2.2.2, 2.3.3 and 2.4.2**The notion of tables**• The idea of a table of values is a familiar way of associating a ‘key’ with a particular value • For example, the following table associates names (the keys) with heights (in metres)**The notion of tables**• Given such a table we can look up the values to discover, for instance, that Harpo’s height is 1.62m • However, we cannot use this table to learn Zeppo’s height because key ‘Zeppo’ does not appear in the table • The particular table shown above is unsorted, although we could choose to order the table by key**A simple data representation for tables**• An easy way to represent a table is as an association list, i.e., a list of key-value pairs • An advantage of using lists is that we can easily increase the size of the table • Association lists are not a very efficient data structure for large databases, but are suitable for maintaining small tables**A simple data representation for tables**• For example, the table of heights above could be represented in Scheme as the following nested list of strings and numbers: • (list (list "Groucho" 1.57) • (list "Harpo" 1.62) • (list "Chico" 1.61)) • However, as usual, we don’t want users of tables to be aware of this underlying data representation • Preventing this allows us to change the represent-ation to a more efficient one such as a ‘hash table’**Exercise 8-1: Some basicoperations on tables**• Define the following procedures for tables, using association lists as the data representation • (make-table) is a parameterless constructor that returns an empty table • (add-to-table kvt) is an operation that returns table t with a new association between key k and value v (overriding any previous association) • (lookup-table kt) is a selector that returns the value in table t associated with key k, or returns string "ERROR" if there is no such key in the table**Exercise 8-1: Some basicoperations on tables**• Example: • (define heights • (add-to-table "Chico" 1.61 • (add-to-table "Harpo" 1.62 • (add-to-table "Groucho" 1.57 • (make-table))))) • (lookup-table "Harpo" heights) returns 1.62 • (lookup-table "Zeppo" heights) returns "ERROR"**Exercise 8-1: Some basicoperations on tables**• Example: • (define heights • (add-to-table "Zeppo" 1.59 heights)) • (lookup-table "Zeppo" heights) returns 1.59 • (define heights • (add-to-table "Harpo" 1.58 heights)) • (lookup-table "Harpo" heights) returns 1.58**Exercise 8-2: Removingassociations from a table**• So far we have been able to make our tables grow larger only • Define a procedure (remove-from-table kt) which returns table t with any association for key k removed • If key k did not appear in table t then remove-from-table should just return table t unchanged • If key k appears more than once in table t then all such associations should be removed**Exercise 8-2: Removingassociations from a table**• Example: • (define heights • (add-to-table "Chico" 1.61 • (add-to-table "Harpo" 1.62 • (add-to-table "Groucho" 1.57 • (make-table))))) • (lookup-table "Harpo" heights) returns 1.62**Exercise 8-2: Removingassociations from a table**• (define heights • (remove-from-table "Harpo" heights)) • (lookup-table "Harpo" heights) returns "ERROR"**Exercise 8-3: Maintaining a sorted table**• For efficient searching we may want to keep entries in the table sorted by key • We can do this by defining a version of procedure add-to-table that always puts associations in the right place • However, to know what the ‘right’ place is we need to know what criterion is used to sort keys • Define a new procedure (add-to-table kvpt) which accepts a predicate p that can be applied to two keys to determine their order**Exercise 8-3: Maintaining a sorted table**• Procedure add-to-table should add the new association to the table in a position such that the key of the preceding association (if any) is ‘less than’ key k, according to predicate p, and the key of the succeeding association (if any) is ‘greater than’ key k, according to predicate p • If table t already contained an association for key k the old association should be removed from the table • You can assume that table t is already sorted and that key k occurs at most once in table t**Exercise 8-3: Maintaining a sorted table**• Example: • (add-to-table "Chico" 1.61 string<? • (add-to-table "Harpo" 1.62 string<? • (add-to-table "Groucho" 1.57 string<? • (make-table)))) • orders associations by predicate string<? and represents the table as • (list (list "Chico" 1.61) • (list "Groucho" 1.57) • (list "Harpo" 1.62))**Exercise 8-3: Maintaining a sorted table**• Comment: To explain the example above we broke the data abstraction barrier for tables • A user of tables should not directly examine (or even care about) their representation**Data abstraction barriersin the tables case study**• With these operations on tables in place it is now possible to use tables without even knowing that they are implemented using association lists • This would allow us to change the representation of tables, or otherwise modify the operations on them, without affecting users of tables**Data abstraction barriersin the tables case study**Programs that use tables Tables in the problem domain lookup-table add-to-table … Tables as association lists cons first rest … Scheme’s implementation of lists**The importance of trees**• Trees are one of the most important data structures in computing and are used to solve a wide variety of data structuring, sorting and searching problems • Like lists, they are an example of a recursively-defined data structure • Indeed, we will build our data abstraction for trees on top of that for lists**An obvious example of a tree is the directory structure of**your computer Each folder is the root of a tree with branches containing other folders and files Each file is a leaf that ends a branch A common example A B 1 2 3 C D 4 5**A conventional notation**• Traditionally, trees are drawn as directed graphs which ‘grow’ downwards • Thus the root is at the top and the leaves are at the bottom A C B 1 2 3 D 5 4**Binary trees**• In general a node within a tree may have any number of branches • In the preceding example node B had three branches • However, an important special case is that of binary trees whose nodes have at most two branches • Binary trees are commonly used for storing values in a particular order so that they can be retrieved quickly**An ordered binary tree is one in which, for all nodes, all**values in its left-hand branch are ‘less than’ the root value and all values in its right-hand branch are ‘greater than’ the root value The tree on the right is ordered by the ‘<’ relationship for numbers Ordered binary trees 4 2 5 1 3**A data structure forrepresenting binary trees**• In Scheme we can represent trees easily using nested lists • Each node in the tree can be represented as a list of length three, containing the node’s value and the left and right branches • If the tree is a leaf then both the branches will be the empty tree • The empty tree can be represented by the empty list**A data structure forrepresenting binary trees**• Example: The following list represents the ordered binary tree shown on the right • (list 4 • (list 2 • (list 1 empty empty) • (list 3 empty empty)) • (list 5 empty empty)) 4 2 5 1 3**A data structure forrepresenting binary trees**• Example: The following binary tree is unordered • (list 7 • (list 9 • (list 6 empty empty) • (list 3 • (list 4 empty empty) • empty))) • (list 0 • (list 8 • empty • (list 2 empty empty)) • (list 5 empty empty))) 7 9 0 3 8 5 6 4 2**A data abstraction for binary trees**• However, representing trees using lists in this way exposes the underlying data structure • Instead, we should define meaningful constructors, selectors and other operations on binary trees that hide the way we have chosen to implement trees • We can represent the empty tree by a special value: (define stump empty)**A data abstraction for binary trees**• The following two constructors are convenient for creating a tree with two branches and a tree with no branches, respectively: (define [root root-value left-branch right-branch] (list root-value left-branch right-branch)) (define [leaf leaf-value] (root leaf-value stump stump))**A data abstraction for binary trees**• The following three selectors for extracting parts of a given tree are defined easily as synonyms of the corresponding list operations: (define root-value first) (define left-branch second) (define right-branch third)**A data abstraction for binary trees**• The following two predicates are helpful when traversing trees: (define stump? empty?) (define [leaf? tree] (and (not (stump? tree)) (stump? (left-branch tree)) (stump? (right-branch tree)))**A data abstraction for binary trees**• Using these constructors we can define a binary tree in a more readable way: • (root 4 • (root 2 • (leaf 1) • (leaf 3)) • (leaf 5)) 4 2 5 1 3**A data abstraction for binary trees**• Similarly in this more complicated case: • (root 7 • (root 9 • (leaf 6) • (root 3 • (leaf 4) • stump))) • (root 0 • (root 8 • stump • (leaf 2)) • (leaf 5))) 7 9 0 3 8 5 6 4 2**Counting leaves**• Given this representation we can easily write a recursive procedure for counting the leaves in a tree: (define [count-leaves tree] (cond [(stump? tree) 0] [(leaf? tree) 1] [else ; node is the root of a sub-tree (+ (count-leaves (left-branch tree)) (count-leaves (right-branch tree)))] ))**Counting leaves**• Procedure count-leaves has two base cases: • One for a leaf • One for an empty tree (‘stump’) • It also makes two recursive references to itself: • One for the left branch of a sub-tree • One for the right branch of a sub-tree**The computational processfor counting leaves**(count-leaves (root 9 (root 5 (leaf 8) stump) (root 3 (leaf 2) (leaf 4)))) = (+ (+ 1 0) (+ 1 1)) = 3 (+ 9 (+ 5 (+ 3 0) 8 2 4 1 1 1))**Exercise 8-4: Depth of a binary tree**• We define the ‘depth’ of a tree as the length of the longest path from the root to a leaf • In the case of sorted trees, this tells us how many steps will be required to find an item in the worst case • Define a procedure tree-depth which returns the maximum depth of a given binary tree**Exercise 8-4: Depth of a binary tree**• Examples: • (tree-depth stump) returns 0 • (tree-depth (leaf 8)) returns 1 • (tree-depth (root 9 • (root 5 • (leaf 2) • (leaf 6)) • (leaf 4))) returns 3**Exercise 8-4: Depth of a binary tree**• (tree-depth (root "a" • (leaf "z") • stump)) returns 2**Exercise 8-5: Binary tree predicate**• We have seen that Scheme provides numerous predicates for checking to see what the type of a given value is, e.g., number?, list?, string?, etc • Having introduced a notion of binary trees we should similarly define a predicate for checking to see whether a given data structure is a properly-formed tree • In addition, we will check that the tree is homogeneous in the sense that all of its leaves are of the same type**Exercise 8-5: Binary tree predicate**• Define a higher-order procedure check-tree which accepts a type predicate (such as number?, string?, etc) • Procedure check-tree should return a predicate (a Boolean-valued procedure) which accepts a data structure and returns #t (logical true) only if the structure is a well-formed binary tree and all the leaves are of the right type**Exercise 8-5: Binary tree predicate**• Example: • (define tree-of-strings? • (check-tree string?)) returns a procedure which tests to see if a given data structure is a binary tree containing only strings • (tree-of-strings? • (root "a" • (leaf "b") • (root "c" stump • (leaf "d")))) returns #t**Exercise 8-5: Binary tree predicate**• (tree-of-strings? • (root 1 (leaf 2) • (leaf 3))) returns #f because the values in the tree are not strings • (tree-of-strings? • (list "a" • (list "b") • (list empty (list "c")))) returns #f because the data structure is not a properly-formed binary tree**Manipulating the values in a tree**• Given a tree of numbers, the following procedure multiplies all the values by a given factor: (define [scale-tree numbers factor] (if (stump? numbers) stump (root (* factor (root-value numbers)) (scale-tree (left-branch numbers) factor) (scale-tree (right-branch numbers) factor))))**Manipulating the leaves of a tree**• Example: • (scale-tree • (root 4 (root 2 (leaf 1) (leaf 3)) • (leaf 5)) • 10) • returns • (root 40 (root 20 (leaf 10) (leaf 30)) • (leaf 50)) • Thought exercise: Why didn’t procedure scale-tree need to treat leaves as a special case?**Cloning trees**• Like count-leaves, the scale-tree procedure ‘walks’ through the given tree by following the branches • However, rather than returning a single value, it returns a whole tree • Importantly, the tree that is returned is built with tree constructor root and special value stump • The returned tree is not the same tree provided as an argument to procedure scale-tree • It is a new tree with the same ‘shape’ as the original one**Exercise 8-6: Largest number in a tree**• Define a procedure tree-max which returns the largest value in a (not necessarily sorted) binary tree of non-negative numbers (or 1 if the tree is just a stump) • Examples: • (tree-max stump) returns -1 • (tree-max • (root 6 • (root 7 (leaf 1) (leaf 8)) • (leaf 2))) returns 8**Exercise 8-6: Largest number in a tree**• (tree-max • (root 4 • (root 8 • (root 5 (leaf 7) stump) • (leaf 2)) • (root 5 (leaf 9) stump))) • returns 9