25-Comp-A4 Program Design and Data Structures · December 2017
Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)
Paper format. 98-Comp-A4 Program Design and Data Structures, December 2017 — 3 hours, closed book, no calculator permitted. Nine questions of equal weight (20 marks each: 1 and 7 split as (a) 10 + (b) 10, 8 split as (a) 15 + (b) 5); candidates answer any six, so a complete paper is 120 marks. Pseudocode or any high-level language is accepted, and the examiner's note states explicitly that marking emphasises the operation of the program, not syntactic details. All nine questions are answered below, because the whole set is the more useful revision resource. Answers are given in C or C++ as the question dictates; each is compilable as written (or corrected where the printed paper itself has a slip), but a clear, correctly reasoned pseudocode answer would earn the same marks.
Reference texts for this subject.
The Computer Engineering citation list is built around architecture and networking texts (Patterson & Hennessy, Tanenbaum, Mano); this subject is programming and data structures, so the works above are cited instead.
Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.
Given. A requirement for a double-only
Matrix class supporting sized (with/without initial value) construction,
read/write element access, +, -, * and
==, and printing, split across a header and an implementation
file.
Find. A Matrix.h / Matrix.cc
pair implementing the class.
Approach. Store rows, cols and
a single heap-allocated double* buffer (row-major), with
operator()(i,j) returning a reference for combined read/write
access. Implement the Big-Three (copy constructor, destructor,
operator=) because the class owns heap memory; overload
+/-/* to check dimension
compatibility, throwing on mismatch (assumption, stated explicitly since the
question leaves error handling open); overload << for
printing rather than a named print() method, and
== for exact elementwise comparison.
data[i*cols+j] avoids the double
indirection of an array of pointers and lets the copy constructor,
destructor and assignment operator each manage exactly one allocation.Matrix.h.
// Matrix.h
#ifndef MATRIX_H
#define MATRIX_H
#include <iostream>
class Matrix {
public:
Matrix(int rows, int cols, double init = 0.0); // sized, optional init
Matrix(const Matrix& other); // copy constructor
~Matrix();
Matrix& operator=(const Matrix& other);
double& operator()(int i, int j); // read & write access
double operator()(int i, int j) const;
Matrix operator+(const Matrix& rhs) const;
Matrix operator-(const Matrix& rhs) const;
Matrix operator*(const Matrix& rhs) const;
bool operator==(const Matrix& rhs) const;
int numRows() const { return rows_; }
int numCols() const { return cols_; }
friend std::ostream& operator<<(std::ostream& os, const Matrix& m);
private:
int rows_, cols_;
double* data_; // row-major, size rows_*cols_
};
#endif
Matrix.cc.
// Matrix.cc
#include "Matrix.h"
#include <stdexcept>
Matrix::Matrix(int rows, int cols, double init)
: rows_(rows), cols_(cols), data_(new double[rows * cols])
{
for (int k = 0; k < rows_ * cols_; k++) data_[k] = init;
}
Matrix::Matrix(const Matrix& other)
: rows_(other.rows_), cols_(other.cols_),
data_(new double[other.rows_ * other.cols_])
{
for (int k = 0; k < rows_ * cols_; k++) data_[k] = other.data_[k];
}
Matrix::~Matrix() { delete[] data_; }
Matrix& Matrix::operator=(const Matrix& other)
{
if (this == &other) return *this;
delete[] data_;
rows_ = other.rows_; cols_ = other.cols_;
data_ = new double[rows_ * cols_];
for (int k = 0; k < rows_ * cols_; k++) data_[k] = other.data_[k];
return *this;
}
double& Matrix::operator()(int i, int j) { return data_[i * cols_ + j]; }
double Matrix::operator()(int i, int j) const { return data_[i * cols_ + j]; }
Matrix Matrix::operator+(const Matrix& rhs) const
{
if (rows_ != rhs.rows_ || cols_ != rhs.cols_)
throw std::invalid_argument("dimension mismatch in +");
Matrix result(rows_, cols_);
for (int k = 0; k < rows_ * cols_; k++) result.data_[k] = data_[k] + rhs.data_[k];
return result;
}
Matrix Matrix::operator-(const Matrix& rhs) const
{
if (rows_ != rhs.rows_ || cols_ != rhs.cols_)
throw std::invalid_argument("dimension mismatch in -");
Matrix result(rows_, cols_);
for (int k = 0; k < rows_ * cols_; k++) result.data_[k] = data_[k] - rhs.data_[k];
return result;
}
Matrix Matrix::operator*(const Matrix& rhs) const
{
if (cols_ != rhs.rows_)
throw std::invalid_argument("dimension mismatch in *");
Matrix result(rows_, rhs.cols_, 0.0);
for (int i = 0; i < rows_; i++)
for (int j = 0; j < rhs.cols_; j++)
for (int k = 0; k < cols_; k++)
result(i, j) += (*this)(i, k) * rhs(k, j);
return result;
}
bool Matrix::operator==(const Matrix& rhs) const
{
if (rows_ != rhs.rows_ || cols_ != rhs.cols_) return false;
for (int k = 0; k < rows_ * cols_; k++)
if (data_[k] != rhs.data_[k]) return false;
return true;
}
std::ostream& operator<<(std::ostream& os, const Matrix& m)
{
for (int i = 0; i < m.rows_; i++) {
for (int j = 0; j < m.cols_; j++)
os << m(i, j) << ' ';
os << '\n';
}
return os;
}
| Operation on $A,B$ (2×2, values 1–8) | Result |
|---|---|
| $A+B$ | [[6,8],[10,12]] |
| $A-B$ | [[-4,-4],[-4,-4]] |
| $A\times B$ | [[19,22],[43,50]] |
| $A==A$ (copy) | true |
Check: the question leaves error
handling on dimension mismatch unspecified; this answer assumes throwing
std::invalid_argument is acceptable (stated explicitly, as the
question allows freedom in "exact syntax of some of the above operations").