Kendall Small
Professor Yu
CSE 330
Homework 3
I believe I deserve full credit (55 points) for this assignment because I successfully completed
each problem and included output.
1.( 20 points ) Suppose for a certain application it was important to always know the number of
elements in a list. The implementation of the member function size() of class List discussed in
class and presented in the textbook employs a loop, and thus has O(n) execution time.
Using inheritance, write a new template class named countedList that maintains an explicit
count on the number of values held in the list, and the function size() will return this count. You
need to rewrite the insertion and deletion functions in the subclass so that the count is handled
appropriately.
//list.h
#ifndef LIST_H
#define LIST_H
template <typename T> class countedList;
template <typename T> class Node; //forward declaration
template <typename T> class listIterator; //forward declaration
template<typename T>
class List {
protected:
Node<T> *first;
Node<T> *last;
public:
//type definition
typedef T value_type;
typedef listIterator<T> iterator;
//constructor and destructor
List ();
virtual ~List();
//operations
bool empty();
int size();
T &front(); //returns first element
T &back(); //returns last element
void push_front ( T & ); //insert from the front
void push_back( T & ); //insert from the back
void pop_front(); //remove first element
void pop_back(); //remove last element
iterator begin();
iterator end();
void sort();
void insert( iterator &, T &);
void erase( iterator & );
void erase( iterator &, iterator &);
};
template <typename T>
class listIterator {
typedef listIterator<T> iterator;
protected:
List<T> *theList;
Node<T> *currentNode;
friend class List<T>;
friend class countedList<T>;
public:
//constructor
listIterator ();
listIterator ( List<T> *tl, Node<T> *cl );
T &operator * (); //dereferencing
bool operator != ( iterator &rhs );
iterator & operator ++ ( int ); //prefix
iterator operator ++ (); //postfix
};
#endif
//Node.h
#ifndef NODE_H
#define NODE_H
template <typename T> class countedList;
template <typename T> class List; //forward declaration
template <typename T> class listIterator; //forward declaration
//a Node is a node ( cell )
template <typename T> class Node {
private:
Node ( T &v ); //constructor
T value;
Node<T> *next;
Node<T> *prev;
//allow lists and iterators to access members
friend class List<T>;
friend class listIterator<T>;
friend class countedList<T>;
};
#endif
//list.cpp
#include <iostream>
#include "list.h"
#include "Node.h"
#include <stdio.h>
template<typename T>
List<T>::List()
{
first = last = 0; //null list
}
template<typename T>
bool List<T>::empty()
{
return first == 0;
}
template<typename T>
int List<T>::size()
//count the number of elements in collection
/*
Comments from Tong: This is NOT a good implementation as
it takes time to traverse the list. A better way is to include
a field called 'size' in the List class; when elements are
inserted or deleted, size is adjusted.
*/
{
int count = 0;
Node<T> *p;
for ( p = first; p != 0; p = p->next )
count++;
return count;
}
template<typename T>
void List<T>::push_front( T &a )
{
Node<T> *newNode = new Node<T> ( a );
if ( empty() )
first = last = newNode;
else {
first->prev = newNode;
newNode->next = first;
first = newNode;
}
}
template<typename T>
void List<T>::pop_front()
{
Node <T> *temp = first;
first = first->next;
if ( first != 0 )
first->prev = 0;
else
last = 0;
delete temp;
}
template<typename T>
List<T>::~List()
{
Node <T> *p = first;
while ( p != 0 ) {
Node<T> *temp = p;
p = p->next;
delete temp;
}
}
template<typename T>
listIterator<T> List<T>::begin()
{
return iterator ( this, first );
}
template<typename T>
listIterator<T> List<T>::end()
{
return iterator ( this, 0 ); //points beyond last
}
//listIterator
//constructors
template<typename T>
listIterator<T>::listIterator()
{
}
template<typename T>
listIterator<T>::listIterator( List<T> *lp, Node<T> *lkp )
{
theList = lp;
currentNode = lkp;
}
template<typename T>
T & listIterator<T>::operator * ()
{
return currentNode->value;
}
template<typename T>
bool listIterator<T>::operator != ( iterator &rhs )
{
return currentNode != rhs.currentNode;
}
template<typename T>
listIterator<T> & listIterator<T>::operator ++ (int)
{
currentNode = currentNode->next;
return *this;
}
template<typename T>
listIterator<T> listIterator<T>::operator ++ ()
//postfix form of increment ( e.g. assigned, then increment )
{
//make an old copy
listIterator<T> clone ( theList, currentNode );
currentNode = currentNode->next; //advance pointer
return clone; //return old iterator
}
template<typename T>
void List<T>::insert( listIterator<T> &itr, T &a )
{
Node<T> *p = new Node<T> ( a );
Node<T> *current = itr.currentNode;
if ( empty() ) { //empty list
first = last = p;
return;
}
//assert ( current );
if ( current == 0 ){ //point to end, thus append to list
last->next = p;
p->next = 0;
p->prev = last;
last = p;
return;
}
//otherwise, always insert before
p->next = current;
p->prev = current->prev;
current->prev = p;
current = p->prev;
if ( current != 0 )
current->next = p;
else
first = p;
}
template<typename T>
void List<T>::erase ( listIterator<T> &start, listIterator<T> &stop )
//remove elements from the range ( before stop )
{
//List is friend of listIterator, so it can access listIterator's
// private or protected data member
Node<T> *p = start.currentNode;
Node<T> *q = p->prev;
Node<T> *stopNode = stop.currentNode;
if ( q == 0 ) { //removing initial portion of list
first = stopNode;
if ( stopNode == 0 ) //pointing to end
last = 0; //whole list is deleted
else
stopNode->prev = 0;
} else {
q->next = stopNode;
if ( stopNode == 0 )
last = q;
else
stopNode->prev = q; // q->prev = q;
}
//now delete the atoms
while ( start != stop ) {
listIterator<T> next = start;
++next;
delete start.currentNode;
start = next;
}
}
//Node.cpp
#include "Node.h"
#include "list.h"
template <typename T>
Node<T>::Node( T &v )
{
value = v;
prev = next = 0;
}
//countedList
//Kendall Small
#include "list.h"
#ifndef COUNTEDLIST_H
#define COUNTEDLIST_H
template<typename T>
class countedList : public List<T>{
protected:
int size;
public:
countedList(){size=0;}
void c_erase(listIterator<T> &start, listIterator<T> &stop);
void c_insert(listIterator<T> &itr, T &a);
void c_pop_front();
void c_push_front(T &a);
int c_size(){return size;}
~countedList();
};
#endif
//countedList.cpp
//Kendall Small
//#include "list.h"
#include "countedlist.h"
#include<iostream>
//using namespace std;
template<typename T>
countedList<T>::~countedList()
{
Node <T> *p = List<T>::first;
while ( p != 0 ) {
Node<T> *temp = p;
p = p->next;
delete temp;
}
}
template<typename T>
void countedList<T>::c_push_front(T &a)
{
size++;
Node<T> *newNode = new Node<T> ( a );
if ( List<T>::empty() )
List<T>::first = List<T>::last = newNode;
else {
List<T>::first->prev = newNode;
newNode->next = List<T>::first;
List<T>::first = newNode;
}
}
template<typename T>
void countedList<T>::c_pop_front()
{
size--;
Node <T> *temp = List<T>::first;
List<T>::first = List<T>::first->next;
if ( List<T>::first != 0 )
List<T>::first->prev = 0;
else
List<T>::last = 0;
delete temp;
}
template<typename T>
void countedList<T>::c_insert(listIterator<T> &itr, T &a)
{
size++;
Node<T> *p = new Node<T> ( a );
Node<T> *current = itr.currentNode;
if ( List<T>::empty() ) { //empty list
List<T>::first = List<T>::last = p;
return;
}
//assert ( current );
if ( current == 0 ){ //point to end, thus append to list
List<T>::last->next = p;
p->next = 0;
p->prev = List<T>::last;
List<T>::last = p;
return;
}
//otherwise, always insert before
p->next = current;
p->prev = current->prev;
current->prev = p;
current = p->prev;
if ( current != 0 )
current->next = p;
else
List<T>::first = p;
}
template<typename T>
void countedList<T>::c_erase (listIterator<T> &start,listIterator<T> &stop)
//remove elements from the range ( before stop )
{
//List is friend of listIterator, so it can access listIterator's
// private or protected data member
Node<T> *p = start.currentNode;
Node<T> *q = p->prev;
Node<T> *stopNode = stop.currentNode;
if ( q == 0 ) { //removing initial portion of list
List<T>::first = stopNode;
if ( stopNode == 0 ) //pointing to end
List<T>::last = 0; //whole list is deleted
else
stopNode->prev = 0;
} else {
q->next = stopNode;
if ( stopNode == 0 )
List<T>::last = q;
else
stopNode->prev = q; // q->prev = q;
}
//now delete the atoms
while ( start != stop ) {
listIterator<T> next = start;
++next;
delete start.currentNode;
start = next;
--size;
}
}
//list_demo1.cpp
/*
Because of the use of template when defining the List and Node classes,
unfortunately, we do need to include the .cpp files here for the
current compilers.
*/
#include <iostream>
#include "list.cpp"
#include "Node.cpp"
#include "countedlist.cpp"
using namespace std;
template <typename T>
void print_list( countedList<T> &aList )
{
typename countedList<T>::iterator start, stop;
start = aList.begin(); stop = aList.end();
while ( start != stop ){
cout << *start << ",\t";
++start;
}
cout << endl;
}
int main()
{
typedef double T;
countedList<T> aList; //a list
T n;
while ( true ) {
cout << "Enter a number, -99 to terminate: ";
cin >> n;
if ( n == -99 )
break;
aList.c_push_front( n ); //insert into list at front
} //while
cout << "You have entered the list: " << endl;
print_list( aList );
listIterator<double> itr1;
listIterator<double> itr2;
itr2 = aList.begin();
itr1 = aList.end();
cout<<"The size of the list is: "<<aList.c_size()<<endl;
for(int i=0;i<aList.c_size()-1;i++){
++itr2;
}
cout<<"Deleting one item...\n";
aList.c_erase(itr2, itr1);
cout<<"The size of the list is: "<<aList.c_size()<<endl;
itr2 = aList.begin();
for(int i=0;i<aList.c_size()-2;i++){
++itr2;
}
cout<<"Deleting two items...\n";
aList.c_erase(itr2, itr1);
cout<<"The size of the list is: "<<aList.c_size()<<endl;
itr2 = aList.begin();
for(int i=0;i<aList.c_size()-3;i++){
++itr2;
}
cout<<"Deleting three items...\n";
aList.c_erase(itr2, itr1);
cout<<"The size of the list is: "<<aList.c_size()<<endl;
cout<<"Adding two items (0's')...\n";
n=0;
aList.c_insert(itr1,n);
itr1 = aList.end();
aList.c_insert(itr1, n);
cout<<"The size of the list is: "<<aList.c_size()<<endl;
//++itr2; ++itr2;
//aList.c_erase(itr2, itr1 );
print_list( aList );
cout<<"The size of the list is: "<<aList.c_size()<<endl;
return 0;
}
2. ( 15 points )
a) What is the postfix expression of the following?
(a * ( b + c ) + ( b / d ) * a / e
The postfix expression is: a, b, c, +, *, b, d, /, a, *, e, /, +
b) Write a complete program that can parse an arbitrary infix expression consisting of real
numbers, positive and negative, convert it to postfix and evaluate it ( see lab 8 ). Add to your
program a menu that have the following instructions:
(i) c -- clear all values from postfix queue,
(ii) d -- double front value of the postfix queue
Test your implementation with various infix input expressions.
//
//Kendall Small
#ifndef SYMBOL_H
#define SYMBOL_H
#include<string>
#include<queue>
#include<stack>
#include<stdio.h>
#include<ctype.h>
using namespace std;
typedef double dType; //Data type: int or double
enum inKind {operate, number}; //input kind
class SYMBOL{
public:
dType num; //stores numbers
inKind kind; //determines number or operator
char operatr; //stores operators
};
void in2postFix(stack<SYMBOL> &ifix, queue<SYMBOL> &pfix);
dType eval (queue<SYMBOL> &post);
#endif
//TOOLS_H
//Kendall Small
#include "symbol.h"
#ifndef TOOLS_H
#define TOOLS_H
void que2stack(queue<SYMBOL> &que, stack<SYMBOL> &s);
void reverse_stack(stack<SYMBOL> &s, stack<SYMBOL> &sr);
bool c_is_an_operator( char c);
void print_que(queue<SYMBOL> q);
void print_stack(stack<SYMBOL> s);
void double_first(queue<SYMBOL> &q);
void clear(queue<SYMBOL> &q);
#endif
//in2postfix.cpp
#include "symbol.h"
int precedence(char c){
switch(c){
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
}
return 0; //lowest precedence
}
void transfer(stack<SYMBOL> &s, queue<SYMBOL> &q){
q.push(s.top());
s.pop(); //Add top stack elem to queue, then delete
}
void in2postFix(stack<SYMBOL> &ifix, queue<SYMBOL> &pfix){
stack<SYMBOL> opStack; //stack of operators
SYMBOL a;
while(!ifix.empty()){
a=ifix.top(); //get next operator/operand from infix
ifix.pop(); //remove(delete) the top operator/operand
if(a.kind==number){pfix.push(a);} //to postfix queue
else if(opStack.empty()){opStack.push(a);} //to operator stack
else if(a.operatr=='('){opStack.push(a);} //Since ( lowest precedence
else if(a.operatr==')'){ //
while(opStack.top().operatr != '(')
transfer (opStack, pfix);
opStack.pop(); //transfer ( and remove
} else {
while(!opStack.empty()&&precedence(a.operatr)<=precedence(opStack.top().operatr))
transfer(opStack, pfix);
opStack.push(a);
}
}//while
while(!opStack.empty())
transfer(opStack, pfix);
}
//eval.cpp
//Kendall Small
#include "tools.h"
#include "symbol.h"
//Evaluate postfix expression
dType eval(queue<SYMBOL> &post){
stack<SYMBOL> eval;
dType a, b, ans;
char binaryOp; //binary operators +,=,*,/
SYMBOL symPop, symEval; //symbols popped element and evaluate
while(!post.empty()){
symPop=post.front();
post.pop();
if(symPop.kind==number)
eval.push(symPop); //save numbers until operator is found
else {
symEval = eval.top(); //gets a number to evaluate
a = symEval.num;
eval.pop();
symEval=eval.top(); //another number to evaluate
b = symEval.num;
eval.pop();
binaryOp=symPop.operatr;
switch(binaryOp){
case '-':
ans = b - a;
break;
case '+':
ans=b+a;
break;
case '/':
ans = b/a;
break;
case '*':
ans=b*a;
break;
}
symEval.num=ans; //answer goes back on until queue empty
eval.push(symEval);
}
}
symEval=eval.top();
return symEval.num;
}
//tools.cpp
//Kendall Small
#include "symbol.h"
#include "tools.h"
#include<iostream>
using namespace std;
void double_first(queue<SYMBOL> &q){
SYMBOL temp = q.front();
if(q.front().operatr == operate){
cout<<"Cannot double an operator.\n";
}
else
q.front().num *= 2;
}
void clear(queue<SYMBOL> &q){
while(!q.empty()){
q.pop();
}
}
void que2stack(queue<SYMBOL> &q, stack<SYMBOL> &s){
SYMBOL sym;
while(!q.empty()){
sym=q.front();
q.pop();
s.push(sym);
}
}
void reverse_stack(stack<SYMBOL> &s, stack<SYMBOL> &sr){
SYMBOL sym;
while(!s.empty()){
sym=s.top();
sr.push(sym);
s.pop();
}
}
bool c_is_an_operator(char c){
if(c=='(' || c==')' || c=='+' || c=='*' || c=='/' || c=='-')
return true;
return false;
}
void print_que(queue<SYMBOL> q){
while(!q.empty()){
SYMBOL s=q.front();
q.pop();
if(s.kind==number)
cout<<s.num<<" ";
else
cout<<s.operatr<< " ";
}
cout<<endl;
}
void print_stack(stack<SYMBOL> s){
while(!s.empty()){
SYMBOL a= s.top();
s.pop();
if(a.kind==number)
cout<<a.num<<" ";
else
cout<<a.operatr<<" ";
}
cout<<endl;
}
//Infix to postfix program main.cpp
//Kendall Small
#include "symbol.h"
#include "tools.h"
#include <iostream>
using namespace std;
int main() {
stack<SYMBOL> sym, s1;
queue<SYMBOL> que;
SYMBOL s;
char c, select, again;
double x, xInt, xFrac, fracD;
int dotFlag, readFlag, numFlag, sign, lpFlag;
dType ans;
do{
cout<<"Enter an infix expression using real numbers\n";
cout<<"Every negative number after the first must be inside parenthesis\n";
cout<<"For example: -1*(3 + (-4))\n";
x=xInt=xFrac=0;
fracD=0.1;
dotFlag=numFlag=0;
lpFlag=0;
while((c=getchar())==' ');
if(c=='-'){
sign=-1;
c=getchar();
} else
sign=1;
while(true){
if(c=='.') dotFlag=1;
if(isdigit(c)){
if(!dotFlag)
xInt=xInt*10+(c-'0');
else {
xFrac+=(c-'0')*fracD;
fracD*=0.1;
}
numFlag=1;
}else
if((numFlag==1)&&(c!='.')){
x=xInt+xFrac;
s.num=x*sign;
s.kind=number;
sym.push(s);
sign=1;
fracD=0.1;
x=xInt=xFrac=0.0;
dotFlag=numFlag=0;
}else if(c=='('){
while((c=getchar())==' ');
if(c=='-'){
lpFlag=1;
sign=-1;
c=getchar();
continue;
}else{
ungetc(c,stdin);
c='(';
}
}//(c=='(')
if(c_is_an_operator(c)){
if(!lpFlag){
s.operatr=c;
s.kind=operate;
sym.push(s);
}
lpFlag=0;
}
if(c=='\n')break;
c=getchar();
}//while(true)
reverse_stack(sym, s1);
cout<<"The infix expression you entered was: ";
print_stack(s1);
in2postFix(s1, que);
cout<<"Please select an option: \n";
cout<<"Enter: c -- clear all values from postfix queue (start again)\n";
cout<<"Enter: d -- double the value in the first spot of the postfix queue\n";
cout<<"Anything else will finish the program as usual, giving output.\n";
cin>>select;
switch(select){
case 'c':
case 'C':{
clear(que);
cout<<"Printing empty postfix queue: ";
print_que(que);
cout<<"If nothing printed then postfix queue successfully cleared.\n";
break;
}
case 'd':
case 'D':{
cout<<"Postfix queue before: \n";
print_que(que);
double_first(que);
cout<<"Postfix expression after doubling: \n";
print_que(que);
cout<<"The answer is: "<<eval(que)<<endl;
break;
}
default:{
cout<<"After conversion the postfix expression is: ";
print_que(que);
cout<<"The answer is: "<<eval(que)<<endl;
break;
}
}//switch
cout<<"Again? (Y/N)\n";
cin>>again;
cin.clear(); cin.ignore(INT_MAX,'\n');
}while(again == 'Y' || again=='y');
return 0;
}
3. ( 10 points ) Write a program that makes use of the functions of bitset to do the following:
a. it asks for an integer as input, prints out its value in 24-bit binary form and in 8-hex-digit
form;
b. it asks for a binary value as input and prints out its decimal value; it should be able to
handle binary values up to 32-bit.
//Bitset
//Kendall Small
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string>
#include<bitset>
using namespace std;
int main() {
int toBinary, temp;
long fromBinary;
char hex[240];
string binary;
cout<<"Please enter an integer to be converted to 24-bit binary: \n";
cin>>toBinary;
bitset<24> intSet(toBinary);
cout<<"The integer "<<toBinary<<" is equal to "<<intSet<<" in binary form.\n";
bitset<32> hexSet(toBinary);
cout<<"The integer "<<toBinary<<" is equal to hex: ";//<<hex<<" in hex form.\n";
for(int i=31;i>=0;i-=4){
bitset<4> t;
for(int j=i;j>(i-4);j--){
t[j%4]=hexSet[j];
}
fromBinary=t.to_ulong();
itoa(fromBinary,hex, 16);
cout<<hex<<" ";
}
cout<<endl<<endl;
cin.clear();
cin.ignore(INT_MAX,'\n');
cout<<"Enter a string of binary up to 32 bits long: \n";
getline(cin, binary);
bitset<32> stringSet(binary);
fromBinary = stringSet.to_ulong();
cout<<"The binary "<<binary<<" is equal to "<<fromBinary<<" in base 10.\n";
return 0;
}
4. ( 10 points ) Write a program that makes use of a backtrack algorithm to see if you can put 10
queens on a hypothetical 10x10 square chess board with no queen threatening any other. If
there's a solution, prints out the solution.
//Backtracking algorithm
//Kendall Small
#include <iostream>
using namespace std;
class nQueen{
public:
nQueen();
void clear();
void printBoard();
void setPiece(int col, bool &verdict);
bool answer(int);
private:
int n; //size
char board[10][10];
void set(int col, int row){board[row][col]='X';}
void get(int col, int row){board[row][col]='-';}
bool danger(int col, int row);
};
nQueen::nQueen(){
n=10; //change size here as well
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
board[i][j] = '-';
}
}
}
void nQueen::printBoard(){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cout<<board[i][j]<<" ";
}
cout<<"\n";
}
}
bool nQueen::danger(int r, int c){
int a, b;
for(a=0;a<c;a++){
if(board[r][a]=='X')
return true;
}
for(a=r, b=c;a>=0 && b>=0;a--, b--){
if(board[a][b]=='X')
return true;
}
for(a=r, b=c;b>=0 && a<n;a++, b--){
if(board[a][b]=='X')
return true;
}
return false;
}
bool nQueen::answer(int col){
if(col>=n){
return true;
}
for(int a=0;a<n;a++){
if(danger(a, col)==false){
set(col, a);
//board[a][col]= 'X';
if(answer(col+1)==true)
return true;
get(col, a);
//board[a][col]='-';
}
}
return false;
}
int main() {
nQueen ten;
bool verdict;
verdict = ten.answer(0);
if(verdict==true)
ten.printBoard();
else
cout<<"There is no solution.\n";
return 0;
}