Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Introduction to Computer Science Unit 19 • Stacks and Queues • More Recursion and Pointers Stacks • Stacks: new records added to one end and taken off from the same end; last-in, firstout, LIFO • We can talk about the abstract data structure “stack” without knowing anything about the “values” that it stores: –Push means “save a value” –Pop means “get the value that was saved most recently” –Empty means “there are no values to pop” 19- 2 More Stack Operations • There are some more primitive operations that might be relevant, depending on how we implement the stack: –Remove means “remove all of the stack’s contents” returning space to memory (relevant for pointer-based stack) –Full means “there’s no more room to push values” (relevant for an array-based stack) 19- 3 The Stack Name Layer (no commitment as to implementation) Objects of class DataNode, of stored items, doesn’t have to be defined yet; these are methods of the Stack class: boolean empty ( ) {…} // true if there are no pushed values void push (DataNode newItem) {…} // Add newItem to stack DataNode pop ( ) {…} // Remove the top item from the stack and return it void remove ( ) {…} // Dispose of any current stack contents 19- 4 Question • pop, push, etc. are primitives; how would we define, in terms of the primitives, top( ), which gets a copy of the top value of a stack but doesn’t remove that value? We pop the top value, copy it, then push it back onto the stack (assume copyData( ) copies one DataNode object to another): if ( !stack.empty( ) ) { item = stack.pop( ); // Pop the top value… newItem.copyData(item); // …copy it… stack.push(item); //then push it back onto the stack } 19- 5 The Implementation Layer • Now we have to implement it • Pointers are often used to build stacks because (as I said) a linked list can get longer, while arrays are limited to their defined size push null <<<< <<<< First Second Third _last Data _value _last _value A Stack _last _value pop head empty remove 19- 6 Two-class Encapsulation of a Linked List Stack (here's the node class, for inside) class DataNode { private int _value; private DataNode _last; public DataNode (int val, DataNode node) { _value = val; _last = node; } public DataNode getLast( ) { return _last; } public void setLast(DataNode node) { _last = node; } public int getValue( ) { return _value; } } public void setValue(int val) { _value = val; } 19- 7 The Actual Stack Class class DataStack { private DataNode _head; DataStack ( ) { _head = null; } boolean empty ( ) {…} void push (DataNode newItem) {…} DataNode pop ( ) {…} void remove ( ) {…} } 19- 8 The Use of a Backwards Pointer • We defined the DataNode to have a “last” pointer (rather than a “next” one); the pointer will always point to an existing past node: remove null <<<< <<<< First Second Third _last Data _value bottom of the stack _last _value A Stack _last _value push pop head empty top of the stack 19- 9 empty( ) (for class DataStack) class DataStack { private DataNode _head; DataStack ( ) { _head = null; } boolean empty ( ) {return (head == null); } void push (DataNode newItem) {…} DataNode pop ( ) {…} void remove ( ) {…} } 19- 10 push( ) (for class DataStack) class DataStack { private DataNode _head; DataStack ( ) { _head = null; } boolean empty ( ) {…} void push (DataNode newItem) { newItem.setLast(_head); _head = newItem; } DataNode pop ( ) {…} void remove ( ) {…} } 19- 11 pop( ) (for class DataStack) class DataStack { private DataNode _head; … DataNode pop ( ) { if ( empty( ) ) return null; else { DataNode temp = _head; _head = _head.getLast( ); return temp; } } … } 19- 12 remove( ) (for class DataStack) class DataStack { private DataNode _head; DataStack ( ) { _head = null; } boolean empty ( ) {…} void push (DataNode newItem) {…} DataNode pop ( ) {…} void remove ( ) { _head = null; } } 19- 13 Stack Applications • One use of a stack is to reverse input: DataStack stack = new DataStack( ); //create the stack while ( not eof ) { read from user, create a DataNode newItem; stack.push(newItem); } // end the stacking loop while ( !stack.empty( ) ) { // print the stack print stack.pop( ); } // end the unstacking loop 19- 14 Another Stack Application • Another use is to evaluate postfix or Reverse Polish Notation expressions: Infix Postfix (A+ B) * C AB+C* (A – B) / (C * D) AB–CD*/ ( (A * (B / C) ) – (D * E) ) ABC/*DE*– Arguments are pushed onto a stack, operators act on the top two popped stack items and push the result onto the stack. 19- 15 The Pseudocode for Postfix Evaluation (no error checking) while ( not eof ) { read the next data; if data was an operand { create DataNode newItem with data in it; stack.push(newItem); } else it’s an operator, so { termNode1 = stack.pop( ); termNode2 = stack.pop( ); carry out the appropriate operation; create DataNode theResult; stack.push(theResult); } } // end of the while loop remainingTerm = stack.pop( ); print data from remainingTerm; 19- 16 Other Uses of Stacks • Language Translation (from one computer language level to another) • Method calls • Recursive method calls (delayed evaluation) • Delimiter matching • Maintenance of free storage space (unused array indexes); order is irrelevant, a stack just holds the information conveniently 19- 17 Easy Question • Use our primitives to reverse the order of a stack’s contents, placing the items into another stack 19- 18 Easy Question • Use our primitives to reverse the order of originalStack’s contents, placing the items into another stack DataStack copyStack = new DataStack( ); while ( !originalStack.empty( ) ) { copyStack.push(originalStack.pop( )); } // Postcondition: originalStack is empty 19- 19 Queues • Queues: new records added to one end and taken off from the other end; first-in, first-out, FIFO • We can talk about the abstract data structure “queue” without knowing anything about the “values” that it stores: –Enqueue means “save a value” –Retrieve means “get the oldest value that remains” –Empty means “there are no values in the queue” 19- 20 More Queue Operations • There are some more primitive operations that might be relevant, depending on how we implement the queue: –Remove means “remove all of the queue’s contents” returning space to memory (relevant for pointer-based queue) –FullQ means “the queue can’t hold any more values” (more relevant for an arraybased queue) 19- 21 The Queue Name Layer (no commitment as to implementation) Objects of class DataNode, of stored items, doesn’t have to be defined yet; these are methods of the Queue class: boolean empty ( ) {…} // true if the queue is empty void enqueue (DataNode newItem) {…} // Add newItem to end of the queue DataNode retrieve ( ) {…} // Remove oldest item from the queue and return it void remove ( ) {…} // Dispose of any current queue contents 19- 22 Question • enqueue, retrieve, etc. are primitives; how would we define, in terms of the primitives, “nextItem”, which gets a copy of the front value of the queue but doesn’t remove that value? 19- 23 Question • enqueue, retrieve, etc. are primitives; how would we define, in terms of the primitives, “nextItem”, which gets a copy of the front value of the queue but doesn’t remove that value? Not so easy. When an item is removed it can only be added back onto the end of the queue. Just to get the value of the first item, we’d need to copy the entire queue. If we really want something like “nextItem”, it should be implemented as a primitive method of the Queue class. 19- 24 The Implementation Layer • Now we have to implement it • Pointers are often used to build queues because (as I keep saying) a linked list can get longer, while arrays are limited to their defined size enqueue ? rear _last Third Data _value ? ? ? _last Second _value A Queue retrieve ? _last First _value front empty remove 19- 25 Which of these is better for us? >>>> _Last Newest Data _value null >>>> _Last _Last Second _value front of the line Oldest _value front rear null <<<< <<<< Newest Second Oldest _last _last Data _value rear _value front of the line _last _value front 19- 26 First Alternative >>>> _Last Newest Data _value rear null >>>> _Last _Last _value _value Second front of the line Oldest front •Adding a node to the rear is easy; •Removing a node from the front is hard. 19- 27 Second Alternative null _last <<<< <<<< Second Oldest _last Newest Data _value rear _value front of the line _last _value front •Adding a node to the rear is easy; •Removing a node from the front is also easy! 19- 28 Two-class Encapsulation of a Linked List Queue (here's the node class, for inside) class DataNode { private int _value; private DataNode _last; public DataNode (int val, DataNode node) { _value = val; _last = node; } public DataNode getLast( ) { return _last; } public void setLast(DataNode node) { _last = node; } public int getValue( ) { return _value; } public void setValue(int val) { _value = val; } } 19- 29 The Actual Queue Class class DataQueue { private DataNode _rear, _front; DataQueue ( ) { _rear = new DataNode(0, null); _front = _rear; } boolean empty ( ) {…} void enqueue (DataNode newItem) {…} DataNode retrieve ( ) {…} void remove ( ) {…} } 19- 30 empty( ) (for class DataQueue) class DataQueue { private DataNode _rear, _front; DataQueue ( ) {…} boolean empty() {return( _front == _rear);} void enqueue (DataNode newItem) {…} DataNode retrieve ( ) {…} void remove ( ) {…} } 19- 31 enqueue( ) (for class DataQueue) class DataQueue { private DataNode _rear, _front; DataQueue ( ) {…} boolean empty ( ) {…} void enqueue (DataNode newItem) { DataNode temp = new DataNode(0, null); _rear.setValue(newItem.getValue( )); _rear.setLast(temp); _rear = temp; //"advance" rear pointer } // copying newItem's value into queue DataNode retrieve ( ) {…} void remove ( ) {…} 19- 32 } retrieve( ) (for class DataQueue) class DataQueue { private DataNode _rear, _front; … DataNode retrieve ( ) { if ( empty( ) ) return null; else { DataNode temp = _front; _front = _front.getLast( ); return temp; } } } … 19- 33 remove( ) (for class DataQueue) class DataQueue { private DataNode _rear, _front; DataQueue ( ) { _rear = new DataNode(0, null); _front = _rear; } boolean empty ( ) {…} void enqueue (DataNode newItem) {…} DataNode retrieve ( ) {…} void remove ( ) { _front = _rear; } } 19- 34 Queue Applications • Queues are found whenever supply and demand (servers and clients) cannot be assured to stay in lockstep • Data may come in too quickly, or in irregular spurts, and have to be held for processing later • Example: Time-shared computer system; tasks (like users’ programs or print jobs) are put in a queue to be processed each in turn 19- 35 Example: Grab First Letters of Succession of Words • Just a white shark • Space, time, and relativity with a ridiculous script • A nauseating nitwit ineffably embalmed Write a program that grabs the first letter of each word, prints each word as it comes in, then prints the acronyms: Jaws, Starwars, Annie 19- 36 Code Segment (assume DataNode _value is of type char) DataNode newItem; newWord = true; ch = sinp.readChar( ); while ( !sinp.eoln( ) ) { newItem = new DataNode(ch, null); if (newWord) {// true when first letter of a new word is read queue.enqueue(newItem); newWord = false; } else newWord = (ch == ‘ ’); //Assume 1 space betweenwords ch = sinp.readChar( ); } // while // Postcond.: No more input. Queue holds first letters. while ( !queue.empty( ) ) { // until the queue is empty newItem = queue.retrieve( ); System.out.print(newItem.getValue( )); } // while 19- 37 Another Example: Palindromic Sentences So patient a doctor to doctor a patient so. while ( not eof ) { // stack and queue the words read a word, ignoring capitalization and punctuation; push the word onto a stack; enqueue the word in a queue; } do { // compare the stored values---assume non-empty lists pop a word from the stack; retrieve a word from the queue; } while ( they match && not empty( ) stack or queue ); decide why we left the loop, and report the results 19- 38 A Few Definition Exercises Define a class suited to building a text editor. Each line object must hold up to 80 characters, but the total number of lines shouldn’t be restricted. Common editing operations, like deleting and moving lines, and printing subsections of the text, should be convenient to perform. 19- 39 A Solution class Line { Line _next; StringBuffer _data; … } Line first, current, last, other auxiliary pointers; first current _next _data m o v i … _next _data o f t … _next _data p e r f … 19- 40 Another Problem A manufacturer has labeled product lines with a letter, followed by the product number (e.g., A1, C7, M4). Define a class definition that allows quick access to any product line, without limiting the number of products in each line. Product information is stored in an object of type ProductData. 19- 41 A Solution— An Array with Buckets class Node { Node _next; ProductData _data; … } array "info"; one cell for each letter of alphabet 0 1 Node[ ] info = new Node[26]; Node current; null >> >> … 24 >> 25 >> _next null null _next null _data null _next null _data Objects of type Node _data 19- 42 Another Problem A company has records describing its employees, but different groups in the company want to keep the records in different orders (e.g., length of employment, frequency of absence, teudat zehut number). If duplicate sets cannot be kept, define a data type that allows each division reasonable access to the database. 19- 43 A Solution class EmployeeInfo { whatever the employee records contain … } class BaseNode { BaseNode _next; EmployeeInfo _employee; … } BaseNode mainList, watchList, healthList, payrollList, current; 19- 44 One set of data, two very different lists mainList >> >> Data Data << << >> >> Data Data << << >> >> Data Data << << >> << Data EmployeeInfo BaseNodes null Data BaseNodes null healthList 19- 45 Don’t Search Past the End of a Linked List • When searching an input stream, check for not eof • When searching an array, watch for the last component • When searching a linked list, look for a null-valued pointer // A loop with a potential bug–sought might not be there current = head; // Start current at head of the list while ( current.getValue( ) != sought) { current = current.getNext( ); } 19- 46 Better, but Still Not Necessarily Correct //A possibly correct, but probably buggy, version of the // same loop current = head; // Start current at head of the list // What precondition has to exist here, before the loop? while ( (current.getValue( ) != sought) && (current.getNext( ) != null) ) { current = current.getNext( ); } //Postcondition: if sought is there, current addresses it if ( current.getValue( ) == sought ) System.out.println("Found the value."); else System.out.println("Did not find the value."); 19- 47 Another Version, Maybe Safer // A different version of the same loop searching = true; //Use an auxiliary boolean variable current = head; //Start current at head of the list // Now, current might be null while ( (current != null) && searching ) { if (current.getValue( ) == sought) searching = false; // since we’ve found it else current = current.getNext( ); } // Postcond.: if current isn’t null, it addresses sought if ( current != null ) System.out.println("Found the value."); else System.out.println("Did not find the value."); 19- 48 Trees • A tree is another data structure that can be built using pointers • It can be defined recursively: a tree is a node that’s linked to one or more trees, or to nothing. • Branches lead to finer branches, but never lead back to the root. Subtrees must be distinct (no two trees share the same node). 19- 49 Nobody Nodes the Trouble I Nodes • The root of a tree is the first (top) node • The nodes an element points to are its children; it is the parent • A node with no children is called a leaf root parent child leaf 19- 50 Binary Tree • A tree whose nodes have at most two children is called a binary tree. class BinaryNode { ProblemData _data; BinaryNode _left, _right; } BinaryNode current; 19- 51 Recursive Tree Searching (one method) • If current’s left child isn’t null, point current at the left child and search the (sub)tree. • If current’s right child isn’t null, point current at the right child and search the (sub)tree. • Print the value stored in the current node. Using recursion allows backtracking without backward pointers. Goal: Print every node’s stored value. Stacking Plan: Visit the left subtree. Visit the right subtree. Bound: Reaching a leaf, or node that has no subtrees. Unstacking Plan: Print the current node’s stored value. 19- 52 The Java Code (acting at the BinaryNode level) void inspectTree (BinaryNode current) { // Visits every node of a non-empty binary tree if ( current.left != null ) inspectTree(current.left); if ( current.right != null ) inspectTree(current.right); printProblemData(current.data); } // inspectTree 19- 53 Using inspectTree — Postorder + * / + A B – D C E F inspectTree searches the tree in postorder: A B C + / D E F – * + Postfix notation and reverse Polish notation are other names for this (as we’ve seen). 19- 54 Preorder Search + * / + A B – D C E F First variation: Preorder search: printProblemData(current.data); if (current.left != null) inspectTree(current.left); if (current.right != null) inspectTree(current.right); Search then goes as: + / A + B C * D – E F 19- 55 Inorder Search + * / + A B – D C E F Second variation: Inorder search: if (current.left != null) inspectTree(current.left); printProblemData(current.data); if (current.right != null) inspectTree(current.right); Search then goes as: A / B + C + D * E – F 19- 56 Programming Binary Trees Let’s use a binary tree to represent Morse code: T E A I U S H V F R L W P M N K D J B X C O G Y Z Q 19- 57 The Type Definition class CodeNode { char _letter; CodeNode _dot, _dash; } CodeNode root; T E A I U S H V F R L W P M N J B X C O G K D Y Z Q 19- 58 How We Can Use It void decode(CodeNode root) { // Decodes Morse code; each letter must be followed by a blank } CodeNode current; char inputCharacter; current = root; SimpleInput sinp = new SimpleInput(System.in); inputCharacter = sinp.readChar( ); while ( !sinp.eof( ) ) { if ( inputCharacter == '.') current = current._dot; else if ( inputCharacter == ‘-‘ ) current=current._dash; else if ( inputCharacter == ‘ ’ ) { Sytem.out.print(current._letter); current = root; } inputCharacter = sinp.readChar( ); } // while System.out.println( ); // decode 19- 59 Relationship Between Data and Name is Stored (Implicitly) in the Tree .--. .- -.-. -.PACK T E A I U S H V F R L W P M N J B X C O G K D Y Z Q Other yes/no questions can similarly lead to an answer, stored implicitly in some binary tree. 19- 60 Trees of Words gregor awoke a samsa discover been one giant morning only cockroach What is going on? to transformed he had into 19- 61 Storing Items in Alphabetical Order gregor samsa awoke one morning only to discover he had been transformed into a giant cockroach gregor awoke a samsa discover been one giant morning cockroach to only transformed he had into 19- 62 To Build an Alphabetically Ordered Tree (recursive specification) • If the current node is null, store the new word there and stop • If the new word precedes the word in the current node, point to the left child and build an alphabetically ordered tree. • If the new word follows the word in the current node, point to the right child and build an alphabetically ordered tree. • If the new word is the same as the word in the current node, stop. 19- 63 class WordStore { private StringBuffer _word; WordStore _before, _after; public WordStore (StringBuffer newWord, WordStore bef, aft) { _word = newWord; _before = bef; _after = aft; } public StringBuffer getWord( ) { return _word; } public WordStore getAfter( ) { return _after; } public WordStore getBefore( ) { return _before; } } void addAWord (WordStore current, StringBuffer newWord) { //Adds string newWord to alphabetically ordered binary tree } if ( current == null ) current = new WordStore(newWord, null, null); else if ( newWord comes before current.getWord( ) ) addAWord the newWord to current.before; else if ( current.getWord( ) comes before newWord ) addAWord the newWord to current.after; // else the word is a duplicate, do nothing // addAWord addAWord is an end recursion; the stack doesn’t store values or pending statements Binary Search Tree (from the targilim) Definitions: * The root of a tree is the only node which doesn’t have a father node. * A leaf is a node which doesn’t have any son nodes. * A binary tree is a tree whose nodes have at most two son nodes. * A binary search tree is: 1. A binary tree; 2. All the nodes which are descendents of the right son of a specific node including the right son itself have values greater or equal to the value in the node; 3. All the nodes which are descendents of the left son of a specific node including the left son itself have values less than the value in the node. a In the example: b,c,d,e,f > a b > d,e,f c>b root b d c e f leaves 19- 65 Binary Tree Node public class Node { protected Comparable _data; protected Node _left,_right; public Node(Comparable data) { _data = data; _left = _right = null; } public Node getRight() { return _right; } public Node getLeft() { return _left; } public void addRight(Node node) { _right = node; } public void addLeft(Node node) { _left = node; } public Comparable getData() { return _data; } } 19- 66 Comparable interface (used as the data object) /** * This interface defines the way two objects should be compared. */ public interface Comparable { /** * This function does the comparison between two objects. * @return -1 second object is greater than this one.<br> * 1 second object is smaller than this one.<br> * 0 second object is equal to this one. * @param right the object to which we compare. */ public int compare(Comparable right); } 19- 67 Example of class implementing the Comparable interface /** * This is an example class that implements the Comparable interface. * I would have extended Integer but Integer is declared final , so my class * is just a wrapper around the Integer class. */ public class MyInteger implements Comparable { private Integer _data; public MyInteger(int data) { _data = new Integer(data); } public MyInteger(String data) throws NumberFormatException { _data = new Integer(data); } public int intValue() { return _data.intValue(); } continued… 19- 68 Example of class implementing the Comparable interface (continued) public String toString() { return _data.toString(); } public int compare(Comparable right) { int leftVal = _data.intValue(); int rightVal = ((MyInteger)right).intValue(); } } if(rightVal>leftVal) return -1; else if(rightVal<leftVal) return 1; return 0; 19- 69 Binary Search Tree Implementation public class BinTree { protected Node _root; protected int _size; public BinTree() { _size = 0; } public void add(Comparable data) { add(data,_root,_root); _size++; } 19- 70 Implementation (continued); Recursive add method private void add(Comparable data, Node son, Node father) { //stop the recursion, we have reached a leaf if (son == null) { if (father == null) //this leaf is the root _root = new Node(data); else { //just a regular leaf if ((father.getData()).compare(data) == 1) father.addLeft(new Node(data)); else father.addRight(new Node(data)); } } else { if ((son.getData()).compare(data) == 1) add(data, son.getLeft(), son); else add(data, son.getRight(), son); } } 19- 71 Implementation (continued) /** * Recursive method: * Traversal of the tree (inorder). */ private void traverse(Node node) { if (node != null) { traverse(node.getLeft()); System.out.println(node.getData()); traverse(node.getRight()); } } 19- 72 Implementation (continued) What's the result of this main: public static void main(String args[]) { BinTree myTree = new BinTree(); myTree.add(new MyInteger(7)); myTree.add(new MyInteger(1)); myTree.add(new MyInteger(3)); myTree.add(new MyInteger(2)); myTree.add(new MyInteger(4)); myTree.add(new MyInteger(5)); myTree.add(new MyInteger(8)); myTree.add(new MyInteger(6)); } The result : 1 2 : 8 The numbers are sorted!!! myTree.traverse(myTree._root); 19- 73 Now We Want to Print the Contents of the Tree in Alphabetical Order—Easy void inOrder (WordStore currentWord) { // Prints nodes of a non-null alphabetically // ordered binary tree in order if ( current.getBefore( ) != null ) inOrder(current.getBefore( ) ); Sytem.out.print(current.getWord( )); if ( current.getAfter( ) != null ) inOrder(current.getAfter( ) ); } // inOrder 19- 74 InOrder Traversal gregor awoke a samsa discover been one giant morning cockroach to only transformed he had into 19- 75 InOrder Traversal a awoke been cockroach discover giant gregor had he into morning one only samsa to transformed gregor awoke a samsa discover been one giant morning only cockroach to transformed he had into 19- 76 More AddAWord What structures are built by AddAWord when presented with: a) a big cat did everything 19- 77 More AddAWord What structures are built by AddAWord when presented with: a) a big cat did everything a big cat did everything 19- 78 More AddAWord What structures are built by AddAWord when presented with: a) a big cat did everything b) zesty young xylophones wed violins a big cat did everything 19- 79 More AddAWord What structures are built by AddAWord when presented with: a) a big cat did everything b) zesty young xylophones wed violins zesty young xylophones wed violins a big cat did everything 19- 80 This is Not the End • We have covered a lot of subjects in Computer Science (e.g., sorting, searching, loops, recursion, simple data structures like arrays and linked lists) • We have covered a lot in Java, but it's only the beginning • You'll be carrying this forward in the next semester in Data Structures 19- 81 The End, for Now Good Luck on the Exam! 19- 82