This document provides the code and comments for a C++ program that tests the construction and functionality of a binary search tree data structure. The main() function contains code to test constructing an empty tree, inserting nodes, checking the size and printing the tree, and clearing the tree. Comments provide descriptions of the program and the parameters and return value for main(). The code tests functions for inserting nodes, getting the size, printing the tree, and clearing it. Assertions confirm the expected behavior.
1. /**
* @author Jane Programmer
* @cwid 123 45 678
* @class COSC 2336, Spring 2019
* @ide Visual Studio Community 2017
* @date April 8, 2019
* @assg Assignment 12
*
* @description Assignment 12 Binary Search Trees
*/
#include <cassert>
#include <iostream>
#include "BinaryTree.hpp"
using namespace std;
/** main
* The main entry point for this program. Execution of this
program
* will begin with this main function.
*
* @param argc The command line argument count which is the
number of
* command line arguments provided by user when they
started
* the program.
* @param argv The command line arguments, an array of
character
* arrays.
*
* @returns An int value indicating program exit status.
Usually 0
* is returned to indicate normal exit and a non-zero value
2. * is returned to indicate an error condition.
*/
int main(int argc, char** argv)
{
// -----------------------------------------------------------------------
cout << "--------------- testing BinaryTree construction --------
--------" << endl;
BinaryTree t;
cout << "<constructor> Size of new empty tree: " << t.size()
<< endl;
cout << t << endl;
assert(t.size() == 0);
cout << endl;
// -----------------------------------------------------------------------
cout << "--------------- testing BinaryTree insertion ------------
-------" << endl;
t.insert(10);
cout << "<insert> Inserted into empty tree, size: " << t.size()
<< endl;
cout << t << endl;
assert(t.size() == 1);
t.insert(3);
t.insert(7);
t.insert(12);
t.insert(15);
t.insert(2);
cout << "<insert> inserted 5 more items, size: " << t.size() <<
endl;
cout << t << endl;
assert(t.size() == 6);
4. }
C y b e r A t t a c k s
“Dr. Amoroso’s fi fth book Cyber Attacks: Protecting National
Infrastructure outlines the chal-
lenges of protecting our nation’s infrastructure from cyber
attack using security techniques
established to protect much smaller and less complex
environments. He proposes a brand
new type of national infrastructure protection methodology and
outlines a strategy presented
as a series of ten basic design and operations principles ranging
from deception to response.
The bulk of the text covers each of these principles in technical
detail. While several of these
principles would be daunting to implement and practice they
provide the fi rst clear and con-
cise framework for discussion of this critical challenge. This
text is thought-provoking and
should be a ‘must read’ for anyone concerned with
cybersecurity in the private or government
sector.”
— Clayton W. Naeve, Ph.D. ,
Senior Vice President and Chief Information Offi cer,
Endowed Chair in Bioinformatics,
St. Jude Children’s Research Hospital,
5. Memphis, TN
“Dr. Ed Amoroso reveals in plain English the threats and
weaknesses of our critical infra-
structure balanced against practices that reduce the exposures.
This is an excellent guide
to the understanding of the cyber-scape that the security
professional navigates. The book
takes complex concepts of security and simplifi es it into
coherent and simple to understand
concepts.”
— Arnold Felberbaum ,
Chief IT Security & Compliance Offi cer,
Reed Elsevier
“The national infrastructure, which is now vital to
communication, commerce and entertain-
ment in everyday life, is highly vulnerable to malicious attacks
and terrorist threats. Today, it
is possible for botnets to penetrate millions of computers around
the world in few minutes,
and to attack the valuable national infrastructure .
“As the New York Times reported, the growing number of
threats by botnets suggests that
this cyber security issue has become a serious problem, and we
are losing the war against
these attacks.
“While computer security technologies will be useful for
network systems, the reality
tells us that this conventional approach is not effective enough
for the complex, large-scale
6. national infrastructure.
“Not only does the author provide comprehensive
methodologies based on 25 years of expe-
rience in cyber security at AT&T, but he also suggests ‘security
through obscurity,’ which
attempts to use secrecy to provide security.”
— Byeong Gi Lee ,
President, IEEE Communications Society, and
Commissioner of the Korea Communications Commission
(KCC)
C y b e r A t t a c k s
Protecting National
Infrastructure
Edward G. Amoroso
AMSTERDAM • BOSTON • HEIDELBERG • LONDON
NEW YORK • OXFORD • PARIS • SAN DIEGO
SAN FRANCISCO • SINGAPORE • SYDNEY • TOKYO
Butterworth-Heinemann is an imprint of Elsevier
Acquiring Editor: Pam Chester
Development Editor: Gregory Chalson
Project Manager: Paul Gottehrer
Designer: Alisa Andreola
8. any liability for any injury and/or damage to persons or
property as a matter of products liability,
negligence or otherwise, or from any use or operation of any
methods, products, instructions, or
ideas contained in the material herein.
Library of Congress Cataloging-in-Publication Data
Amoroso, Edward G.
Cyber attacks : protecting national infrastructure / Edward
Amoroso.
p. cm.
Includes index.
ISBN 978-0-12-384917-5
1. Cyberterrorism—United States—Prevention. 2. Computer
security—United States. 3. National
security—United States. I. Title.
HV6773.2.A47 2011
363.325�90046780973—dc22 2010040626
British Library Cataloguing-in-Publication Data
A catalogue record for this book is available from the British
Library.
Printed in the United States of America
10 11 12 13 14 10 9 8 7 6 5 4 3 2 1
For information on all BH publications visit our website at
www.elsevierdirect.com/security
CONTENTS v
CONTENTS
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16. PREFACE ix
PREFACE
Man did not enter into society to become worse than he was
before,
nor to have fewer rights than he had before, but to have those
rights better secured.
Thomas Paine in Common Sense
Before you invest any of your time with this book, please take
a
moment and look over the following points. They outline my
basic philosophy of national infrastructure security. I think that
your reaction to these points will give you a pretty good idea of
what your reaction will be to the book.
1. Citizens of free nations cannot hope to express or enjoy
their freedoms if basic security protections are not provided.
Security does not suppress freedom—it makes freedom
possible.
2. In virtually every modern nation, computers and
networks
power critical infrastructure elements. As a result, cyber
attackers can use computers and networks to damage or ruin
the infrastructures that citizens rely on.
3. Security protections, such as those in security books,
were
designed for small-scale environments such as enterprise
computing environments. These protections do not extrapo-
late to the protection of massively complex infrastructure.
17. 4. Effective national cyber protections will be driven
largely by
cooperation and coordination between commercial, indus-
trial, and government organizations. Thus, organizational
management issues will be as important to national defense
as technical issues.
5. Security is a process of risk reduction, not risk removal.
Therefore, concrete steps can and should be taken to
reduce, but not remove, the risk of cyber attack to national
infrastructure.
6. The current risk of catastrophic cyber attack to national
infra-
structure must be viewed as extremely high, by any realistic
measure. Taking little or no action to reduce this risk would be
a foolish national decision.
The chapters of this book are organized around ten basic
principles that will reduce the risk of cyber attack to national
infrastructure in a substantive manner. They are driven by
x PREFACE
experiences gained managing the security of one of the largest,
most complex infrastructures in the world, by years of learning
from various commercial and government organizations, and by
years of interaction with students and academic researchers in
the security fi eld. They are also driven by personal experiences
dealing with a wide range of successful and unsuccessful cyber
attacks, including ones directed at infrastructure of considerable
value. The implementation of the ten principles in this book will
require national resolve and changes to the way computing and
networking elements are designed, built, and operated in the
18. context of national infrastructure. My hope is that the sugges-
tions offered in these pages will make this process easier.
ACKNOWLEDGMENT xi
ACKNOWLEDGMENT
The cyber security experts in the AT&T Chief Security Offi
ce, my
colleagues across AT&T Labs and the AT&T Chief Technology
Offi ce, my colleagues across the entire AT&T business, and my
graduate and undergraduate students in the Computer Science
Department at the Stevens Institute of Technology, have had
a profound impact on my thinking and on the contents of this
book. In addition, many prominent enterprise customers of
AT&T with whom I’ve had the pleasure of serving, especially
those in the United States Federal Government, have been great
infl uencers in the preparation of this material.
I’d also like to extend a great thanks to my wife Lee, daugh-
ter Stephanie (17), son Matthew (15), and daughter Alicia (9)
for
their collective patience with my busy schedule.
Edward G. Amoroso
Florham Park, NJ
September 2010
This page intentionally left blank
20. National infrastructure, especially in the United States, has
always been vulnerable to malicious physical attacks such as
equipment tampering, cable cuts, facility bombing, and asset
theft. The events of September 11, 2001, for example, are the
most prominent and recent instance of a massive physical attack
directed at national infrastructure. During the past couple of
decades, however, vast portions of national infrastructure have
become reliant on software, computers, and networks. This reli -
ance typically includes remote access, often over the Internet, to
1
1 E.W. Dijkstra, Selected Writings on Computing: A
Personal Perspective , Springer-Verlag,
New York, 1982, pp. 212–213.
2 T. Friedman, The World Is Flat: A Brief History of the
Twenty-First Century , Farrar,
Straus, and Giroux, New York, 2007. (Friedman provides a
useful economic backdrop to
the global aspect of the cyber attack trends suggested in this
chapter.)
2 Chapter 1 INTRODUCTION
the systems that control national services. Adversaries thus
can
initiate cyber attacks on infrastructure using worms, viruses,
leaks, and the like. These attacks indirectly target national
infra-
structure through their associated automated controls systems
(see Figure 1.1 ).
A seemingly obvious approach to dealing with this national
21. cyber threat would involve the use of well-known computer
security techniques. After all, computer security has matured
substantially in the past couple of decades, and considerable
expertise now exists on how to protect software, computers, and
networks. In such a national scheme, safeguards such as fi re-
walls, intrusion detection systems, antivirus software,
passwords,
scanners, audit trails, and encryption would be directly embed-
ded into infrastructure, just as they are currently in small -scale
environments. These national security systems would be con-
nected to a centralized threat management system, and inci-
dent response would follow a familiar sort of enterprise process.
Furthermore, to ensure security policy compliance, one would
expect the usual programs of end-user awareness, security train-
ing, and third-party audit to be directed toward the people
build-
ing and operating national infrastructure. Virtually every
national
infrastructure protection initiative proposed to date has
followed
this seemingly straightforward path. 3
While well-known computer security techniques will certainly
be useful for national infrastructure, most practical experience
to date suggests that this conventional approach will not be suf-
fi cient. A primary reason is the size, scale, and scope inherent
in
complex national infrastructure. For example, where an enter-
prise might involve manageably sized assets, national
infrastruc-
ture will require unusually powerful computing support with
the ability to handle enormous volumes of data. Such volumes
Indirect
Cyber
Attacks
23. Chapter 1 INTRODUCTION 3
will easily exceed the storage and processing capacity of
typical
enterprise security tools such as a commercial threat manage-
ment system. Unfortunately, this incompatibility confl icts with
current initiatives in government and industry to reduce costs
through the use of common commercial off-the-shelf products.
In addition, whereas enterprise systems can rely on manual
intervention by a local expert during a security disaster, large-
scale national infrastructure generally requires a carefully
orches-
trated response by teams of security experts using
predetermined
processes. These teams of experts will often work in different
groups, organizations, or even countries. In the worst cases,
they will cooperate only if forced by government, often sharing
just the minimum amount of information to avoid legal conse-
quences. An additional problem is that the complexity
associated
with national infrastructure leads to the bizarre situation where
response teams often have partial or incorrect understand-
ing about how the underlying systems work. For these reasons,
seemingly convenient attempts to apply existing small-scale
security processes to large-scale infrastructure attacks will ulti-
mately fail (see Figure 1.2 ).
As a result, a brand-new type of national infrastructure protec-
tion methodology is required—one that combines the best ele-
ments of existing computer and network security techniques
with
the unique and diffi cult challenges associated with complex,
large-
24. scale national services. This book offers just such a protection
methodology for national infrastructure. It is based on a quarter
century of practical experience designing, building, and
operating
Small-Scale
Small Volume
Possibly Manual
Local Expert
High
Focused
High Volume
Large-Scale
Process-Based
Distributed Expertise
Partial or Incorrect
Broad
Collection
Emergency
Expertise
Knowledge
25. Analysis
Large-Scale
Attributes
Complicate
Cyber Security
Figure 1.2 Differences between small- and large-scale cyber
security.
National infrastructure
databases far exceed the
size of even the largest
commercial databases.
4 Chapter 1 INTRODUCTION
cyber security systems for government, commercial, and con-
sumer infrastructure. It is represented as a series of protection
principles that can be applied to new or existing systems.
Because
of the unique needs of national infrastructure, especially its
mas-
sive size, scale, and scope, some aspects of the methodology
will
be unfamiliar to the computer security community. In fact,
certain
elements of the approach, such as our favorable view of
“security
through obscurity,” might appear in direct confl ict with
conven-
tional views of how computers and networks should be
protected.
26. National Cyber Threats, Vulnerabilities,
and Attacks
Conventional computer security is based on the oft-repeated
tax-
onomy of security threats which includes confi dentiality,
integrity,
availability, and theft. In the broadest sense, all four diverse
threat
types will have applicability in national infrastructure. For
example,
protections are required equally to deal with sensitive
information
leaks (confi dentiality ), worms affecting the operation of some
criti-
cal application (integrity), botnets knocking out an important
system
(availability), or citizens having their identities compromised
(theft).
Certainly, the availability threat to national services must be
viewed
as particularly important, given the nature of the threat and its
rela-
tion to national assets. One should thus expect …
In this assignment you will be given the beginning of a
BinaryTree imple-
mentation using linked nodes via pointers. You will be
implementing some
of the basic function of a BinaryTree abstract data type. The
abstraction
we are using for the BinaryTreeNode and the BinaryTree are
similar to
the Sha_er BSTNode (pg. 156,161) and the BST abstract class
and linked
pointer implementation (Sha_er pg. 171), but we will de_ne our
27. own version
and simplify some of the functions and interface.
You have been given a BinaryTree.[cpp|hpp] _le that de_nes the
BinaryTreeNode
structure and BinaryTree class. This class is current not
templatized, the
constructed trees only hold items of simple type int (one of the
extra credit
opportunities suggests you templatize your resulting class). The
BinaryTree
has a constructor, and you have been provided a tostring()
method and
an overloaded operator_() so that you can display the current
contents of
the tree.
For this assignment you need to perform the following tasks.
1
1. In order to test your class, we _rst have to get a working
capability to
insert new items into the BinaryTree, which isn't the simplest
task to
start with, but we can't really test others until we can add new
items.
For many of the functions in this assignment, you will be
required to
implement them using a recursive function. Thus many of the
func-
tions for your BinaryTree will have a public function that asks
as the
interface that is called by users of the BinaryTree, and a private
ver-
sion that actually does the work using a recursive algorithm. I
will
give you the signature you need for the insert() functions:
class BinaryTree
{
28. private:
BinaryTreeNode* insert(BinaryTreeNode* node, const int item);
public:
void insert(const int item);
}
Lets start _rt with the public insert() function. This function is
the
public interface to insert a new item into the tree. Since we are
only
implementing a tree of int items, you simply pass in the int
value that
is to be inserted. This function basically only needs to call the
private
insert() function, passing in the current root of the tree as the
_rst
parameter, and the item to be inserted as the second parameter.
Notice
that the private insert() returns a pointer to a BinaryTreeNode.
The private insert() function is a recursive function. The base
case
is simple. If the node you pass in is NULL, then that means you
have
found the location where a new node should be created and
inserted.
So for the base case, when node is NULL you should
dynamically create
a new BinaryTreeNode item, assign the item and make sure that
the
left and right pointers are initialized to NULL.When you create
a new
node like this, you should return the newly created
BinaryTreeNode as
a result from the insert() function (notice that the private
insert()
should always return a BinaryTreeNode*). This is because,
when a
29. new node is allocated, it gets returned and it needs to be
assigned to
something so it gets inserted into the tree. For example, think of
what
happens initially when the BinaryTree is empty. In that case the
root
of the tree will be NULL. When you call the recursive insert()
on the
initially empty tree, you need to assign the returned value back
into
2
root in the non-recursive function (and you also need to
increment the
nodeCount by 1 in your public non-recursive function).
The general cases for the recursion are as follows. Since we are
imple-
menting a binary search tree, we need to keep the tree
organized/sorted.
Thus in the general case, remember that we have already tested
that
the node is not NULL, thus there is an item in the node->item.
So for
the general case, if the item we are inserting is less than or
equal to
node->item, then we need to insert it into the left child subtree
(it
is important to use <= comparison to determine if to go left
here). To
do this you will basically just call insert() recursively with the
item
to be inserted, and passing in node->left as the _rst parameter.
Of
course, in the case that the item is greater than the one in the
cur-
rent node, you instead need to call insert() on the node->right
child
30. subtree.
And _nally, make sure you take care of correctly returning a
result
from the recursive insert(). Here when you call insert() on ei -
ther the left or right child subtree, the function should return a
BinaryTreeNode*. For example, imagine that you are inserting
into
the left child, and there is no left subtree, and thus left will be
NULL. In that case the recursive call to insert() will create a
new node
dynamically and return it. So the return value from calling
insert()
needs to be assiged back into something. If you are calling
insert()
on the left child, the returned result should be assigned back
into
node->left, and if you are calling on the right child, the returned
re-
sult should be assigned back into node->right. Again this is
because
when we _nally _nd where the node needs to be linked into the
tree,
we will do it at either an empty left or right subtree child. Thus
in order to link the newly created node into the tree, we need to
as-
sign the returned pointer back into either node->left or node-
>right
appropriately. And _nally, after you call insert() recursively in
the
general case, you do have to remember that you always have to
return
a BinaryTreeNode*. For the base case, when you dynamically
create
a new node, the new node is what you return. But in the general
case,
you should simply return the current node. This will get
31. (re)assigned
when you return back to the parent, but this is _ne and
expected.
To summarize, you need to do the following to implement the
insert()
functionality:
. The public insert() should simply call the private insert() on
3
the root node.
. In the public insert() the return result should be assigned back
into root.
. The public insert() is also responsible for incrementing the
nodeCount
member variable.
. For the private recursive insert() the base case occurs when a
NULL node is received, in which case a new BinaryTreeNode is
dynamically created and returned.
. For the general case, if node is not NULL, then you instead
either
need to call insert() recursively on the left or right subchild,
depending on if the item to be inserted is <= or > the node-
>item
respectively.
. Don't forget in the general case, that the returned result from
calling insert() needs to be assigned back into left or right as
appropriate.
. And _nally, the recursive insert() always returns a value, and
in the general case you should simply just return the node as the
result.
2. Next we have a relatively easier set of tasks to accomplish.
Once
you have insert() working and tested, we will implement a
function
to determine the current height() of the tree. You should read
our
textbook to make sure you know the de_nition of the height of a
32. tree.
height() needs 2 functions again, a public function which is the
in-
terface, and a private function that is recursive and does the
actual
work. Both the public and private height() functions should be
de-
clared as const functions, as they do not actually modify the
contents
of the tree. Both functions return an int result. The public
function
doesn't have any input parameters, but the private function
should
take a single BinaryTreeNode* as its input parameter.
The public height() function should be very simply, it should
simply
call the private height() on the root node of the binary tree, and
return the resulting calculated height.
For the private height() function, the base case is that if node is
NULL
then the height is 0, so you should return 0 in that case.
Otherwise,
in the general case, the height is conceptuall 1 plus the height
of the
bigger of the heights of the two subtree children left and right.
Thus
4
to calculate the height for a given node, recursive calculate
height on
both the left and right children, _nd the maximum of these two,
add
1 to it, and that is the height of the node.
3. The third and _nal task is to implement the clear() abstract
function.
The clear() function basically clears out all of the stored items
from
33. the tree, deallocating and returning the memory used for the
node
storage back to the OS.
As with all of the functions for this assignment, clear() needs
both
a public function that acts as the interface, and a private
recursive
version that does all of the work. The implementation of the
pub-
lic clear() is almost as simple as the previous height() function.
The public clear() should simply call the private clear(), passing
in the current root of the tree. Both the public and private
versions
of clear() should be void functions, they do not return any result
or
value.
The private recursive clear() is a void function, as we
mentioned,
and it takes a single BinaryTreeNode* parameter as its input.
This
function is also relatively rather easy. The base case is that, if
node is
NULL then you don't have to do anything, simply return, as you
have
reached the end of the recursion in that case. For the general
case,
all you need to do is simply call clear() recursively on the left
and
right subtree children _rst. Then after this you can safely call
delete
on the node, because all of the nodes in the two subtree children
will
have been deleted by the recursion, and now you can safely
delete and
free up the memory for the node.
In this assignment you will only be given 3 _les in total. The
34. "assg-
12.cpp" _le contains tests of the BinaryTree insert(), height()
and clear()
functions you are to implement. You will also be given
"BinaryTree.hpp"
which is a header _le containing the de_nition of the
BinaryTreeNode struc-
ture and BinaryTree class, including initial implementations for
constructors
and for displaying the tree as a string.
Here is an example of the output you should get if your code is
passing
all of the tests and is able to run the simulation. You may not
get the
exact same statistics for the runSimulation() output, as the
simulation is
generating random numbers, but you should see similar values.
--------------- testing BinaryTree construction ----------------
<constructor> Size of new empty tree: 0
5
size: 0 items: [ ]
--------------- testing BinaryTree insertion -------------------
<insert> Inserted into empty tree, size: 1
size: 1 items: [ 10 ]
<insert> inserted 5 more items, size: 6
size: 6 items: [ 2 3 7 10 12 15 ]
--------------- testing BinaryTree height -------------------
<height> Current tree height: 3
<height> after inserting nodes, height: 5 size: 8
size: 8 items: [ 2 3 4 5 7 10 12 15 ]
--------------- testing BinaryTree clear -------------------
<clear> after clearing tree, height: 0 size: 0
size: 0 items: [ ]
Assignment Submission
/**
35. * @author Jane Programmer
* @cwid 123 45 678
* @class COSC 2336, Spring 2019
* @ide Visual Studio Community 2017
* @date April 8, 2019
* @assg Assignment 12
*
* @description Assignment 12 Binary Search Trees
*/
#include <string>
using namespace std;
/** Binary Tree Node
* A binary tree node, based on Shaffer binary tree node ADT,
pg. 156.,
* implementation pg. 161. The node class is not the tree. A
binary
* search tree consists of a structure/colleciton of binary tree
nodes,
* arranged of course as a binary tree. A binary tree nodes
purpose is to
* store the key/value of a single item being managed, and to
keep links
* to left and right children.
*
* We assume both key and value are the same single item here.
This
* version is not templatized, we create nodes that hold simple
int
* values, but we could parameritize this to hold arbitrary value
* types.
*
* @value item The item held by this binary tree node. This
item is
36. * both the key and the value of the item being stored. In
* alternative implementations we might want to split the key
and
* value into two separate fields.
* @value left, right Pointers to the left child and right child
nodes
* of this node. These can be null to indicate that not left/right
* child exists. If both are null, then this node is a leaf node.
*/
struct BinaryTreeNode
{
int item;
BinaryTreeNode* left;
BinaryTreeNode* right;
};
/** Binary Tree
* A binary search tree implementation, using pointers/linked
list, based
* on Shaffer example implementation pg. 171. This is the class
that
* actually manages/implements the tree. It contains a single
* pointer to the root node at the top (or bottom depending on
how you
* view it) of the tree. We also maintain a count of the number
of nodes
* currently in the tree. This class will support insertion
* and searching for new nodes.
*
* @value root A pointer to the root node at the top of the
* tree. When the tree is initially created and/or when the tree
is
* empty then root will be null.
* @value nodeCount The count of the number of nodes/items
currently in
37. * this binary tree.
*/
class BinaryTree
{
private:
BinaryTreeNode* root;
int nodeCount;
// private helper methods, do actual work usually using
recursion
string tostring(BinaryTreeNode* node) const;
BinaryTreeNode* insert(BinaryTreeNode* node, const int
item);
public:
// constructors and destructors
BinaryTree();
~BinaryTree();
// accessor methods
int size() const;
// insertion, deletion and searching
void insert(const int item);
// tree traversal and display
string tostring() const;
friend ostream& operator<<(ostream& out, const BinaryTree&
aTree);
};
/**
* @author Jane Programmer
* @cwid 123 45 678
* @class COSC 2336, Spring 2019
38. * @ide Visual Studio Community 2017
* @date April 8, 2019
* @assg Assignment 12
*
* @description Assignment 12 Binary Search Trees
*/
#include <iostream>
#include <string>
#include <sstream>
#include "BinaryTree.hpp"
using namespace std;
/** BinaryTree default constructor
* Default constructor for a BinaryTree collection. The default
* behavior is to create an initially empty tree with no
* items currently in the tree.
*/
BinaryTree::BinaryTree()
{
root = NULL;
nodeCount = 0;
}
/** BinaryTree destructor
* The destructor for a BinaryTree. Be a good manager of
memory
* and make sure when a BinaryTree goes out of scope we free
* up all of its memory being managed. The real work is done
* by the clear() member function, whose purpose is exactly
this,
* to clear all items from the tree and return it back to an
* empty state.
*/
39. BinaryTree::~BinaryTree()
{
// uncomment this after you implement clear in step X, to
ensure
// when trees are destructed that all memory for allocated
nodes
// is freed up.
//clear();
}
/** BinaryTree size
* Return the current size of this BinaryTree. Here size means
the
* current number of nodes/items currently being managed by
the
* BinaryTree.
*
* @returns int Returns the current size of this BinaryTree.
*/
int BinaryTree::size() const
{
return nodeCount;
}
/** BinaryTree tostring
* This is the recursive private function that does the actual
* work of creating a string representation of the BinaryTree.
* We perform a (recursive) inorder traversal, constructing a
* string object, to be returned as a result of this function.
*
* @param node The BinaryTreeNode we are currently
processing.
*
40. * @returns string Returns the constructed string of the
BinaryTree
* contents in ascending sorted order.
*/
string BinaryTree::tostring(BinaryTreeNode* node) const
{
// base case, if node is null, just return empty string, which
// stops the recursing
if (node == NULL)
{
return "";
}
// general case, do an inorder traversal and build tring
else
{
ostringstream out;
// do an inorder traversal
out << tostring(node->left)
<< node->item << " "
<< tostring(node->right);
return out.str();
}
}
/** BinaryTree tostring
* Gather the contents and return (for display) as a string.
* We use an inorder traversal to get the contents and construct
* the string in sorted order. This function depends on
operator<<
* being defined for the item type being held by the
BinaryTreeNode.
* This function is actually only the public interface, the
41. * actual work is done by the private recursive tostring()
function.
*
* @returns string Returns the constructed string of the
BinaryTree
* contents in ascending sorted order.
*/
string BinaryTree::tostring() const
{
ostringstream out;
out << "size: " << nodeCount
<< " items: [ " << tostring(root) << "]" << endl;
return out.str();
}
/** BinaryTree output stream operator
* Friend function for BinaryTree, overload output stream
* operator to allow easy output of BinaryTree representation
* to an output stream.
*
* @param out The output stream object we are inserting a
string/
* representation into.
* @param aTree A reference to the actual BinaryTree object to
be
* displayed on the output stream.
*
* @returns ostream Returns reference to the output stream after
* we insert the BinaryTree contents into it.
*/
ostream& operator<<(ostream& out, const BinaryTree& aTree)
{
out << aTree.tostring();
42. return out;
}
BinaryTreeNode* BinaryTree::insert(BinaryTreeNode* node,
const int item)
{
// Base Cases: root is null or key is present at root
if (root == NULL || root->item == item)
return root;
// Key is greater than root's key
if (root->item < item)
return insert(root->right, item);
// Key is smaller than root's key
return insert(root->left, item);
}
void BinaryTree::insert(const int item)
43. {
BinaryTreeNode* newNode; //Pointer to a new
node
//Create a new node and store num in it
newNode = new BinaryTreeNode;
newNode-> item = item;
newNode->left = newNode->right = NULL;
//Insert the node
insert(root, item);
}