245 views

Uploaded by api-3701809

save

- Data Structures Assignment
- UNIT III.docx
- 6. IMPLEMENTATION OF BINARY SEARCH TREE
- Data Strs Using C
- Project 4
- data structure lab manual
- CS-302-(3001-(O)).pdf
- Data Structures
- mcdermott 6014 final summer b 17
- 1-Java.docx
- Topic1 State Space Search
- Hull-White Model 2
- Artificial Intelligence Projects for the Commodore 64
- 2014-fpdaa
- TOTSOL-DSTR-02
- A Dynamic Error based fair scheduling using Two Layered Distributed Heap Sort Tree for a Computational Grid
- Seg Tree
- Lecture 8 - Binary Trees
- B_plus_tree_ch14.doc
- Fast Meals Quick Snacks- A Cookbook for Teenagers
- Linux-Training-Volume1
- Computer's Bus
- Q A Testing

You are on page 1of 43

**The curiosity of our surroundings is the constant force that drives humanity forward. In an effort to
**

better ourselves and our future we study the world we live in. Our own inventions define the way in

which we lead our lives, and what people we become. Computers have now become the center of many

cultures around the world, as technology unites people in a way that has never been seen before,

changing the way we view each other. In the last decade, the Internet has become a medium that lets

people share their ideas and opinions with millions of others. We are very close to a world where

ignorance is no longer an excuse. Computers are, and will be even more, in the center of our lives.

-- "World Around Us" by Alec Solway

**Computer programming is an exiciting field in the modern world. We make our lives easier by "telling"
**

the computer to perform certain tasks for us. In a sense, this is what programming is. All types of tasks

require some kind of data to be manipulated. Whether we want to play a game, or manage our portfolio,

data is involved. By creating new ways to manage (access and change) data, we can make programs

more efficient, and thus obtain more reliable and faster results. Different types of programs require

different ways of handling data, however, standards exists between various programs. This website gives

you a peek into those standards, into the world of data structures and algorithms. It is

recommended that the reader have some experience with programming in general, although a brief

review of the C++ concepts needed to understand the data structure tutorials is provided. Please click on

"C++ Review" to begin your visit, or on "Data Structures" if you already have a solid C++ programming

background. Enjoy!

© 2000 ThinkQuest Team C005618

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\An Introduction to Data ... 12/13/2007
**

An Introduction to Data Structures with C++ Page 1 of 14

Binary Trees

Binary trees are different from the three previous structures we have covered before. Lists, stacks, and

queues were all linear structures, that is, the elements in them were logically following each other.

A binary tree structure contains a root node, which is the first in the structure. The root points to one or

two other nodes, its left and right children. The root is considered to be a parent of these two nodes.

Each child is also a sub-tree, since it can have one or two children of its own. If a node has no children,

it is referred to as a leaf node.

Each node in the tree also has a level associated with it. The root node is at level 0, and increases with

each row of nodes below the root.

**Binary trees have many different basic implementations. An array implementation is often times used,
**

where every level must be completely filled. In larger trees, this can be a very big waste of space. For

our demonstration, we will create a generic class using dynamic memory allocation. This particular

implementation was created by the author using a mixture of possible approaches. It is very effective in

explaining the concepts behind binary trees.

The binary tree class gives the programmer complete control over the tree. Nodes may be removed and

inserted into any location in the list. The class allows the user to traverse the tree by keeping a current

pointer, just as in the linked list class. The programmer can then use the functions left(), right(), and

parent() to move from one node to another. The class also allows the user to display the tree in in-

order, post-order, and pre-order. The "order" refers to how the nodes are displayed. For instance, in pre-

order, a node's value is displayed, then the value of its left child, followed by the right child. In the case

of in-order, the node's value is displayed between the value of its left and right child. In post order, the

node's children are displayed before it. The implementation for the binary tree class is displayed below.

Although it may look intimidating at first, the code is very easy to follow. The purpose and code behind

each function is explained following the definition. You will note, most functions are programmed using

recursion. Since each node is actually a tree within itself, using recursion is the easiest approach

Many books make a class for a single node, and use it to implement the tree. However, we will separate

the structure for each node and the entire tree to conserve overhead processing time. Each time a node is

created, much less time and memory is used than when a whole tree structure is made. Each node will

store a value, and pointers to its children and parent. These will be used and modified by the general tree

class.

**template <class ItemType>
**

struct TreeNode

{

ItemType data;

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 2 of 14

TreeNode<ItemType> *left;

TreeNode<ItemType> *right;

TreeNode<ItemType> *parent;

};

**template <class ItemType>
**

class BinaryTree

{

public:

BinaryTree(); //create empty tree with default root node which has no value. set

current to main root node.

BinaryTree(TreeNode<ItemType>*,int); //create new tree with passed node as the

new main root. set current to main root. if the second parameter is 0, the new

object simply points to the node of the original tree. If the second parameter is

1, a new copy of the subtree is created, which the object points to.

~BinaryTree();

void insert(const ItemType&,int); //insert new node as child of current. 0=left

1=right

void remove(TreeNode<ItemType>*); //delete node and its subtree

ItemType value() const; //return value of current

**//navigate the tree
**

void left();

void right();

void parent();

void reset(); //go to main_root

void SetCurrent(TreeNode<ItemType>*);

**//return subtree (node) pointers
**

TreeNode<ItemType>* pointer_left() const;

TreeNode<ItemType>* pointer_right() const;

TreeNode<ItemType>* pointer_parent() const;

TreeNode<ItemType>* pointer_current() const;

**//return values of children and parent without leaving current node
**

ItemType peek_left() const;

ItemType peek_right() const;

ItemType peek_parent() const;

**//print the tree or a subtree. only works if ItemType is supported by <<
**

operator

void DisplayInorder(TreeNode<ItemType>*) const;

void DisplayPreorder(TreeNode<ItemType>*) const;

void DisplayPostorder(TreeNode<ItemType>*) const;

**//delete all nodes in the tree
**

void clear();

//

bool IsEmpty() const;

bool IsFull() const;

private:

TreeNode<ItemType>* current;

TreeNode<ItemType>* main_root;

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 3 of 14

**TreeNode<ItemType>* CopyTree(TreeNode<ItemType>*,TreeNode<ItemType>*)
**

const; //create a new copy of a subtree if passed to the constructor

bool subtree; //does it reference a part of a larger object?

};

The first constructor simply sets the main_root and current data members to NULL, since the tree has

no nodes. A new tree is made, therefore it is not part of a larger tree object, and the subtree value is set

accordingly.

**template <class ItemType>
**

BinaryTree<ItemType>::BinaryTree()

{

//create a root node with no value

main_root = NULL;

current = NULL;

subtree = false;

}

The second constructor accepts a pointer to a node, and creates a new tree object with the node that is

passed acting as the new tree's main root. current is then set to the main root. The second parameter

specifies whether the new subtree object points directly to the original tree's nodes (the root and its

decedents), or creates a copy of the subtree and is thus a new tree. The subtree variable specifies if the

subtree points directly to the original tree's nodes. As you will later find out, this is important in the class

destructor.

**template <class ItemType>
**

BinaryTree<ItemType>::BinaryTree(TreeNode<ItemType>* root, int op)

{

if(op = 0)

{

main_root = root;

current = root;

subtree = true;

}

else

{

main_root = CopyTree(root,NULL);

current = main_root;

subtree = false;

}

}

The CopyTree() function creates a copy of subtree root and returns a pointer to the location of the new

copy's root node. The second parameter is a pointer to the parent of the subtree being passed. Since

CopyTree() uses recursion to traverse the original tree, passing each node's parent as a parameter is the

most efficient way of assigning each new node's parent value. Since the parent of the main root is

always NULL, we pass NULL as the second parameter in the class constructor above.

**template <class ItemType>
**

TreeNode<ItemType>* BinaryTree<ItemType>::CopyTree(TreeNode<ItemType> *root,

TreeNode<ItemType> *parent) const

{

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 4 of 14

**if(root == NULL) //base case - if the node doesn't exist, return NULL.
**

return NULL;

TreeNode<ItemType>* tmp = new TreeNode<ItemType>; //make a new location in

memory

tmp->data = root->data; //make a copy of the node's data

tmp->parent = parent; //set the new node's parent

tmp->left = CopyTree(root->left,tmp); //copy the left subtree of the current

node. pass the current node as the subtree's parent

tmp->right = CopyTree(root->right,tmp); //do the same with the right subtree

return tmp; //return a pointer to the newly created node.

}

The job of the class destructor is to delete all the nodes, and free up memory as usual. The clear()

function is called just as in the previous data structure implementations. However, this operation is only

performed if the object is a main tree. If the object is a subtree that points to the nodes of a larger tree, it

will be deleted when the main tree itself is deleted. Attempting to delete the data in the memory

associated with the subtree after it has already been deleted by the main tree will have unpredictable

results.

**template <class ItemType>
**

BinaryTree<ItemType>::~BinaryTree()

{

if(!subtree)

clear(); //delete all nodes

}

The insert() function creates a new node as a child of current. The first parameter is a value for the

new node, and the second parameter is an integer indicating what child the new node will become. A

value of 0 indicates that the new node will be a left child of current, whereas a value of 1 indicates the

new node will be a right child. If a node already exists in the location that programmer wishes to insert

it, that node adopts the value passed to insert(). If the tree does not have any nodes, the second

parameter is disregarded, and a main root is created.

**template <class ItemType>
**

void BinaryTree<ItemType>::insert(const ItemType &item,int pos) //insert as child

of current 0=left 1=right. if item already exists, replace it

{

assert(!IsFull());

//if the tree has no nodes, make a root node, disregard pos.

if(main_root == NULL)

{

main_root = new TreeNode<ItemType>;

main_root->data = item;

main_root->left = NULL;

main_root->right = NULL;

main_root->parent = NULL;

current = main_root;

return; //node created, exit the function

}

**if(pos == 0) //new node is a left child of current
**

{

if(current->left != NULL) //if child already exists, replace value

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 5 of 14

**(current->left)->data = item;
**

else

{

current->left = new TreeNode<ItemType>;

current->left->data = item;

current->left->left = NULL;

current->left->right = NULL;

current->left->parent = current;

}

}

else //new node is a right child of current

{

if(current->right != NULL) //if child already exists, replace value

(current->right)->data = item;

else

{

current->right = new TreeNode<ItemType>;

current->right->data = item;

current->right->left = NULL;

current->right->right = NULL;

current->right->parent = current;

}

}

}

**The remove() function removes the subtree referenced to by root, as well as the root node itself.
**

Depending on whether it was a left or right child, the left or right pointer of the parent is set to NULL.

The function uses recursion to perform the necessary operation on all nodes of the subtree. We must

start with the nodes on the lowest level, and work our way up. If we were to delete the top level nodes

first, we would loose the link the lower levels.

**template <class ItemType>
**

void BinaryTree<ItemType>::remove(TreeNode<ItemType>* root)

{

if(root == NULL) //base case - if the root doesn't exist, do nothing

return;

remove(root->left); //perform the remove operation on the nodes left subtree

first

remove(root->right); //perform the remove operation on the nodes right subtree

first

if(root->parent == NULL) //if the main root is being deleted, main_root must be

set to NULL

main_root = NULL;

else

{

if(root->parent->left == root) //make sure the parent of the subtree's root

points to NULL, since the node no longer exists

root->parent->left = NULL;

else

root->parent->right = NULL;

}

current = root->parent; //set current to the parent of the subtree removed.

delete root;

}

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 6 of 14

The next function returns the value of current.

**template <class ItemType>
**

ItemType BinaryTree::value() const

{

return current->data;

}

The next five functions are used to navigate the tree. The programmer can visit a node's left child, right

child, or parent, as well as reset current to the main root. Finally, the programmer can set current to a

specific node by supplying a pointer to it. This is very helpful if the programmer would like to work

with subtrees within the main tree object. Note, the SetCurrent() function should be used with caution.

If a pointer is supplied to a node that is not within the tree, the results are unpredictable.

**template <class ItemType>
**

void BinaryTree<ItemType>::left()

{

current = current->left;

}

**template <class ItemType>
**

void BinaryTree<ItemType>::right()

{

current = current->right;

}

**template <class ItemType>
**

void BinaryTree<ItemType>::parent()

{

current = current->parent;

}

**template <class ItemType>
**

void BinaryTree<ItemType>::reset()

{

current = main_root;

}

**template <class ItemType>
**

void BinaryTree<ItemType>::SetCurrent(TreeNode<ItemType>* root)

{

current = root;

}

The four functions that follow return pointers to various nodes in the tree, depending on current. This

is a required parameter for a few of our other functions, such as remove() and the three display

functions. It is also used by one of our class constructors, which can make a new tree object from a

subtree. The only function that is required is pointer_current(), since the programmer can navigate

the tree to any node. The other three functions were also included for ease of use. It is often times

necessary to perform an operation on a node's children or parent without leaving the node. The functions

are also useful if a programmer would like to work on a subtree. An external TreeNode* pointer can be

created, set by one of the pointer returning functions, and then passed to the operation functions of the

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 7 of 14

class.

**template <class ItemType>
**

TreeNode<ItemType>* BinaryTree<ItemType>::pointer_left() const

{

return current->left;

}

**template <class ItemType>
**

TreeNode<ItemType>* BinaryTree<ItemType>::pointer_right() const

{

return current->right;

}

**template <class ItemType>
**

TreeNode<ItemType>* BinaryTree<ItemType>::pointer_parent() const

{

return current->parent;

}

**template <class ItemType>
**

TreeNode<ItemType>* BinaryTree<ItemType>::pointer_current() const

{

return current;

}

The next three functions are also not required, but were added for ease of use. They return the values of

a node's two children and parent without having to leave the node.

**template <class ItemType>
**

ItemType BinaryTree<ItemType>::peek_left() const

{

assert(current->left != NULL);

return current->left->data;

}

**template <class ItemType>
**

ItemType BinaryTree<ItemType>::peek_right() const

{

assert(current->right != NULL);

return current->right->data;

}

**template <class ItemType>
**

ItemType BinaryTree<ItemType>::peek_parent() const

{

assert(current->parent != NULL);

return current->parent->data;

}

The display functions as explained above are next. Note, these functions will work only if ItemType is

supported by the << operator. For instance, any simple built in C/C++ type (such as int, float, char,

etc.) will work without any modification. template <class ItemType>

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 8 of 14

**void BinaryTree<ItemType>::DisplayInorder(TreeNode<ItemType>* root) const
**

{

if (root == NULL)

return;

**DisplayInorder(root->left);
**

cout << root->data;

DisplayInorder(root->right);

}

**template <class ItemType>
**

void BinaryTree<ItemType>::DisplayPreorder(TreeNode<ItemType>* root) const

{

if (root == NULL)

return;

**cout << root->data;
**

DisplayInorder(root->left);

DisplayInorder(root->right);

}

**template <class ItemType>
**

void BinaryTree<ItemType>::DisplayPostorder(TreeNode<ItemType>* root) const

{

if (root == NULL)

return;

**DisplayInorder(root->left);
**

DisplayInorder(root->right);

cout << root->data;

}

The clear() function deletes all nodes in the list. This is very easy to do, since we can take advantage

of the remove() function, which we has already defined. The remove() functions deletes all nodes of a

subtree, as well as the root node. Therefore, we can pass the main root to remove() in order to delete all

nodes in the tree.

**template <class ItemType>
**

void BinaryTree<ItemType>::clear()

{

remove(main_root); //use the remove function on the main root

main_root = NULL; //since there are no more items, set main_root to NULL

current = NULL;

}

**The IsEmpty() function works by evaluating main_root. If there aren't any nodes in the tree,
**

main_root points to NULL.

**template <class ItemType>
**

bool BinaryTree<ItemType>::IsEmpty() const

{

return (main_root == NULL);

}

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 9 of 14

Finally, other than the data types, the implementation of the IsFull() function does not change from

previous classes.

**template <class ItemType<
**

bool BinaryTree<ItemType>::IsFull() const

{

TreeNode<ItemType> *tmp = new TreeNode<ItemType>;

if(tmp == NULL)

return true;

else

{

delete tmp;

return false;

}

}

Now let's take a look at two additional functions, which are not part of the tree class. Often times it is

necessary to know how many nodes are in the list, or how many of them are leafs. One example of when

a leaf count is required is in a binary expression tree. Binary expression trees store mathematical

expression, for instance, 5*x+7=22. Each character of the expression is represented by one node. They

are stored in such a way that the expression can then be displayed using an in-order traversal. Also, pre-

order and post-order traversals will display the mathematical expression using prefix and postfix

notations. This means an operator stored in a node perform an operation on its two children. In such a

setup, all operators are internal nodes, whereas variables and constants are leafs. The code for the

NodeCount() and LeafCount() functions is displayed below. Both are very short since recursion is used.

**template <class ItemType>
**

int LeafCount(TreeNode<ItemType>* root)

{

if(root == NULL) //base case - if the node doesn't exist, return 0 (don't count

it)

return 0;

if((root->left == NULL) && (root->right == NULL)) //if the node has no children

return 1 (it is a leaf)

return 1;

return LeafCount(root->left) + LeafCount(root->right); //add the leaf nodes in

the left and right subtrees

}

**template <class ItemType≶
**

int NodeCount(TreeNode<ItemType>* root)

{

if(root == NULL) //base case - if the return 0 if node doesn't exist (don't

count it)

return 0;

else

return 1 + NodeCount(root->left) + NodeCount(root->right); //return 1 for the

current node, and add the amount of nodes in the left and right subtree

}

Binary Search Trees

Another type of special binary tree is the binary search tree (BST). BSTs must conform to a property

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 10 of 14

that states all the left children of a node have a lesser value than the node, and all the right children

have a value greater than the node. In order to make our binary tree class a BST, we need only modify

the insert() function, since nodes can no longer be placed anywhere in the tree by the programmer.

Otherwise, a BST acts in the same fashion as a standard binary tree.

The new insert() function accepts one parameter, the item to be inserted. If the tree is empty, then the

main root is added in the same fashion as it was with a standard binary tree, and the function exits. If the

tree is not empty, the function proceeds with a new algorithm.

**The parent of the new node is found by running the insert_find() function, a new private member
**

function that must be added to the BST class. The insert_find() function accepts two parameters - the

root of the tree and the item value. The root is needed as a parameter because insert_find() uses

recursion to traverse the tree. The function works by comparing the value of item to each node. If it is

less than the node's value, and the node has a left child, the function proceeds to that child and performs

the same operation. If it is greater (or equal to) than the node's value, and a right child exists, then the

function proceeds to the right child. If item is less than the node and a left child does not exist, or it is

more than the node and a right child does not exist, that is where the new node belongs.

The insert() function receives a pointer to the new parent, however, we must check again if the new

node is to be the left or right child. This is because there is no efficient way a recursive version of

insert_find() can return this information. We would have to add another parameter, or write a non-

recursive version of insert_find(). Both methods are far more space and time consuming than simply

performing another check.

A new node is then created using the same method as in the original version of insert().

**template <class ItemType>
**

void BST<ItemType>::insert(const ItemType &item)

{

//if the tree has no nodes, make a root node

if(main_root == NULL)

{

main_root = new TreeNode<ItemType>;

main_root->data = item;

main_root->left = NULL;

main_root->right = NULL;

main_root->parent = NULL;

current = main_root;

return;

}

**TreeNode<ItemType>* new_parent = insert_find(main_root,item); //find the new
**

node's parent

**if (item < new_parent->data) //check whether the new node is a left or right
**

child and create it

{

new_parent->left = new TreeNode<ItemType>;

new_parent->left->data = item;

new_parent->left->left = NULL;

new_parent->left->right = NULL;

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 11 of 14

**new_parent->left->parent = new_parent;
**

}

else

{

new_parent->right = new TreeNode<ItemType>;

new_parent->right->data = item;

new_parent->right->left = NULL;

new_parent->right->right = NULL;

new_parent->right->parent = new_parent;

}

}

**template <class ItemType>
**

TreeNode<ItemType>* BST<ItemType>::insert_find(TreeNode<ItemType>*

delete_node,ItemType item)

{

if((root->left != NULL) && (item < root->data))

return insert_find(root->left,item);

**if((root->right != NULL) && (item >= root->data))
**

return insert_find(root->right,item);

return root; }

**Since the programmer is no longer in control of the location of each node, we can add a function that
**

removes one node at a time. The reason we did not implement such a function for the standard binary

tree class is that we do not know how the program requires the structure to handle removing a node. If

the node to be deleted is a leaf, the solution is simple. We set its parent's pointer to NULL. If it has one

child, then the parent is set to point to that child. However, what happens if the node has two children ?

How should we insert those children back into the tree once the node is deleted ? The solution can vary,

depending on the programming task. Since a binary search tree follows a specific property, we can

libraryelop an algorithm that maintains the binary search tree property when rearranging the node's

children.

The code for the remove_node() function may look difficult at first, however when broken down into

each possible situation, it is very simple to understand. The first case that must be considered is if we

wish to remove the main root, and it has only one child. In this situation, that child becomes the new

main root.

If the node to be deleted has no children, node's parent is set to point to NULL, and node is then deleted.

Also as mentioned before, if node has one child, the parent of node is set to point to this child, and node

is then deleted.

If delete_node has two children, a little bit more work must be done. The question arises as to how to

attach delete_node's children to the tree, while preserving the binary search tree property. One possible

solution would be to attach one of the children to delete_node's parent, and reinsert each node from the

second child subtree one-by-one. However, this method is very inefficient, especially if the node to be

deleted has a very large subtree.

The ideal approach is to find another node in the tree, which can replace delete_node, and still

maintain the binary search tree property. We can then replace the value of delete_node, and remove the

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 12 of 14

node who's value we replaced it with instead. The possible nodes that would fit such a criteria are the

largest node in the left subtree, and the smallest node in the right subtree. The largest node in the left

subtree is still smaller than any node of the right subtree, and the smallest node in the right subtree is

larger than any node in the left subtree, therefore making both possible values that can replace root. If a

right subtree exists, then it is used, since it may contain a value that is equal to delete_node (in which

case that value will be used).

The largest node in the left subtree can be found by moving to the left one time (starting from

delete_node), and then moving to the right as much as possible. The smallest node in the right subtree

can be found by moving once to the right, and then to the left as much as possible. This means that

either node will have at most one child (the largest node in the left subtree can only have a left child, and

the smallest node in the right subtree can only have a right child). It can therefore be removed using the

above method, by attaching that child to the node's parent.

**The replace_find() private member function returns the node that is used to replace delete_node.
**

The first parameter of the function is a pointer to the first possible node (if we are searching the left

subtree, this value is root->left, whereas it is root->right if we are searching the right subtree), and

the second parameter is what direction to search in. Zero means the function will locate the largest value

in the left subtree, meaning it will travel to the right as much as possible. A value of one means the

function will locate the smallest value in the right subtree, therefore travelling to the left as much as

possible. Once the node is found, delete_node is set to its value, and the node is deleted.

**template <class ItemType>
**

void BST<ItemType>::remove_node(TreeNode<ItemType>* root)

{

if((root == main_root) && ((root->left == NULL) || (root->right == NULL)))

{

//set the main root's only child as the new root. if it has no children,

main_root becomes NULL as the tree is empty.

if(root->left == NULL)

main_root = root->right;

else

main_root = root->left;

main_root->parent = NULL; //set the new main root's parent to NULL

if(current == root) //if current is at the original main root, set it to the

new root, since the original will be deleted

current = main_root;

delete root;

return;

}

**if(current == root) //if current is at the node to be deleted, set it to the
**

node's parent

current = root->parent;

**if((root->left == NULL) && (root->right == NULL)) //if the root has no children
**

{

//have the parent point to NULL in place of it

if(root->parent->left == root) //if it a left child

root->parent->left = NULL;

else //it is a right child

root->parent->right = NULL;

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 13 of 14

delete root;

return;

}

**//if the root has one child, have the parent point to it in place of root
**

if((root->left == NULL) && (root->right != NULL))

{

if(root->parent->left == root)

root->parent->left = root->right;

else

root->parent->right = root->right;

delete root;

return;

}

if((root->left != NULL) && (root->right == NULL))

{

if(root->parent->left == root)

root->parent->left = root->left;

else

root->parent->right = root->left;

delete root;

return;

}

**//if the node has two children
**

TreeNode<ItemType> *tmp;

if(root->right != NULL) //if the root has a right subtree, search it for the

smallest value

tmp = replace_find(root->right,1);

else //search the left subtree for the largest value

tmp = replace_find(root->left,0);

root->data = tmp->data;

//if tmp has a child, have tmp's parent point to it. Otherwise, have the parent

point to NULL in place of tmp.

if(tmp->parent->left == tmp) //if tmp is a left child

{

if(root->right != NULL) //if it has a right child, have the parent point to

it

tmp->parent->left = tmp->right;

else //point to the left child. This value is NULL if there is no left child

tmp->parent->left = tmp->left;

}

else //if tmp is a right child

{

if(root->right != NULL) //if it has a right child, have the parent point to

it

tmp->parent->right = tmp->right;

else //point to the left child. This value is NULL if there is no left child

tmp->parent->right = tmp->left;

}

delete tmp;

}

**template <class ItemType>
**

TreeNode<ItemType>* BST<ItemType>::replace_find(TreeNode<ItemType>* root,int

direction)

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 14 of 14

{

if(direction = 0) //searching left subtree for largest value. go right as much

as possible. Return last node.

{

if(root->right == NULL)

return root;

return replace_find(root->right,0);

}

else //searching right subtree for smallest value. go left as much as possible.

Return last node.

{

if(root->left == NULL)

return root;

return replace_find(root->left,1);

}

}

© 2000 ThinkQuest Team C005618

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\binarytree.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 1 of 4

Heaps

**Another type of special binary tree is called a heap. In order to understand what a heap is, we must first
**

define a complete and full binary tree. In a full binary tree, all nodes are either a parent with two

children, or a leaf. In a complete binary tree, all the levels except the last must be completely filled. In

the last level, all nodes must be filled in from the left side, without spacing between them, however, it

does not have to be filled to the end.

A heap is a complete binary tree, which is partially ordered with either the max-heap or min-heap

properties. That is, if a heap is a max-heap, then the children of every node have a value less than that

node. In a min-heap, the children of every node are greater than the node itself. With such a setup, the

main root always has either the highest or lowest value in the tree. For demonstration purposes, we will

show how to implement a max-heap, as it also an important part of the HeapSort algorithm, which will

be covered later. [It is easy to change to code to work as a min-heap by changing the relational operators

between node values]. A max-heap usually used for maintaining priority queues. Priority queues store

values and release the object with the highest "priority" (or value) when needed. For instance, a value is

associated with a particular task in a program, put into such a structure, and then executed based on its

position.

**Since a heap must conform to the complete tree property, simple formulae can be libraryeloped to find
**

the logical position of a node's children and parent given the position of the node itself. It is therefore

very easy and efficient to implement a heap using arrays, and is done so most of the time, even if

dynamic memory allocation is available.

**In an array implementation, we must allocate a certain amount of memory space that may be used for
**

the heap. The space may not be used up, and is therefore a waste of memory. Other times, we may need

to add more nodes to the heap than the allocated memory allows for. However, we usually allocate more

space than we think may be required in order to insure the heap is usable. If we have a tree of very large

structures, this space can be significant. However, this is the price we always pay for greater efficiency.

It should noted though, that we no longer have three pointers for every tree node (left, right, parent),

which took up a lot of space in the dynamic memory implementation. The logical position of a node in a

heap corresponds to the index of the node's array position, thereby making it very easy to access any

node. A generic implementation is shown below.

**const int MAX_SIZE = 100; //the maximum amount of elements our heap should have.
**

This may be changed to any number so long as memory permits, depending on how the

heap will be used.

**template <class ItemType>
**

class Heap

{

public:

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\heaps.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 2 of 4

Heap();

int left(int) const;

int right(int) const;

int parent(int) const;

void insert(const ItemType&);

ItemType remove_max();

bool IsEmpty() const;

bool IsFull() const;

int count() const;

ItemType value(int) const;

private:

ItemType array[MAX_SIZE];

int elements; //how many elements are in the heap

void ReHeap(int);

};

**//default constructor - initialize private variables
**

template <class ItemType>

Heap<ItemType>::Heap()

{

elements = 0;

}

**The left(), right(), and parent() functions return the index positions of a node's children and
**

parent. Since the index position of each element correspond to their logical position in the heap, the

functions use simple formulae that are derived by observing the heap structure.

**template <class ItemType>
**

int Heap<ItemType>::left(int root) const

{

assert(root return (root * 2) + 1;

}

**template <class ItemType>
**

int Heap<ItemType>::right(int root) const

{

assert(root < (elements-1)/2); //does a right child exist?

return (root * 2) + 2;

}

**template <class ItemType>
**

int Heap<ItemType>::parent(int child) const

{

assert(child != 0); //main root has no parent

return (child - 1) / 2;

}

The insert() function accepts the new item value as its parameter. It works by inserting the new item

at the end of the heap, and swapping positions with the parent, if the parent has a smaller value than the

item. The new item continues to travel up the heap, swapping its position with its new parents until the

item's parent is larger than it.

**template <class ItemType>
**

void Heap<ItemType>::insert(const ItemType &item)

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\heaps.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 3 of 4

{

assert(!IsFull());

array[elements] = item; //elements represents the array position after the last,

since indexing starts with 0

int new_pos = elements; //index of the new item

elements++; //update the amount of elements in heap

while((new_pos != 0) && (array[new_pos] > array[parent(new_pos)])) //loop while

the item has not become the main root, and while its value is less than its parent

{

swap(array[new_pos],array[parent(new_pos)]); //swap the value of item with

its lesser parent

new_pos = parent(new_pos); //update the item's positions

}

}

The remove_max() removes the item with the highest priority and returns its value. The item is swapped

with the last item, and elements is updated to one less.

Notice the item is not physically deleted, it will remain as part of the array. It will not be part of the heap

since elements is updated, and the heap goes only as far as (elements - 1).

The new root may not have the largest priority, therefore the ReHeap() function is then used to insert the

new root into its proper position, thus conserving the heap property.

**template <class ItemType>
**

ItemType Heap<ItemType>::remove_max()

{

assert(!IsEmpty());

elements--; //update the amount of elements in heap

if(elements != 0) //if we didn't delete the root

{

swap(array[0],array[elements]);

ReHeap(0);

}

return array[elements];

}

The ReHeap() function checks of either of root's children are bigger than it, in which case the bigger

child is swapped with root. The process is then continued using recursion, on root's new children. The

function stops when root is bigger than both of its children.

**template <class ItemType>
**

void Heap<ItemType>::ReHeap(int root)

{

int child = left(root);

if((array[child] < array[child+1]) && (child < (elements-1))) //if a right child

exists, and it's bigger than the left child, it will be used

child++;

if(array[root] >= array[child]) //if root is bigger than its largest child,

stop.

return;

swap(array[root],array[child]); //swap root and its biggest child

ReHeap(child); //continue the process on root's new children

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\heaps.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 4 of 4

}

The rest of our member functions are east to implement.

**template <class ItemType>
**

int Heap<ItemType>::count() const

{

return elements;

}

**template <class ItemType>
**

ItemType Heap<ItemType>::value(int pos) const

{

assert(pos < elements); //is pos a valid index in the heap

return array[pos];

}

**template <class ItemType<
**

bool Heap<ItemType>::IsEmpty() const

{

return (elements == 0);

}

**template <class ItemType>
**

bool Heap<ItemType>::IsFull() const

{

return (elements == MAX_SIZE);

}

© 2000 ThinkQuest Team C005618

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\heaps.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 1 of 6

Lists

**A list is one of the most basic data structures in programming. It is a logically sequential order of
**

elements, any of which can be accessed without restriction. Any element in the list can be removed, and

its value be read or modified. Also, a new element may be inserted into any location in the list structure.

Each element points to the next one in the list, and the last does not reference any other item.

**Physically, the elements of a list can be stored at various locations in memory, and the addresses of each
**

element are not correlated in any way. The list is linked since each element points to the location of the

next item.

The dynamic representation of a list is called a linked list. Each element in the list is called a node, and

contains two values. The first, is the data value that is to be stored. For instance, in a list of names, this

would be a value such as John. The second value in a node is a pointer to the next node in the list. A

common representation of a list node is as follows:

**template <class ItemType>
**

struct ListNode

{

ItemType data;

ListNode<ItemType> *next;

};

Linked lists can be implemented in many ways, depending on how the programmer will use lists in their

program. We will show how to implement a generic class, which can be adapted and modified to use in

most situations. The member functions implemented will be those necessary to add, modify, or delete

nodes in a linked list. The class will be constructed in such a way that if the implementation were to be

changed, the class definition would remain the same, and therefore any program that uses the class will

not need to be altered. This is usually good practice in the design of any class. A definition of the linked

list class is displayed below.

**template <class ItemType>
**

class List

{

public:

List(); //constructor - initialize private variables

~List(); //destructor - free used memory

void insert(const ItemType); //insert new node at current location

void delete(); //remove the current node

void next(); //set current to the next node in the list

void prev(); //set current to the previous node in the list

void reset(); //set current to the first node in the list

void clear(); //remove all nodes in the list

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\links.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 2 of 6

**int length() const; //return the amount of nodes in the list
**

bool IsEmpty() const; //returns true if the list doesn't have any nodes

bool IsFull() const; //returns true if there is no system memory for additional

nodes

ItemType value() const; //returns the value of the current node

private:

ListNode<ItemType> *list; //points to the list header

ListNode<ItemType> *prevcurrent;

int len;

}

len will contain the total number of nodes in the list, and is self explanatory. prevcurrent and list will be

implemented in a special way, and require further explanation. At first, it would appear logical to have a

pointer directly to the node being referenced. However, this would make the implementation of the prev

(), as well as the insert() and delete() functions to be time consuming. These three functions

require access to the node that precedes the current node being referenced. Therefore, if there were a

pointer directly to the required node, the only solution would be to search through the entire list (in the

worst case scenario) for the preceding node. A temporary pointer would be created that points to the

list's first node, and be used to traverse the list. A condition would then be implemented that triggers

when temp->next->data equals the current node's value.

A more efficient approach is to have prevcurrent store the pointer to the node that precedes the one

being referenced. Therefore, the time needed to otherwise find this node is not wasted.

This approach raises a new concern - if the list has only one item, then a special case will need to be

introduced every place prevcurrent is used, since there is no preceding node to point to. The most

efficient way of solving this problem is by using a header node. A header node is a "dummy" node that

acts as the first node of the list, but is not logically in the list. It is used only in the implementation of the

linked list class, and the programmer who uses the class does not need to know about header nodes. It is

created, manipulated, and deleted by the member functions. list will point to header node. Now let's

look at the implementation of the linked list class.

The class constructor will create the header node, and set prevcurrent to point to its location. It will

also set length to a value of zero.

**template <class ItemType>
**

List<ItemType>::List()

{

list = new ListNode; //create a new ListNode in memory

list->next = NULL; //the header is the only node in the list

revcurrent = list; //set current to the header, since there are no nodes

len = 0;

}

The destructor will delete all nodes of the list, freeing up the memory they occupied. Since the clear()

function does this operation, it can be called in the destructor. In addition, the header node will also be

deleted in the destructor, as the clear() function only removes actual list nodes. Two local variables of

type ListNode<itemType> are used for the operation. traverse is set to the first node in the list, and

used to visit every node. tmp will be used to point to the node to be deleted. Since we cannot move on to

the next node if the current node is deleted (the next pointer will no longer exist), traverse will be set

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\links.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 3 of 6

to the next node first, after which tmp will be deleted.

**template <class ItemType>
**

void List<ItemType>::clear()

{

ListNode<ItemType> *tmp; //point to the node to be deleted

ListNode<ItemType> *traverse = list->next; //used to visit each node in the

list. The header node is not deleted, so we start with the first actual node.

while(traverse != NULL) //while the list is not empty

{

tmp = traverse; //store the current node.

traverse = traverse->next; //visit the next node

delete tmp; //free the memory taken up by the current node

}

prevcurrent = list; //set current to the header node

len = 0;

}

**template <class ItemType<
**

List<ItemType>::~List()

{

clear(); //delete all list nodes

delete list; //delete the header "dummy" node

}

The insert() function will create a new node preceding the one being referenced, and move the

reference to it. Remember, current->next is the node currently being referenced, since prevcurrent

points to the preceding node.

**template <class ItemType>
**

void List<ItemType>::insert(const ItemType item)

{

assert(!IsFull()); //abort if there is no memory to create a new node

ListNode<ItemType> *NewNode = new ListNode<ItemType>; //create a new node in

memory

NewNode->data = item; //set the node's value

NewNode->next = prevcurrent->next; //referenced node will follow new node in

order

prevcurrent->next = NewNode; //The node that preceded the old node now precedes

the new one. The new node is now referenced.

len++; //increment length

}

The delete() function sets the previous node to point to the node following the one being referenced,

thus removing it from the logical list. It is then deleted from memory.

**template <class ItemType>
**

void List<ItemType>::delete()

{

if(len != 0) //don't delete the header node

{

prevcurrent->next = prevcurrent->next->next; //logically remove it from the

list

delete (prevcurrent->next); //free up memory

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\links.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 4 of 6

**len--; //decrement length
**

}

}

The next() function is very short, and self explanatory.

**template <class ItemType>
**

void List<ItemType>::next()

{

prevcurrent = prevcurrent->next;

}

The prev() function visits each node until the one that points to prevcurrent is found, and then sets

prevcurrent to this node. The node being referenced now becomes the node prevcurrent pointed to

before the function was executed.

**template <class ItemType>
**

void List<ItemType>::prev()

{

if (len > 1) //run only if there is an element behind the current

{

ListNode *tmp = list;

while(tmp->next != prevcurrent)

tmp = tmp->next;

revcurrent = tmp;

}

}

The reset() function sets the item in reference to the first by setting prevcurrent to the header node.

**template <class ItemType>
**

void List<ItemType>::reset()

{

prevcurrent = list;

}

Next, the length() function simply returns the value of the private length member len. A function

would not be necessary to perform this operation if we were to make the length a public data member, in

which case the programmer can read it directly. However, a member function is used to retrieve this

value for two reasons. First, if the length data member were public, the programmer could also change

the length of the list in the program without modifying the number of nodes in the list. Second, if we

were to change the implementation of the class, and the length was no longer controlled by a single

variable, the programmer would not have to modify his program in order for it to work.

**template <class ItemType>
**

int List<ItemType>::length() const

{

return len;

}

The IsEmpty() function works by checking if the length of the list is zero.

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\links.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 5 of 6

**template <class ItemType>
**

bool List<ItemType>::IsEmpty() const

{

return (len == 0);

}

**The IsFull() function checks to see if there is enough system memory to create a new node. This is
**

done by attempting to create a new node, and checking if the resulting pointer is NULL. If the new

operation was unsuccessful in assigning the appropriate memory space, NULL is the return value. If the

value is not NULL, the memory space is freed, and false is returned. Otherwise, the function returns

true, meaning no more items can be added to the list.

template <class ItemType>

**bool List<ItemType>::IsFull() const
**

{

ListNode<ItemType> *tmp = new ListNode<ItemType>;

if(tmp == NULL)

return true;

else

{

delete tmp;

return false;

}

}

Finally, the value() function returns the value of the node that is currently being referenced.

**template <class ItemType>
**

ItemType List<ItemType>::value() const

{

return prevcurrent->next->data;

}

Other Types of Lists

Like header nodes, lists may also have a trailer node, which is a dummy node at the end of the list. They

are maintained in a similar fashion to that of header nodes, that is, they are not part of the logical list

structure. Header nodes are used to eliminate any special cases that may arise when inserting a new node

at the end of the list.

Other type of standard lists exist as well. For instance, in a circular list, the last node points to the first

node instead of a NULL value. This would require minor changes in the class implementation. Nodes

inserted at the end must now point to the first node, and the same must be done when searching for the

last node. We must look for a node which points to the first instead of NULL.

**Finally, a doubly linked list maintains a prev pointer in ListNode, which points to the previous node.
**

This makes functions such as insert() and remove() as well as the general implementation very

simple. We no longer need to maintain a pointer to the node preceding the one being referenced. Since

the previous node is required by both functions, we need only check prev for it. Other modifications

needed in order to create a doubly linked list include updating each new node's prev pointer when it is

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\links.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 6 of 6

created. The front pointer has a prev value of NULL and requires a special condition, unless a header

node or a circular doubly linked list is used.

© 2000 ThinkQuest Team C005618

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\links.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 1 of 4

Queues

**A queue is another special type of list structure. Elements can only be inserted to the back of a queue,
**

and only the front element can be accessed and modified. The structure of a queue is the same as that of

a line of people. A person who wishes to stand in line must go to the back, and the person in front of the

line is served. Thus, a queue is a FIFO structure, "First In, First Out". A generic queue is very simple to,

a class definition for a linked queue is shown below.

**template <class ItemType>
**

struct QueNode

{

ItemType data;

QueNode<ItemType> *next;

};

**template <class ItemType>
**

class Queue

{

public:

Queue(); //class constructor - initialize variables

~Queue(); //class destructor - return memory used by queue elements

void enqueue(const ItemType); //add an item to the back of the queue

ItemType dequeue(); //remove the first item from the queue and return its value

ItemType first() const; //return the value of the first item in the queue

without modification to the structure

bool IsEmpty() const; //returns true if there are no elements in the queue

bool IsFull() const; //returns true if there is no system memory for a new queue

node

int length() const; //returns the amount of elements in the queue

private:

QueNode<ItemType> *front;

QueNode<ItemType> *back;

int len;

};

The front pointer will reference the first node in the queue, and the back pointer will reference the last

node in the queue. It is possible to maintain only a front pointer. The last node in the list points to a

NULL value, and can easily be found. However, such a design would be inefficient since finding the last

node every time its location is needed is very time consuming. Therefore, we maintain a reference to it

in our class implementation.

The class constructor initializes the private data members.

template <class ItemType>

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\queue.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 2 of 4

Queue<ItemType>::Queue()

{

front = NULL;

back = NULL;

len = 0;

}

The destructor deletes all nodes, freeing up the memory they used. The clear() function is called to do

this operation.

**template <class ItemType>
**

Queue<ItemType>::~Queue()

{

clear();

}

The enqueue() function adds a new item to the back of the queue. The algorithm differs slightly,

depending on whether the queue is empty or not. If the queue is not empty, the last node is set to point to

the newly created node, and the back pointer is set to reference the new node. The value of the new node

is item, and its next pointer has a value of NULL.

If the queue is empty, a similar procedure is used. However, the front pointer is also set to reference the

newly created node. Since there is only one node in the queue, the front and back are one in the same.

**template <class ItemType>
**

void Queue<ItemType>::enqueue(const ItemType item)

{

assert(!IsFull()); //abort if there is no more memory for a new node

if(len != 0) //if the queue is not empty

{

back->next = new QueNode<ItemType>; //create a new node

back = back->next; //set the new node as the back node

back->data = item; back->next = NULL; }

else

{

back = new QueNode<ItemType>; //create a new node

back->data = item; back->next = NULL; front = back; //set front

to reference the new node. Since there it is the only node in the queue, it is

considered to be both the back and front.

}

len++; //increment the amount of elements in the queue

}

The dequeue() function removes the node at the front of the queue and returns its value. The value of

the front node is stored in item. A temporary local pointer is then created to reference the front node,

and the front pointer is set to the next element in the queue. The front node is deleted using tmp as a

reference. The function then checks if the queue is empty by evaluating front. If it has a value of NULL,

the queue is empty, and the back pointer must also be set to NULL since it maintains the address of the

now deleted node.

**template <class ItemType>
**

ItemType Queue<ItemType>::Dequeue()

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\queue.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 3 of 4

{

assert(!IsEmpty()); //abort if the queue is empty, no node to dequeue

ItemType item = front->data; //store the value of the first node, to be returned

at the end

QueNode<ItemType> *tmp = front; //temporary pointer to the first node.

front = front->next; //set the second node in the queue as the new front

delete tmp; //delete the original first node

if(front == NULL) //if the queue is empty, update the back pointer

back = NULL;

len--; //decrement the amount of nodes in the queue

return item; //return the value of the original first element

}

The first() function returns the value of the front node without modifying the queue.

**template <class ItemType>
**

ItemType Queue<ItemType>::first() const

{

assert(!IsEmpty()); //abort if the queue is empty

return front->data;

}

The IsEmpty() function checks to see if there are any nodes in the queue by evaluating the front

pointer. If the queue is empty, front has a value of NULL.

**template <class ItemType>
**

bool Queue<ItemType>::IsEmpty() const

{

return (front == NULL);

}

The IsFull() function works exactly the same way as it did with other data structures. A node is

"created" using the new command, which is then checked. If the new command had failed to set aside

the necessary memory, its value is NULL, in which case the function returns true. If the new node is

created successfully, it is deleted and the function returns false.

**template <class ItemType>
**

bool Queue<ItemType>::IsFull() const

{

QueNode<ItemType> *tmp = new QueNode<ItemType>;

if(tmp == NULL)

return true;

else

{

delete tmp;

return false;

}

}

The length() function returns the value of len, which maintains the amount of nodes in the queue.

Again, a function is used to retrieve this value instead of making it a public data member to avoid error

and make our class abstract.

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\queue.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 4 of 4

**template <class ItemType>
**

int Queue<ItemType>::length() const

{

return len;

}

© 2000 ThinkQuest Team C005618

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\queue.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 1 of 2

Searching

**Searching refers to finding the location of an element with a specific value within a collection of
**

elements. The simplest search algorithm is the sequential search, which evaluates every element in the

array (in order) and compares its value with the one being looked for. The function below demonstrates

a sequential search. The function accepts a pointer to an array of integers, the amount of integer in the

array, and a number to be looked for in the array. A boolean value is returned specifying whether that

number exists in the array.

**bool InArray(int *array, int size, int num)
**

{

for(int j = 0; j < size; j++)

if(array[j] == num)

return true;

return false;

}

The algorithm is very simple to implement, but also very inefficient. In the average and worst case, it

takes O(N) time to find if the item exists. In very large arrays, this is a very slow operation.

A more efficient search can be performed if the array is already sorted. Note, sorting an array first, and

then using one of the more efficient search algorithms may be inefficient in the long run. It is

recommended that such algorithms be used only if the array is sorted to begin with. The binary search

algorithm is one of the simplest searching algorithms on a sorted array. For demonstration purposes, we

will assume the array is sorted in ascending order. However, the algorithm can easily be modified to

work with descending list by changing the relational operators. The binary search algorithm compares

the number being looked for to the value of the middle element in the array. Depending on whether it is

less or greater, the same process is then done on the left or right part of the array respectively. One

possible implementation of a binary search is shown below.

bool InArray(int *array, int left, int right, int num) //left and right are the left and right index values of

the array. These are both necessary as parameters since the function is recursive.

{

if(num == ((left+right)/2)) //if a match is found, return true

return true;

if(left == right) //all possibilities have been searched. num is not in the array

return false;

if(num < ((left+right)/2))

return InArray(array,left,((left+right)/2) - 1,num); //perform the same operation. New right position

is the element before the middle

if(num > ((left+right)/2))

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\searching.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 2 of 2

return InArray(array,((left+right)/2) + 1,right,num); //perform the same operation. New left position is

the element directly after the middle.

}

**Hasing is a somewhat different approach to searching, as it attempts to make searching O(1) efficiency.
**

A hash function is applied, which uses some type of algorithm or formula to determine what index of an

array (also called the hash table) the object should be in. The algorithm or formula depends on the type

of data in each situation.

**Most times, at least several collisions occur in the hash table. A collision is when an index is returned by
**

the hash function that already has a value. This could mean it is either a duplicate, or the hash function is

not unique, which is often times the case. There are two approaches to resolving a collision.

The first is known as open hashing. In this method, collision values are stored "outside" of the array. An

example of open hashing is having each array index point to another array, or linked list. Thus, all

values that hash to that location are stored in the list. The items in the list can be sorted by their value,

access frequency, or the order in which they were put into the table.

**Closed hashing is another collision resolution technique. In this approach, the collision values are stored
**

at a different location in the hash table. The hash function takes care of this, as the resolution is

dependent on data and programming task. Whatever algorithm the hash function uses to resolve a

collision must then be used when searching to find the item required.

© 2000 ThinkQuest Team C005618

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\searching.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 1 of 8

Sorting

**Finding better algorithms to sort a given set of data is an ongoing problem in the field of computer
**

science. Sorting is placing a given set of data in a particular order. Simple sorts place data in ascending

or descending order. For discussion purposes, we will look at sorting data in ascending order. However,

you may modify the code to sort the data in descending order by reversing the relational operators (i.e.

change 'nums[j] < nums[j-1]' to 'nums[j] > nums[j-1]').

In this lesson we will analyze sorts of different efficiency, and discuss when and where they can be used.

In order to simplify the explanation of certain algorithms, we will assume a swap() function exists that

switches the values of two variables. An example of such a function for int variables is displayed

below.

**void swap(int &item1,int &item2) //reference parameters, point directly to the
**

storage location of the variables passed. Local copies are not made, and these

values are saved after the function life span ends. See 'Functions' in the

preliminary lesson for further information.

{

int tmp;

tmp = item1;

item1 = item2;

item2 = tmp;

}

We will first analyze sorts that are O(N^2). These sorts are very easy to understand, however they are

very slow when there are a lot of elements to be sorted.

The first sort we will look it is called the insertion sort. The algorithm processes each element in turn,

and compares it to the elements before it. The first element has no elements before it for comparison, so

it is left alone. In the next iteration, the second element is evaluated. It is compared to the element

directly before it, which is the first element in the structure. If the second element has a value less than

the first, their positions are switched. If they second element is more than the first, then they are left as

they are, and the third element is processed. The third element is then compared to the second element in

the new list ('new' list here since the first two items may have been swapped). If it is less than the

second, then they are swapped, and it is then compared to the first element. If it is more than the second

element, it is left in place and the process continues to the next element.

In short, each element is moved to the front of the list by switching positions with the previous elements

as long as it is smaller than the elements before it.

The algorithm is programmed using two nested for loops. The first loop creates n-1 iterations, where n

is the number of elements in the list. Since element[0] does not have any elements before it to compare

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\sorting.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 2 of 8

to, we start with the second element. The nested loop statement starts at the element that is being

processed by the first loop, and works backwards, comparing the element to the one before it. If it is

smaller, a swap is made and the loop continues. If it is larger, the loop ends, and the next iteration begins

in the outer loop. The code for the insertion sort algorithm is shown below. A standard array of int

variable is used for simplicity. However, you can modify the code to work for any linear structure.

**void InsertionSort(int *nums,int n) //array called nums with n elements to be
**

sorted

{

for(int i=1; i<n; i++)

for(int j=i; (j>0) && (nums[j]<nums[j-1])); j--)

swap(j,j-1);

}

The next O(N^2) algorithm that we will analyze is the bubble sort. The bubble sort works from the

bottom-up (back to front), and evaluates each element to the one before it. If the element on the bottom

has a smaller value than the top, the two are swapped, if not - they remain in their original position. The

algorithm compares the next two elements from the bottom-up, no matter what the outcome of the

previous comparison was. In this fashion, the smallest value "bubbles up" to the top in each iteration. In

subsequent comparisons, the values that were bubbled up in previous iterations are no longer compared,

since they are in place.

The code for the bubble sort is shown below, using a standard array of int variables. Two nested for

loops are used. The first loop has n iterations, the number of elements. Each iteration, at least one

element is set into its proper sorted position. The inner for loop runs from the bottom-up, comparing

adjacent values, and stops at the group of values that have already been set in place, this position being

one more each iteration of the outer loop.

**void BubbleSort(int *nums, int n)
**

{

for (int i=0; i<n-1; i++)

for (int j=n-1; j>i; j--)

if(nums[j] < nums[j-1]

swap(j,j-1);

}

The selection sort will be the final O(N^2) sorting algorithm that we will look at. In a selection sort, the

entire list is searched to find the smallest value. That is, we compare every element in the structure and

find the smaller value, and then swap it with the first item. Then, every element but the first is searched

to find the smallest value out of that group, and it is then swapped with the item in the second position.

This continues until all items are in the correct order.

This technique is similar to what would be done if a person were sorting a list of items by hand. The list

is searched for the smallest value, which is then crossed out and written as the first item in a new list.

The computer algorithm is the same, however, in order to preserve memory and not have to make two

lists, we use a swap operation.

The selection sort uses two nested for loops, the outer having n-1 iterations. When there is only one

item left, it will appear in its correct position, last in the structure. The inner for loop searches the

unsorted portion of structure (from bottom-top) by assuming the first element in the unsorted section is

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\sorting.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 3 of 8

**the smallest, and then comparing it to each element in turn. If a smaller element is found, it is considered
**

to be the smallest, and compared to the rest of the elements. The code for selection sort is shown below.

**void SelectionSort(int *nums, int n)
**

{

int low; //holds the index of the smallest element in the unsorted portion

for (int i=0; i<n-1; i++)

{

low = i; //assume the first item in the unsorted section is the lowest,

unless a smaller value is found

for (int j=n-1; j>i; j--)

{

if (nums[j] < nums[low]) //if element has smaller value than low

low = j; //it then becomes the new low

}

swap(i,low); //switch the current position item with the smallest in the

unsorted portion

}

}

The algorithms that follow are O(N log N).

The next sorting algorithm that will be covered is the Shell sort, named after its creator D.L. Shell. It is

the first algorithm that we will look at that swaps non-adjacent elements, and takes a "divide and

conquer" approach. The list is divided into many sublists, which are sorted, and are then merged

together. The shell sort takes advantage of the insertion sort, which is very efficient in a best case

scenario (that is, the list being sorted is already 'near sorted').

The shell sort divides the list into n/2 sublists, each being n/2 apart. For instance, in a list of ten

elements, the first iteration would consist of five lists, two elements each. The first list would be list[0]

and list[5], the second would be list[1] and list[6], and so on. Each of these lists is then sorted using an

insertion sort. During the next iteration, we divide the list into bigger sublists, with the elements being

closer together. In the second iteration, there are n/4 lists, each element being n/4 apart. These lists are

then sorted using insertion sort, and so on. The process continues with twice the amount of lists each

iteration as in the one before. Each iteration, the list becomes closer to being sorted. The last sort is done

on the entire list, using a standard insertion sort. Since the list should be 'near sorted', the algorithm is

very efficient.

**Note, during some iterations, sublists will contain unequal amount of elements, since the amount of
**

sublists does not evenly divide into the total number of elements. Remember, in integer division, the

decimal in the answer is dropped, e.g. 5/2 = 2. Therefore, if we have seven elements, there are three lists

during the first iteration. One contains three elements, and the other two each contain two elements.

{6,3,1,5,2,4,9} -> {6,3,1,5,2,4,9}

In the example, list one starts at list[0] (6) and includes every item two apart. The next list starts at list[1]

(3) and also includes every item two apart from its position. Since there is no item that is two locations

after the '4', the list has only two items.

The code for shell sort is very simple and straightforward. A slightly modified version of the insertion

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\sorting.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 4 of 8

**sort is used however. Since the elements of the sublists to be sorted are not adjacent, an increment
**

parameter is added, which specifies how far apart the elements of the sublists are. The value '1' is then

replaced by the increment in the original insertion sort code, since it now compares values that are

increment apart.

**void InSortShell(int *nums,int n, int incr) //array called nums with n elements to
**

be sorted, incr apart

{

for(int i=incr; i<n; i+=incr)

for(int j=i; (j>=incr) && (nums[j] < nums[j-incr]); j-=incr)

swap(nums[j],nums[j-incr]);

}

**void ShellSort(int *nums, int n)
**

{

for(int i=n/2; i>2; i/=2) //each iteration there are twice as many sublists.

Divide the distance between each element by 2.

for(int j=0; j<i; j++) //sort each sublist

InSortShell(&nums[j],n-j,i); //the first element of each sublist begins at

j, and therefore the entire list is j items shorter (n-j). The elements of the

sublist are i apart.

InSortShell(nums,n,1); //do a standard insertion sort on the now nearly sorted

list.

}

**QuickSort is the quickest algorithm in the average case, however it has a very bad running time in a
**

worst case scenario (e.g. items completely out of order, in reverse of how they should appear sorted,

etc). The QuickSort takes a "divide and conquer" approach. A value called a pivot is first selected,

usually it is the value of the middle element. A "partition" of the array is then preformed. Any elements

that are less than the pivot value will be moved to the beginning of the list, followed by the pivot

element, and then all values that are bigger will appear at the end. The elements in each 'sublist' do not

need to be sorted in any way with respect to each other, but this order must be maintained. The

QuickSort algorithm is then used on each sublist, through recursion. This continues until the structure

has been sorted.

**Let's take a look at how the partitioning algorithm is implemented. The algorithm starts at each end of
**

the sublist being analyzed. It then moves inward from each end. First, it uses a while loop to find the

first value from the left that is greater than the pivot. Then, it uses another while loop to find the first

value from the right that is less than the pivot. It swaps these two values, and continues the process until

the left position value and right position value meet somewhere in the center. When this algorithm is

finished, every element at the left position and after is greater than the pivot, and the elements before it

are less than the pivot. The code for the partition algorithm is shown below.

**int part(int *nums,int left,int right,int pivot)
**

{

do

{

while(nums[left] < pivot) //find the next position greater than the pivot

from the left

left++;

while(nums[right] > pivot) //find the next position less than the pivot from

the right

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\sorting.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 5 of 8

right--;

swap(nums[left],nums[right]); //swap these two values

} while(left<right); //move inward until they cross

swap(nums[left],nums[right]); //the last swap occurs after left and right have

crossed (i.e. left is already < right, after which the outer loops end), therefore

we must re-swap these elements back into their correct positions

return left;

}

The pivot of each list is simply the middle element.

**int getpivot(int left,int right) //the left and right indices of the sublist
**

{

return (left+right)/2;

}

Now let's take a look how QuickSort brings everything together. The left and right indices of the sublist

must be passed into the QuickSort() function. Recursion is used by the algorithm to run QuickSort on

each partition, which is why these values are required as parameters. On the initial call to sort an array, 0

would be used for left index, and n-1 for the right index. The pivot value itself is already locked in the

correct position. Note, the pivot itself is not evaluated for the partition algorithm to work correctly. To

accomplish this, we swap it with the position of the last element, and start the partition with right-1.

After the partition, it is then swapped with the element at the first position of the right sublist. Now, all

the elements to the left are less than the pivot, and all those to the right are greater than the pivot.

**void QuickSort(int *nums, int left, int right)
**

{

int pivot = getpivot(left,right); //find the pivot

swap(nums[pivot],nums[right]); //move the pivot to the last position

int r_sublist = part(nums,left,right-1,nums[right]); //partition left->right-1,

excluding the pivot

swap(nums[r_sublist],nums[right]); //move the pivot in the proper position

if((r_sublist - left) > 1) //if a left sublist exists, sort it

QuickSort(nums,left,r_sublist-1);

if((right - r_sublist) > 1) //if a right sublist exists, sort it

QuickSort(nums,r_sublist+1,right);

}

**The merge sort is another algorithm which takes a "divide and conquer" approach. It begins by dividing
**

a list into two sublists, and then recursively divides each of those sublists until there are sublists with

one element each. These sublists are then combined using a simple merging technique.

In order to combine two lists, the first value of each is evaluated, and the smaller value is added to the

output list. This process continues until one of the lists has become exhausted, at which point the

remainder of the other list is simply appended to the output list. Two closest lists are combined at each

end, until all the elements are merged back into a single list.

The code for merge sort is very straightforward. The algorithm uses two arrays to accomplish the task.

First, the items to be sorted are copied to a temporary array, where they are divided. The original array

acts as the output array, and will contain the sorted list at the end. The parameters of the MergeSort()

function consist of these two arrays, as well as the left and right boundaries of the list to be sorted. This

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\sorting.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 6 of 8

is required since the MergeSort() function is recursive, and repeats the algorithms to sublists within the

array. On the initial call, left will have a value of 0, and right will have a value of n-1.

**void MergeSort(int *nums, int *tmp, int left, int right)
**

{

if (left==right) return; //if the boundaries are the same, the sublist has only

one element, and cannot be further split

int mid = (left+right)/2;

MergeSort(nums,left,mid); //sort the first half

MergeSort(nums,mid+1,right) //sort the second half

//copy the sublist into the temporary array

for(int i = left; i<=right; i++)

temp[i] = array[i];

//merge the lists

int l = left; //the first element in the first sublist

int r = mid + 1; //the first element in the second sublist

for(int j=left; j<=right; j++)

{

if(l == mid+1) //if the index of the left list is equal to the first element

of the right list, the left list has ended. Insert next item from right list.

nums[j] = tmp[r++];

else if (r > right) //if the index of the right sublist has exceeded it's

right boundary, the right list has ended. Insert next item from the left list.

nums[j] = tmp[l++];

else if(tmp[l] < tmp[r]) //if two lists exist, and the current element in the

left is smaller than the right, insert it into the next position in the output

array and move to the next element in the left list.

nums[j] = tmp[l++];

else //the current element in the right sublist is smaller than the one in

the left sublist, insert it into the output array and move to the next element in

the right list.

nums[j] = tmp[r++];

}

}

**The next algorithm, HeapSort, is very simple to implement. The array to be sorted is first inserted as a
**

heap structure. Then, a loop is used to remove each element of the heap. Remember from the lesson on

heaps, when an element is removed, it is still part of the physical array, and is swapped with the last item

of the heap. The process continues and each time the largest item is pushed to the end of the heap (which

is directly before the item discarded the previous iteration, since the heap becomes smaller). This

approach requires a slightly modified version of the heap class. The changes that were made are shown

in bold below.

const int MAX_SIZE = 100;

**template <class ItemType>
**

class Heap

{

public:

Heap(ItemType*,int);

int left(int) const;

int right(int) const;

int parent(int) const;

void insert(const ItemType&);

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\sorting.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 7 of 8

ItemType remove_max();

bool IsEmpty() const;

bool IsFull() const;

int count() const;

ItemType value(int) const;

private:

ItemType *array;

int elements; //how many elements are in the heap

void ReHeap(int);

void BuildHeap();

};

This version of the heap class accepts a pointer to the array to be sorted in the class constructor. The

second parameter of the constructor is the size of the array. The array is initialized as a pointer (which

will point to the array passed to the construtor), and a the function BuildHeap() has been added, which

will make the array into a heap.

**template <class ItemType>
**

Heap<ItemType>::Heap(ItemType *array_ptr, int size)

{

array = array_ptr;

elements = size;

BuildHeap();

}

The BuildHeap() function begins at the first non-leaf node and works up the array, sorting each subtree

with the ReHeap() function. Since leafs can't travel down any further, they do not need to be processed.

Instead, they will fall into their proper place by being exchanged with a node on a higher level if

necessary, when that node comes down.

By working up, the subtrees of a node are made into heaps first, which allows the ReHeap() function to

be used. The ReHeap() function relies on the fact that the node's subtrees are heaps. This is because it

compares the node to its children, and makes a switch if necessary. If the elements did not follow the

heap property, larger items on lower levels would never be brought to the top, since a comparison is

made with the node's children and not the parent.

**template <class ItemType>
**

void Heap<ItemType>::BuildHeap()

{

for(int j = n/2 - 1; j >= 0; j--)

ReHeap(j);

}

The heap sort algorithm makes the array to be sorted into a heap, and then follows the above procedure.

**template <class ItemType>
**

void HeapSort(ItemType *array, int size)

{

Heap<ItemType> sort(array, size);

for(int j = 0; j < size; j++)

sort.remove_max();

}

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\sorting.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 8 of 8

Note, although algorithms such as the QuickSort seem to be the only ones that should be used, this is

not always the case. If you know that the array to be sorted is very small, a O(N^2) algorithm is much

more simple to implement, and the difference will not be significant.

© 2000 ThinkQuest Team C005618

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\sorting.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 1 of 4

Stacks

A stack is a special type of list, where only the element at one end can be accessed. Items can be

"pushed" onto one end of the stack structure. New items are inserted before the others, as each old

element moves down one position. The first element is referred to as the "top" item, and is the only item

that may be accessed at any time. In order to access items that are further down the stack, they must be

moved to the top by "popping" the appropriate number of items. Popping refers to removing the top

element of a stack. This is referred to as a LIFO structure, "Last In, First Out".

These rules make stacks very restricted in use, however they are very efficient and much easier to

implement than lists. The uses of stacks vary from programming a simple card game, to maintaining the

order of operations in a complex program. For example, a stack is useful in a management program

where the newest tasks must be executed first. The node of a stack is usually presented with the

following structure, which is very similar to that of a list node.

**template <class ItemType>
**

struct StackNode

{

ItemType data;

StackNode<ItemType> *next;

};

**Implementing a generic stack class, which can be modified to work in any type of programming
**

situation is very easy to do. A definition of such a class is shown below.

**template <class ItemType>
**

class Stack

{

public:

Stack(); //class constructor - initialize private variables

~Stack(); //class destructor - free up used memory

void push(const ItemType); //add a new node to the top of the stack

ItemType pop(); //remove the top node and return its contents

ItemType top() const; //return the top node without popping it

void clear(); //delete all nodes in the stack

bool IsEmpty() const; //return true if the stack has no elements

bool IsFull() const; //return true if there is no free memory for new nodes

int count() const; //return the amount of nodes on the stack

private:

StackNode<ItemType> *top; //pointer to the top node in stack

int counter; //maintain the amount of nodes in the stack

};

The class constructor sets counter to zero. Since there are no nodes in the stack when an instance of the

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\stack.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 2 of 4

class is first created, top is set to NULL.

**template <class ItemType>
**

Stack<ItemType>::Stack()

{

counter = 0;

top = NULL;

}

The role of the destructor is to delete all nodes in the list, and return the memory they occupy to free

store. Since the clear() function does this task, it can be called by the destructor.

**template <class ItemType>
**

Stack<ItemType>::~Stack()

{

clear();

}

The push() function inserts a new node on top of the stack, and sets the top pointer to reference this new

node. First, we check if there is enough system memory to create a new node, and then create the node,

assigning it to top. The node's value is set equal to item, and its next component is set to the node that

was on top before the creation of the new node.

**template <class ItemType>
**

void Stack<ItemType>::push(const ItemType item)

{

assert(!IsFull()); //abort if there is not enough memory to create a new node

StackNode<ItemType> *tmp = new StackNode<ItemType>; //create a new node on top

of the others with value item. set the original top node to follow the new one.

tmp->data = item; tmp->next = top; top = tmp; counter++; //increment

the amount of nodes in the stack

}

The pop() function removes the top node from the stack (freeing up the memory it uses) and returns its

value. top is set to the next node in the stack, and a temporary local variable(tmp) is created to point to

the original top node. It is then used to reference the memory address of the node to delete. If we were to

delete the node using top as a reference, the position of the next node in the stack would be lost, since

top->next would no longer exist.

**template <class ItemType>
**

ItemType Stack<ItemType>::pop()

{

assert(!IsEmpty()); //abort if the stack is empty, no node to pop

ItemType item = top->data; //maintain top value, to be returned later

StackNode<ItemType> *tmp = top; //create a temporary reference to the top node

top = top->next; //set top to be the next node

delete tmp; //delete the top node

counter--; //decrement the amount of nodes in the stack

return item; //return the original top value

}

The top() function simple returns the value of the top node, without any modifications to the stack.

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\stack.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 3 of 4

**template <class ItemType>
**

ItemType Stack<ItemType>::top() const

{

assert(!IsEmpty());

return top->data;

}

The clear() function delete all nodes in the stack, and frees the memory they occupy. Each node in the

stack is visited using a loop, which executes until it reaches a NULL reference. A temporary variable is

used for the same reason as in the list implementation. If we were to delete a node using top as a

reference, the position of the next node in the list would be lost, since top->next would no longer exist.

**template <class ItemType>
**

void Stack<ItemType>::clear()

{

StackNode<ItemType> *tmp;

while(top != NULL) //loop through every node in the stack

{

tmp = top; //reference the top node

top = top->next; //set top to the next node

delete tmp; //delete the original top node

}

}

The IsEmpty() function returns true if the stack has no nodes. This task is accomplished very simply by

checking to see if the top pointer is NULL.

**template <class ItemType>
**

bool Stack<ItemType>::IsEmpty() const

{

return (top == NULL);

}

**The IsFull() function checks to see if there is enough system memory avaliable to create a new node
**

for the stack. It works exactly the same way as it did in the linked list class. A node is "created" using

the new command, which is then evaluated. If the new command had failed to set aside the necessary

memory, its value is NULL, in which case the function returns true. If the new node is created

successfully, it is deleted, and the function returns false.

**template <class ItemType>
**

bool Stack<ItemType>::IsFull() const

{

StackNode<ItemType> *tmp = new StackNode<ItemType>;

if(tmp == NULL)

return true;

else

{

delete tmp;

return false;

}

}

**file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\stack.htm 12/13/2007
**

An Introduction to Data Structures with C++ Page 4 of 4

The count() function returns the amount of nodes in the stack, which is maintained by the class' private

counter member. Again, this value can be maintained using a public member which the programmer can

access directly, however it is good practice to hide this value from the programmer, since it can be

modified without any nodes being added or removed. Also, if we were to change the class

implementation, a program using the stack class would not require any change, since all the new code

will be written in the count() function.

**template <class ItemType>
**

int Stack<ItemType>::count() const

{

return counter;

}

© 2000 ThinkQuest Team C005618

file://F:\My Ebooks\Introduction_to_Data_Structures_with_C++\stack.htm 12/13/2007

- Data Structures AssignmentUploaded byapi-26041279
- UNIT III.docxUploaded byJayakumar Loganathan
- 6. IMPLEMENTATION OF BINARY SEARCH TREEUploaded byeffffffff
- Data Strs Using CUploaded byShashank M Chanmal
- Project 4Uploaded byDanh Nguyen
- data structure lab manualUploaded bybharatkumarpadhi
- CS-302-(3001-(O)).pdfUploaded byMaz Har Ul
- Data StructuresUploaded byHenryHai Nguyen
- mcdermott 6014 final summer b 17Uploaded byapi-373102817
- 1-Java.docxUploaded bymanas199
- Topic1 State Space SearchUploaded bySumit Mehrotra
- Hull-White Model 2Uploaded bymeko1986
- Artificial Intelligence Projects for the Commodore 64Uploaded byCubemanPDX
- 2014-fpdaaUploaded byajitkarthik
- TOTSOL-DSTR-02Uploaded bygauravhchavda
- A Dynamic Error based fair scheduling using Two Layered Distributed Heap Sort Tree for a Computational GridUploaded byJournal of Computing
- Seg TreeUploaded bybradburywills
- Lecture 8 - Binary TreesUploaded byshubhamgupta007
- B_plus_tree_ch14.docUploaded byHeena Sharma