Short C++ Program Answers
by Curtis Krauskopf
Two factors are important with the "Showing Skills"
type questions. The first is to create a working program
that solves the problem. The second factor is to do
the work within the time you've allotted yourself.
Giving an accurate time estimate is a skill that I've
had to learn to develop. I practice it daily by challenging
myself even on routine matters, such as how long will
it take me to debug a problem, or how long will it take
me to design a module?
Asking how long a task will take is a reasonable question
for an employer or customer because they want to know
when a solution will be available and how much the solution
will cost.
For yourself, it's part of time management and being
able to deliver projects on-time and on-budget.
The solutions for the six "Showing Skills" problems
are shown in listings F through K. I've provided the
time I took to create the solution. The purpose is to
give you a benchmark with which to gauge your productivity.
For example, if you estimate 30 minutes for a problem
and you're still working on it two hours later, that
should tell you something constructive about your organization,
coding skills, and debugging skills.
I used all available references for my solutions. When
I interview people, I allow them to use references because
employers never take away your programming books when
they assign you a project. When given a programming
assignment, you should feel free to ask about using
reference books or the Internet.
Array destruction
An array that is instantiated with the new[]
operator should also be deleted using the delete[] operator.
Write a program that proves that the destructors for
an array are not called when the array was instantiated
with new [] and the array was deleted with delete (without
the delete[] syntax).
My first version of the array destruction test in Listing
F did not use the VCL (a Borland C++ compiler feature)
and an access violation was thrown at runtime. I tried
to wrap the delete with a try/catch, but the exception
still wasn't caught. The debugger told me that an EAccessViolation
exception was being thrown and the C++ Builder Help
told me that it was defined in the VCL. So I converted
the program to use the VCL and tried it again. The VCL
version does not cause an access violation at runtime,
so I removed the try/catch block in the code.
Caseless string comparison
Write a String class that compares its strings
by ignoring the case of the characters.
I had two choices when writing the caseless string
comparison solution in Listing G. I could either create
my own string class that stores a string using a has-a
relationship or I could override the compare method
in the std::char_traits class. The former would require
me to write helper functions for all of the public and
protected constructors and methods. I chose the latter
solution because its code should be limited to a specialized
std::char_traits class.
Notice that I didn't have to write any specialized
comparison methods (operator==, operator<, operator>,
and others). I used the template supplied by the STL,
which calls _Traits::compare(). The static compare()
method in CaselessTrait was created by debug-tracing
a normal std::string comparison into the char_traits.h
file. I copy-pasted the definition of compare() from
char_traits into the solution and changed the comparison
function from memcpy to strnicmp.
Time difference
A comma-delimited file has two columns: timeA
and timeB. Both columns are times in the following format:
hh:mm [a|p]m
where:
hh is from 1 to 12.
mm is from 1 to 60.
[a|p] is either an 'a' or 'p'.
Example file:
5:57 pm,10:37 am
Write a program that reads the comma-delimited text
file. For each line in the text file, report the time
that is earlier. Assume all times are in the same
time zone and that all times are for the same day.
The time comparison solution in Listing H primarily
converts both times into the number of minutes past
midnight and then simply compares those two values.
I added some code that reports errors, such as when
the file can't be opened or when the data format is
grossly wrong.
The parsing algorithm in decodeTime() assumes the data
is in the right format. The problem doesn't require
anything more than this but in a real interview I would
ask if the program should check for incorrectly formatted
data or invalid data, such as 11:88am. My am/pm detection
only checks for "pm" and assumes all other values, including
"PM", are "am". I could have easily used stricmp instead
of operator==(), but at
that point in the parser I was assuming that the data
would be correctly formatted. These are the kinds of
tradeoffs one makes when keeping the solution simple
and staying within the deadline.
Recursive sort
Sort a linked list using recursion.
The recursive sort algorithm in Listing I took a lot
longer than I would have expected. My implementation
assumes that only the head pointer is available. A flag,
sortAgain, is initialized to false and is used to tell
Sort() if any of the nodes in the list were swapped.
If RecursiveSort() returns with sortAgain still false,
the list has been sorted. Otherwise, sortAgain is reset
to false and the list is resorted.
To keep the algorithm simple, I didn't make any attempt
to keep track of the sorted and unsorted parts of the
list. The entire list is sorted every time RecursiveSort
is called.
Recursive sort solutions that swap the key values or
swap the struct's payload values should be considered
failures. Shuffling the data inside of the list defeats
the purpose of using a linked list. The main reason
for using a linked list is because the data is supposedly
large or difficult to copy. If that were not the case,
then an array would have been used. List nodes are being
used to point to the data. The head pointer and the
next pointers are the only parts of the list that need
to be modified to sort it.
Don't forget to test your final solution for an empty
list and for a list with only one item in it. The first
version of my algorithm would have thrown an access
violation for an empty list.
Iterative list sorting
Sort a linked list without using recursion.
Listing J shows my solution for nonrecursively sorting
the single-linked list. I cheated a little bit and used
the recursive sort solution from listing I as a starting
point. It's not really cheating, though, because I'm
allowed to use whatever resources are available.
In the process of looking at the swap algorithm a second
time, I noticed it could be improved a little. I think
the version in listing J is a little clearer because
only the work that's needed for the boundary condition
(the very first element in the list) is inside of the
if statement.
Reversing a single linked list
Reverse a single-linked list without using
recursion.
My solution for reversing the single-linked list, in
Listing K, was based on the code in Listing J. The solution
does not overwrite the next pointer for the head node
until the entire list has been sorted. I thought this
would be easier than checking, on each loop iteration,
if the head node was being modified.
As with the sorting solutions, any solutions that involve
moving the data values instead of changing the head
and next pointers is a failure.
If I were to provide the linked list problems as an
interviewer, I would provide everything in the solution
except for the sorting or reversing method and everything
in the main() function up to the first Print method.
|