inheritance and data structures

Post on 19-Apr-2022

3 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Inheritance and datastructures

Task

Transform an infix expression to a postfix expression (Reverse Polish Notation - RPN) and calculate its value.

2Teréz A. Várkonyi: Object-oriented programming

5+(11+26)*(43-4) 5 11 26 + 43 4 - * + 1448

To transform an infix expression and to evaluate it, usually two stacks are needed. In the first one, the operators and the open parentheses are stored. In the second one, the operands and the partial results are put.

infix expression postfix expression value

1. Tokenize the infix expression and put the tokens into an x sequence.

2. Convert to Polish notation: x is converted into a y sequence in which the tokens are in postfix form. For the conversion, a stack is used.

3. Evaluate the y sequence by using a second stack.

Plan

3Teréz A. Várkonyi: Object-oriented programming

*

*

11( + 26 ) * ( 43 - 4 )x:

input: 5+(11+26)*(43-4)

2611 + 43 4 -y:

result: 1448

11 ( 26 -4)43

+5

5 +

tokenization

conversion to postfix form

+5

tokens:

evaluation

It is enough to create one instanceof some of the tokens and later on,they can be referred multiple times.

Tokens are objects, only their address isstored in the sequence.

Objects to be used

string: an infix expression given in a standard input (fstream)

tokens: specific tokens (Token), as operands (Operand), operators (Operator), and parentheses (LeftP, RightP)

sequences: pointers pointing at the tokens (vector<Token*>): for the tokenized infix expression (x),for the tokenized postfix expression (y)

stacks: for storing the pointers of the tokens (Stack<Token*>),for storing the numbers (Stack<int>)

4Teréz A. Várkonyi: Object-oriented programming

vector<Token*> x;

// Tokenization…

// Transforming into Polish notationvector<Token*> y;Stack<Token*> s…

// EvaluationStack<int> v;…

deallocateToken(x);

int main() {char ch;do {

cout << "Give me an arithmetic expression:\n";vector<Token*> x;try{// Tokenization

…// Transforming into Polish notation

vector<Token*> y;Stack<Token*> s…

// EvaluationStack<int> v;…

} catch (MyException ex) { }deallocateToken(x);

cout << "\nDo you continue? Y/N";cin >> ch;

} while ( ch!='n' && ch!='N' );return 0;

}

MyException::Interrupt exceptionmay be raised anytime

5Teréz A. Várkonyi: Object-oriented programming

Main program

void deallocateToken(vector<Token*> &x){

for( Token* t : x ) delete t;}

main.cpp

enum MyException { Interrupt };

frees the memoryallocation of the tokens

token instantiation

Token class and its childrenToken

+is_Operand() : bool {virtual, query}+is_Operator(): bool {virtual, query}+is_LeftP() : bool {virtual, query}+is_RightP() : bool {virtual, query}+read(stream) : Token*+to_String() : string {virtual}

Operand- val:int

+is_Operand() : bool+to_String() : string+value() : int {query}

LeftP

+is_LeftP() : bool+to_String() : string

Operator- op:char

+is_Operator() : bool+to_String() : string+evaluate(int,int) : int {query}+priority() : int {query}

RightP

+is_RightP() : bool+to_String() : string

alternative type

tokenizer

6Teréz A. Várkonyi: Object-oriented programming

return false

it reads thenext token

return truereturn truereturn truereturn true

abstract methodabstract class

Abstract class, interface❑ Abstract class is never instantiated, it is used only

as a base class for inheritance.

‒ name of the abstract class is italic.

❑ A class is abstract if

• its constructors are not public, or

• at least one method is abstract (it is not implemented and it is overridden in a child)

− name of the abstract method is also italic

7Teréz A. Várkonyi: Object-oriented programming

<class>

<interface>

❑ Pure abstract classes are called interfaces, none of their methods are implemented.

❑ When a class implements all of the abstract methods of an interface, it realizes the interface.

<child class>

<base class>

class Token{public:

class IllegalElementException{private:

char _ch;public:

IllegalElementException(char c) : _ch(c){}char message() const { return _ch;}

};virtual ~Token();virtual bool is_LeftP() const { return false; }virtual bool is_RightP() const { return false; }virtual bool is_Operand() const { return false; }virtual bool is_Operator() const { return false; }virtual bool is_End() const { return false; }

virtual std::string to_String() const = 0;

friendstd::istream& operator>>(std::istream&, Token*&);

}; token.h

not presented inthe specification

8Teréz A. Várkonyi: Object-oriented programming

Token class

for exception handling

Why is the destructor virtual?

class Operand: public Token{private:

int _val;public:

Operand(int v) : _val(v) {}

bool is_Operand() const override { return true; }

std::string to_String() const override {std::ostringstream ss; ss << _val; return ss.str();

}

int value() const { return _val; }};

conversion

9Teréz A. Várkonyi: Object-oriented programming

Operand class

token.h

class LeftP : public Token{

public:

bool is_LeftP() const override { return true; }

std::string to_String() const override { return "("; }};

10Teréz A. Várkonyi: Object-oriented programming

LeftP class(one instance is enough)

LeftP(){}

static LeftP *_instance;

static LeftP *instance() {

return _instance;}

private:

LeftP *LeftP::_instance = nullptr;

if ( _instance == nullptr ) _instance = new LeftP();

private constructor

creator method

points at the onlyone instance

private constructoris called here

token.h

token.cpp

Singleton design pattern

❑ The class is instantiated only once, irrespectively of the number of

instantiation requests.

11Teréz A. Várkonyi: Object-oriented programming

Singleton- instance : Singleton

- Singleton()+ instance() : Singleton+ destroy() : void

if instance = nil then instance := new Singleton()

endifreturn instance

Design patterns are class diagram patterns that help object-oriented modeling. They play a

significant role in reusability, modifiability, and ensuring efficiency.

class-level attribute:refers to one instanceprivate constructor:

the class cannot beinstantiated directly

class-level method for serving theinstantiation requests:it returns an instance

class RightP : public Token {private:

RightP(){}static RightP *_instance;

public:static RightP *instance() {

if ( _instance == nullptr ) _instance = new RightP();return _instance;

}bool is_ RightP() const override { return true; }std::string to_String() const override { return ")"; }

};

12Teréz A. Várkonyi: Object-oriented programming

RightP, End singleton classes

RightP *RightP::_instance = nullptr;End *End::_instance = nullptr;

class End : public Token {private:

End(){}static End *_instance;

public:static End *instance() {

if ( _instance == nullptr ) _instance = new End();return _instance;

}bool is_ End() const override { return true; }std::string to_String() const override { return ";"; }

};

token.h

token.cpp

class Operator: public Token{private:

char _op; public:

Operator(char o) : _op(o) {}

bool is_Operator() const override { return true; }std::string to_String() const override {

string ret;ret = _op;return ret;

}virtual int evaluate(int leftValue, int rightValue) const;virtual int priority() const;

};

13Teréz A. Várkonyi: Object-oriented programming

Operator class

conversion

token.h

14Teréz A. Várkonyi: Object-oriented programming

Methods of class Operator

int Operator::evaluate(int leftValue, int rightValue) const{

switch(_op){case '+': return leftValue+rightValue;case '-': return leftValue-rightValue;case '*': return leftValue*rightValue;case '/': return leftValue/rightValue;default: return 0;

}}

int Operator::priority() const{

switch(_op){case '+': case '-': return 1;case '*' : case '/': return 2;default: return 3;

}}

SOLID

pen-Close

SOLID

this code does notsatisfy the open-closeprinciple

token.cpp

ingle responsibility

iskov substitution

epedency inversion

nterface segregation

Operator classesOperator

- op:char# Operator(c:char)+ is_Operator() : bool {override}+ to_String() : string {override, query}+ evaluate(l,r:int): int {virtual, query}+ priority() : int {virtual, query}

<<singleton>>OperatorAdd

+ evaluate(l,r:int) : int{override, query}+ priority() : int{override, query}

<<singleton>>

OperatorMul

+ evaluate(l,r:int) : int{override, query}+ priority() : int{override, query}

<<singleton>>OperatorSub

+ evaluate(l,r:int) : int{override, query}+ priority() : int{override, query}

<<singleton>>

OperatorDiv

+ evaluate(l,r:int) : int{override, query}+ priority() : int{override, query}

15Teréz A. Várkonyi: Object-oriented programming

return truereturn op

return 2return 2return 1return 1

op := c

return 3

return l+r return l-r return l*r return l/r

protected to becalled in the childrenclasses

class Operator: public Token{private:

char _op; protected:

Operator(char o) : _op(o) {}public:

bool is_Operator() const override { return true; }std::string to_String() const override {

string ret;ret = _op;return ret;

}virtual int evaluate(int leftValue, int rightValue) const = 0;virtual int priority() const { return 3; }

};

16Teréz A. Várkonyi: Object-oriented programming

token.h

Abstract Operator class

class OperatorAdd: public Operator{private:

OperatorAdd() : Operator('+') {}static OperatorAdd *_add;

public:static OperatorAdd * instance(){

if ( _add == nullptr ) _add = new OperatorAdd();return _add;

}int evaluate(int leftValue, int rightValue) const override {

return leftValue + rightValue; }int priority() const override { return 1; }

};

17Teréz A. Várkonyi: Object-oriented programming

Singleton operator classes

class OperatorSub: public Operator{private:

OperatorSub() : Operator('-') {}static OperatorSub *_sub;

public:static OperatorSub * instance(){

if ( _sub == nullptr ) _sub = new OperatorSub();return _sub;

}int evaluate(int leftValue, int rightValue) const override {

return leftValue - rightValue; }int priority() const override { return 1; }

};

class OperatorMul: public Operator{private:

OperatorMul() : Operator('*') {}static OperatorMul *_mul;

public:static OperatorMul * instance(){

if ( _mul == nullptr ) _mul = new OperatorMul();return _mul;

}int evaluate(int leftValue, int rightValue) const override {

return leftValue * rightValue; }int priority() const override { return 2; }

};

class OperatorDiv: public Operator{private:

OperatorDiv() : Operator('/') {}static OperatorDiv *_div;

public:static OperatorDiv * instance(){

if ( _div == nullptr ) _div = new OperatorDiv();return _div;

}int evaluate(int leftValue, int rightValue) const override {

return leftValue / rightValue; }int priority() const override { return 2; }

};OperatorAdd* OperatorAdd::_add = nullptr;OperatorSub* OperatorAdd::_sub = nullptr;OperatorMul* OperatorAdd::_mul = nullptr;OperatorDiv* OperatorAdd::_div = nullptr;

No need for conditionals

token.cpp

token.h

istream& operator>> (istream &s, Token* &t){char ch;s >> ch;switch(ch){

case '0' : case '1' : case '2' : case '3' : case '4':case '5' : case '6' : case '7' : case '8' : case '9':

s.putback(ch);int intval; s >> intval;t = new Operand(intval); break;

case '+' : t = OperatorAdd::instance(); break;case '-' : t = OperatorSub::instance(); break;case '*’ : t = OperatorMul::instance(); break;case '/' : t = OperatorDiv::instance(); break;case '(' : t = LeftP::instance(); break;case ')' : t = RightP::instance(); break;case ';' : t = End::instance(); break;default: if(!s.fail()) throw new Token::IllegalElementException(ch);

}return s;

}

an expression isended by a semicolon

back to the a buffer

18Teréz A. Várkonyi: Object-oriented programming

Tokenizer operator

singletons

token.cpp

// Tokenization

try{Token *t;cin >> t;while( !t->is_End() ){

x.push_back(t);cin >> t;

}}catch(Token::IllegalElementException *ex){

cout << "Illegal character: " << ex->message() << endl;delete ex;throw Interrupt;

}

the reading throws it

token reading

19Teréz A. Várkonyi: Object-oriented programming

Tokenization

main.cpp

)

20Teréz A. Várkonyi: Object-oriented programming

Convert to Polish notationLeft parentheses and operators are put into a stack. The operator withlower priority has to swap with the higher priority operators in the stack.Every other token is copied into the output sequence. In case of a rightparenthesis, the content of the stack until the first left parenthesis is putinto the output sequence. When we reach the end of the input sequence,the content of the stack is put into the output sequence.

+

4-43(*)26+11(+5

-

+

*

x.first() ; y:=<>

x.end()

t := x.current()

x.next()

t.is_Operand() t.is_LeftP() t.is_RightP() t.is_Operator()

y.push_back(t)

s.top().is_LeftP()

s.empty()

s.top().is_LeftP()

s.top().priority()≧ t.priority()s.push(t) y.push_back(s.top())

s.pop() y.push_back(s.top())

s.pop()

s.pop() s.push(t)

y.push_back(s.top()) ; s.pop()

s.empty()

x.next()

21Teréz A. Várkonyi: Object-oriented programming

#include <stack>

enum StackExceptions{EMPTYSTACK};

template <typename Item>class Stack{private:

std::stack<Item> s;public:

void pop() {if( s.empty() ) throw EMPTYSTACK;s.pop();

}Item top() const {

if( s.empty() ) throw EMPTYSTACK;return s.top();

}bool empty() { return s.empty(); }void push(const Item& e) { s.push(e); }

};

22Teréz A. Várkonyi: Object-oriented programming

Template for the stack

Stack

+empty() : bool+push(Item) : void+pop() : void+top() : Item

if s.empty() then errorelse return s.top()

Item

std::stack

+empty() : bool+push(Item) : void+pop() : void+top() : Item

- s

Item

if s.empty() then errorelse s.pop()

s.push(e)

return s.empty()

stack.hpp

// Transforming into polish form

vector<Token*> y;Stack<Token*> s;

for( Token *t : x ){if ( …else if ( …else if ( …else if ( …

}while( !s.empty() ){

if( s.top()->is_LeftP() ){cout << "Syntax error!\n"; throw Interrupt;

}else{ y.push_back(s.top());s.pop();

}}

error when we have more leftparentheses than right

enumeration

see the next slide

23Teréz A. Várkonyi: Object-oriented programming

Creating the postfix expression

main.cpp

if ( t->is_Operand() ) y.push_back(t);else if ( t->is_LeftP() ) s.push(t);else if ( t->is_RightP() ){

try{while( !s.top()->is_LeftP() ) {

y.push_back(s.top());s.pop();

}s.pop();

}catch(StackExceptions ex){if(ex==EMPTYSTACK){

cout << "Syntax error!\n"; throw Interrupt;

}}

}else if ( t->is_Operator() ) {while( !s.empty() && s.top()->is_Operator() &&

((Operator*)s.top())->priority()>=((Operator*)t)->priority() ) {

y.push_back(s.top()); s.pop();

}s.push(t);

}

”static casting”: s.top()->priority() isnot good, as in Token there is no priority().

error when we have more rightparentheses than left

24Teréz A. Várkonyi: Object-oriented programming

Creating the postfix expression

main.cpp

11 +26 *43 -4

37

39

25Teréz A. Várkonyi: Object-oriented programming

5 +

1443

1448

Evaluation of the postfix expressionOperands of the postfix expression (in order of reading) are put into a stack. In case of operator, the top two numbers are taken and processedaccording to the type of the operator. The result is put back into the stack. At the end of the process, the result can be found in the stack.

y.first()

y.end()

t := y.current()

v.push(t)

rightOp := v.top(); v.pop()leftOp := v.top(); v.pop()v.push(t.evaluate(leftOp, rightOp))

y.next()

z := v.top(); v.pop()

t.is_operand()

26Teréz A. Várkonyi: Object-oriented programming

Evaluation

// Evaluationtry{

Stack<int> v;for( Token *t : y ){

if ( t->is_Operand() ) {v.push( ((Operand*)t)->value() );

} else{int rightOp = v.top(); v.pop();int leftOp = v.top(); v.pop();v.push(((Operator*)t)->evaluate(leftOp, rightOp));

}}int result = v.top(); v.pop();if( !v.empty() ){

cout << "Syntax error!";throw Interrupt;

}cout << "The value of the expression: " << result << endl;

}catch( StackExceptions ex ){if( ex==EMPTYSTACK ){

cout << "Syntax error! "; throw Interrupt;

}}

static casting

static casting

error when we havetoo many operands

enumeration

27Teréz A. Várkonyi: Object-oriented programming

Evaluation

error when we do not haveenough operands main.cpp

token.h

stack.hpp

token.cpp main.cpp

Stack<Item>

TokenOperandOperatorOperatorAdd, OperatorSub, OperatorMul, OperatorDivLeftP, RightPEnd

28Teréz A. Várkonyi: Object-oriented programming

Package diagram

main()enum MyException { … };deallocateToken()

Task: traversal of a binary treeRead some numbers from a standard input and build randomly a binary treefrom them. Then print the tree’s elements to a standard output based ondifferent traversal strategies. Finally,• sum up the internal nodes, • find the maximums of the internal nodes and all of the nodes,• find the ”first” even element!

The tree is planned so that the summation, maximum search, and linearsearch are implemented easily. To be able to change the type of the nodes, thetree becomes a template.

29Teréz A. Várkonyi: Object-oriented programming

2

3 4

7 15 4

8 4

21

max

search

condmax

Chained binary treeclass BinTreeprotected:

LinkedNode *_root;...

};

2

3 3

5 nil nil 4 nil nil 7 nil 1 nil

nil 8 nil nil 4 nil

root

Teréz A. Várkonyi: Object-oriented programming 30

template <typename Item>struct LinkedNode {

LinkedNode *_left;Item _val;LinkedNode *_right;

};

Class diagram

Node# val : Item

+ value() : Item {query}+ is_Leaf() : bool {virtual}+ is_Internal() : bool

Action

+exec(Node*) : void {virtual}

LinkedNode

+ is_Leaf() : bool

BinTree

+ randomInsert(const Item&):void+ preOrder(Action) :void+ inOrder(Action) :void+ postOrder(Action) :void

0..2

*

- *root

Teréz A. Várkonyi: Object-oriented programming 31

has

child

Item

Item

Item

Item

return not is_Leaf()

return left=nil and right = nil

- *left- *right

Template class of a nodetemplate <typename Item>class Node {public:

Item value() const { return _val; }virtual bool is_Leaf() const = 0;bool is_Internal() const { return !is_Leaf(); }virtual ~Node(){}

protected:Node(const Item& v): _val(v){}Item _val;

};template <typename Item> class BinTree;template <typename Item>class LinkedNode: public Node<Item>{public:

friend class BinTree;LinkedNode(const Item& v, LinkedNode *l, LinkedNode *r):

Node<Item>(v), _left(l), _right(r){}bool is_Leaf() const override

{ return _left==nullptr && _right==nullptr; }private:

LinkedNode *_left;LinkedNode *_right;

};

Teréz A. Várkonyi: Object-oriented programming 32

bintree.hpp

BinTree class is defined afterLinkedNode. To avoid circularreference, BinTree is justindicated here.

LinkedNode allows BinTree tosee its private attributes andmethods.

template <typename Item>class BinTree{public:

BinTree():_root(nullptr) {srand(time(nullptr));}~BinTree();

void randomInsert(const Item& e);

void preOrder (Action<Item>*todo){ pre (_root, todo); }void inOrder (Action<Item>*todo){ in (_root, todo); }void postOrder(Action<Item>*todo){ post(_root, todo); }

protected:LinkedNode<Item>* _root;

void pre (LinkedNode<Item>*r, Action<Item> *todo);void in (LinkedNode<Item>*r, Action<Item> *todo);void post (LinkedNode<Item>*r, Action<Item> *todo);

};

Teréz A. Várkonyi: Object-oriented programming 33

Template class of the binary tree

initialization of therandom generator : #include <time.h>#include <cstdlib>

with a given action, starting from the root,they traverse the nodes

bintree.hpp

template <typename Item>class Action{public:

virtual void exec(Node<Item> *node) = 0;virtual ~Action(){}

};

2

3 3

5 nil nil 4 nil nil 7 nil 1 nil

nil 8 nil nil 4 nil

root

Inserting a new node into the tree

nil nil

r

r

r

Right

Left

Left

Teréz A. Várkonyi: Object-oriented programming 34

Inserting a new node into the tree

void BinTree<Item>::randomInsert(const Item& e){

if(_root==nullptr) _root = new LinkedNode<Item>(e, nullptr, nullptr);else {

LinkedNode<Item> *r = _root;int d = rand();while(d&1 ? r->_left!=nullptr : r->_right!=nullptr){

if(d&1) r = r->_left;else r = r->_right;d = rand();

}if(d&1) r->_left = new LinkedNode<Item>(e, nullptr, nullptr);else r->_right= new LinkedNode<Item>(e, nullptr, nullptr);

}}

Teréz A. Várkonyi: Object-oriented programming 35

bintree.hpp

random generator

Is the last bit of the random number 1?

Building the tree

#include <iostream>#include "bintree.hpp"

using namespace std;

int main(){

BinTree<int> t;int i;while(cin >> i){

t.randomInsert(i);}

return 0;}

Teréz A. Várkonyi: Object-oriented programming 36

bintree.hpp

template <typename Item>void BinTree<Item>::pre(LinkedNode<Item> *r, Action<Item> *todo){

if(r==nullptr) return;todo->exec(r);pre(r->_left, todo);pre(r->_right, todo);

}

Preorder traversalr

I.

II. III.

Teréz A. Várkonyi: Object-oriented programming 37

1

2 3

4 nil nil 5 nil nil 6 nil 7 nil

nil 8 nil nil 9 nil

root

bintree.hpp

1 2 4 8 5 3 6 9 7

template <typename Item>void BinTree<Item>::in(LinkedNode<Item> *r, Action<Item> *todo){

if(r==nullptr) return;in(r->_left, todo);todo->exec(r);in(r->_right, todo);

}

Inorder traversalr

II.

I. III.

Teréz A. Várkonyi: Object-oriented programming 38

1

2 3

4 nil nil 5 nil nil 6 nil 7 nil

nil 8 nil nil 9 nil

root

bintree.hpp

8 4 2 5 1 6 9 3 7

template <typename Item>void BinTree<Item>::post(LinkedNode<Item> *r, Action<Item> *todo){

if(r==nullptr) return;post(r->_left, todo);post(r->_right, todo);todo->exec(r);

}

Postorder traversalr

III.

I. II.

Teréz A. Várkonyi: Object-oriented programming 39

1

2 3

4 nil nil 5 nil nil 6 nil 7 nil

nil 8 nil nil 9 nil

root

bintree.hpp

8 4 5 2 9 6 7 3 1

BinTree<int> t = build();

Printer<int> print(cout);

cout << "Preorder traversal :";t.preOrder (&print); cout << endl;

cout << "Inorder traversal :";t.inOrder (&print); cout << endl;

cout << "Postorder traversal :";t.postOrder (&print); cout << endl;

Template class of printingtemplate <typename Item>class Printer: public Action<Item>{public:

Printer(ostream &o): _os(o){};void exec(Node<Item> *node) override {

_os << '[' << node->value() << ']';}

private:ostream& _os;

};

Teréz A. Várkonyi: Object-oriented programming 40

Output operator has to be definedfor the datatype replacing Item.

bintree.hpp

Action

+exec(Node*) : void {virtual}

Printer- os : ostream&+ Printer(o:ostream&)+ exec(node:Node) : void

Item

Item

os << node._val

os := o

template <typename Item>BinTree<Item>::~BinTree(){

DelAction del;post(_root, &del);

}

protected:class DelAction: public Action<Item>{public:

void exec(Node<Item> *node) override {delete node;}};

Teréz A. Várkonyi: Object-oriented programming 41

Destructor: traversal with delete

It works only with postorder!

in BinTree<Item>’s protected part.

bintree.hpp

bintree.hpp

Action

+exec(Node*) : void {virtual}

DelAction

+ exec(node:Node) : void

Item

Item

delete node

Other actions’ classesAction

+exec(Node*) : void {virtual}

Summation- s : int+ exec(node:Node) : void+ value() : int

MaxSelect- m : int+ exec(node:Node) : void+ value() : int

LinSearch- l : bool- elem : int + exec(node:Node): void+ found() : bool+ elem() : int

Teréz A. Várkonyi: Object-oriented programming 42

Item

the attributes are initializedby the constructors

m := max(node.value(), m)

If not l and node.value() mod 2 = 0 then

l := trueelem := node.value()

endif

CondMaxSearch- m : int- l : bool+ exec(node:Node) : void+ value() : int+ found() : bool

if node.is_Leaf() then return endifif not l then

l := truem := node. value()

elsem := max(node.value(), m)

endif

if node.is_Internal() thens := s + node.value()

endif

int

Summation

class Summation: public Action<int>{public:

void Summation():_s(0){}void exec(Node<int> *node) override {

{ if(node->Is_Internal()) _s += node->value(); }int value() const {return _s;}

private:int _s;

};

BinTree<int> t = build();

Summation sum;t.preOrder(&sum);cout << "Sum of the elements of the tree: "

<< sum.value() << endl;

Teréz A. Várkonyi: Object-oriented programming 43

Linear searchclass LinSearch: public Action<int>{public:

void LinSearch():_l(false){}void exec(Node<int> *node) override {

if (!l && node->value ()%2==0){l = true;_elem = node->value();

}}bool found() const {return _l;}int elem() const {return _elem;}

private:bool _l;int _elem;

};

BinTree<int> t = build();

LinSearch search;t.preOrder(&search);

if (search.found()) cout << search.elem() << " is an";else cout << "There is no";cout << " even element in the tree.";

Teréz A. Várkonyi: Object-oriented programming 44

Maximum search

class MaxSelect: public Action<int>{public:

MaxSelect(int &i) : _m(i){}void exec(Node<int> *node) override{ _m = max( _m, node->value() ); }

int value() const {return _m;}private:

int _m;};

template <class Item> class BinTree {…public:

enum Exceptions{NOROOT};Item rootValue() const {

if( _root==nullptr ) throw NOROOT;return _root->value();

}

BinTree<int> t = build();

MaxSelect max(t.rootValue());t.preOrder(&max);

cout << "Maxima of the elements of the tree: " << max.value();

Teréz A. Várkonyi: Object-oriented programming 45

bintree.hpp

It shoud raise an exception ifthe tree is empty (without root)

Conditional maximum search

BinTree<int> t = build();

CondMaxSearch max;t.preOrder(&max);

cout << "Maxima of the elements of the tree: " << endl;if(max.value().l) cout << max.value().m << endl;else cout << "none" << endl;

Teréz A. Várkonyi: Object-oriented programming 46

class CondMaxSearch: public Action<int>{public:

struct Result {int m;bool l;

};CondMaxSearch(){_r.l = false;}virtual void exec(Node<int> *node) {

if(node->is_Leaf()) return;if(!_r.l){

_r.l = true;_r.m = node->value();

}else{_r.m = max( _r.m, node->value() );

}}Result value(){return _r;}

private:Result _r;

};

top related