Presentation is loading. Please wait.

Presentation is loading. Please wait.

Introduction to Computer Science Stacks and Queues More Recursion and Pointers Unit 19.

Similar presentations


Presentation on theme: "Introduction to Computer Science Stacks and Queues More Recursion and Pointers Unit 19."— Presentation transcript:

1 Introduction to Computer Science Stacks and Queues More Recursion and Pointers Unit 19

2 19- 2 Stacks Stacks: new records added to one end and taken off from the same end; last-in, first- out, 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”

3 19- 3 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)

4 19- 4 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

5 19- 5 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 }

6 19- 6 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 _value Third <<<< Data _last _value First null _value Second <<<< _last head A Stack push pop empty remove

7 19- 7 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; } }

8 19- 8 The Actual Stack Class class DataStack { private DataNode _head; DataStack ( ) { _head = null; } boolean empty ( ) {…} void push (DataNode newItem) {…} DataNode pop ( ) {…} void remove ( ) {…} }

9 19- 9 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: _value Third <<<< Data bottom of the stack _last _value First null _value Second <<<< top of the stack _last head A Stack push pop empty remove

10 19- 10 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 ( ) {…} }

11 19- 11 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 ( ) {…} }

12 19- 12 pop( ) (for class DataStack) class DataStack { private DataNode _head; … DataNode pop ( ) { if ( empty( ) ) return null; else { DataNode temp = _head; _head = _head.getLast( ); return temp; } } … }

13 19- 13 remove( ) (for class DataStack) class DataStack { private DataNode _head; DataStack ( ) { _head = null; } boolean empty ( ) {…} void push (DataNode newItem) {…} DataNode pop ( ) {…} void remove ( ) { _head = null; } }

14 19- 14 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

15 19- 15 Another Stack Application Another use is to evaluate postfix or Reverse Polish Notation expressions: InfixPostfix (A+ B) * CA B + C * (A – B) / (C * D)A B – C D * / ( (A * (B / C) ) – (D * E) )A B C / * D E * – Arguments are pushed onto a stack, operators act on the top two popped stack items and push the result onto the stack.

16 19- 16 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;

17 19- 17 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

18 19- 18 Easy Question Use our primitives to reverse the order of a stack’s contents, placing the items into another stack

19 19- 19 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

20 19- 20 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”

21 19- 21 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 array- based queue)

22 19- 22 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

23 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?

24 19- 24 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.

25 19- 25 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 _value ? Data _last _value First ? _value Second ? _last front A Queue enqueue retrieve empty remove rear Third ? ?

26 19- 26 Which of these is better for us? _value Oldest <<<< Data rear _last _value Newest null _value Second <<<< front _last front of the line _value Oldest Data >>>> rear _Last _value Newest null _value Second >>>> front _Last front of the line >>>>

27 19- 27 First Alternative Adding a node to the rear is easy; Removing a node from the front is hard. _value Oldest Data >>>> rear _Last _value Newest null _value Second >>>> front _Last front of the line >>>>

28 19- 28 Second Alternative Adding a node to the rear is easy; Removing a node from the front is also easy! _value Oldest <<<< Data rear _last _value Newest null _value Second <<<< front _last front of the line

29 19- 29 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; } }

30 19- 30 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 ( ) {…} }

31 19- 31 empty( ) (for class DataQueue) class DataQueue { private DataNode _rear, _front; DataQueue ( ) { … } boolean empty() {return( _front == _rear);} void enqueue (DataNode newItem) { … } DataNode retrieve ( ) { … } void remove ( ) { … } }

32 19- 32 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 ( ) {…} }

33 19- 33 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; } } … }

34 19- 34 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; } }

35 19- 35 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

36 19- 36 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

37 19- 37 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

38 19- 38 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

39 19- 39 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.

40 19- 40 A Solution class Line { Line _next; StringBuffer _data; … } Line first, current, last, other auxiliary pointers; first current _next_data of t _next_data per f … … … _next_data mov i

41 19- 41 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.

42 19- 42 A Solution— An Array with Buckets class Node { Node _next; ProductData _data; … } Node[ ] info = new Node[26]; Node current; _next _data null _next _data null 0 1 >> 24 25 >> _next _data null … array "info"; one cell for each letter of alphabet Objects of type Node

43 19- 43 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.

44 19- 44 A Solution class EmployeeInfo { whatever the employee records contain … } class BaseNode { BaseNode _next; EmployeeInfo _employee; … } BaseNode mainList, watchList, healthList, payrollList, current;

45 19- 45 One set of data, two very different lists Data >> null Data mainList << null healthList BaseNodes EmployeeInfo

46 19- 46 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( ); }

47 19- 47 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.");

48 19- 48 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.");

49 19- 49 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).

50 19- 50 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

51 19- 51 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;

52 19- 52 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.

53 19- 53 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

54 19- 54 Using inspectTree — Postorder + / + * – 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). A B C D E F

55 19- 55 Preorder Search 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 + / + * – A B C D E F

56 19- 56 Inorder Search 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 + / + * – A B C D E F

57 19- 57 Programming Binary Trees Let’s use a binary tree to represent Morse code: E A T M I F W N G O S U D K H V L P J B X Z Q C Y R

58 19- 58 The Type Definition class CodeNode { char _letter; CodeNode _dot, _dash; } CodeNoderoot;

59 19- 59 How We Can Use It void decode(CodeNode root) { // Decodes Morse code; each letter must be followed by a blank CodeNode current; charinputCharacter; 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

60 19- 60 Relationship Between Data and Name is Stored (Implicitly) in the Tree.--..- -.-. -.- PACK Other yes/no questions can similarly lead to an answer, stored implicitly in some binary tree.

61 19- 61 Trees of Words gregor awokesamsa adiscover beengiant cockroach oneto transformedmorningonly he hadinto What is going on?

62 19- 62 Storing Items in Alphabetical Order gregor samsa awoke one morning only to discover he had been transformed into a giant cockroach gregor awokesamsa adiscover beengiant cockroach oneto transformedmorningonly he hadinto

63 19- 63 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.

64 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

65 19- 65 Binary Search Tree (from the targilim) a b dc ef root 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. In the example: b,c,d,e,f > a b > d,e,f c > b leaves

66 19- 66 Binary Tree Node public class Node { protected Comparable _data; protected Node _left,_right; public Node(Comparable data) { _data = data; _left = _right = null; } public void addRight(Node node) { _right = node; } public void addLeft(Node node) { _left = node; } public Node getRight() { return _right; } public Node getLeft() { return _left; } public Comparable getData() { return _data; }

67 19- 67 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. * 1 second object is smaller than this one. * 0 second object is equal to this one. * @param right the object to which we compare. */ public int compare(Comparable right); }

68 19- 68 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…

69 19- 69 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; }

70 19- 70 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++; }

71 19- 71 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); }

72 19- 72 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()); }

73 19- 73 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)); myTree.traverse(myTree._root); } The result : 1 2 : 8 The numbers are sorted!!!

74 19- 74 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

75 19- 75 InOrder Traversal gregor awokesamsa adiscover beengiant cockroach oneto transformedmorningonly he hadinto

76 19- 76 InOrder Traversal a awoke been cockroach discover giant gregor had he into morning one only samsa to transformed gregor awokesamsa adiscover beengiant cockroach oneto transformedmorningonly he hadinto

77 19- 77 More AddAWord What structures are built by AddAWord when presented with: a) a big cat did everything

78 19- 78 More AddAWord What structures are built by AddAWord when presented with: a) a big cat did everything a big cat did everything

79 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 a big cat did everything

80 19- 80 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

81 19- 81 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

82 19- 82 The End, for Now Good Luck on the Exam!


Download ppt "Introduction to Computer Science Stacks and Queues More Recursion and Pointers Unit 19."

Similar presentations


Ads by Google