1.【描述】
编写程序,输入若干个正整数,输入-1时输入结束,可以简化修改本章教材提供的链表类LinkedList,用单向链表组织输入的正整数。要求链表按照结点中整数值的大小从大到小排序,不包括最后标识结束的-1。输出单向链表。
【输入】
一系列正整数,输入-1表示结束,-1不是输入的数据的一部分。
【输出】
按照结点中整数值的大小从大到小输出所有的整数,每个整数后面跟一个空格以与后面的整数区分,最后的整数后面没有空格。
【输入示例】
1 3 5 2 -1
【输出示例】
5 3 2 1
#include <iostream>
using namespace std;
template<typename T>
class Node {
public:
Node() {
next = NULL;
}
Node(const T &value) {
this->value = value;
next = NULL;
}
T value;
Node<T> *next;
};
template<typename T>
class LinkedList {
public:
LinkedList();
void add(const T &value);
void print() const;
private:
Node<T> *head;
int size;
};
template<typename T>
LinkedList<T>::LinkedList() {
head = NULL;
size = 0;
}
template<typename T>
void LinkedList<T>::add(const T &value) {
Node<T> *temp = new Node<T>(value);
Node<T> *current = head;
Node<T> *previous = NULL;
while (current != NULL && current->value > value) {
previous = current;
current = current->next;
}
if (current == head)
head = temp;
else
previous->next = temp;
temp->next = current;
++size;
}
template<typename T>
void LinkedList<T>::print() const {
Node<T> *current = head;
while (current != NULL) {
cout << current->value << " ";
current = current->next;
}
cout << endl;
}
int main() {
LinkedList<int> list;
int num;
cin >> num;
while (num > 0) {
list.add(num); // 输入的正整数按从大到小的顺序添加到链表中
cin >> num;
}
list.print(); // 输出链表
return 0;
}
2.
【描述】
栈可以应用于算术表达式求值。这里对算术表达式做如下简化:运算符为+、-、*、/、%;操作数为单数字(0~9)非负整数。
例如:
(2+5)*3-8/3
上述形式的算术表达式也称中缀表达式,因为每个运算符出现在它的两个操作数之间。编译器在求算术表达式值时,往往将中缀表达式转换为后缀表达式。后缀表达式也称逆波兰表达式,由波兰数学家Jan Lukasiewicz发明,指运算符出现在操作数后面的不含括号的算术表达式。
中缀表达式:a+b*c,其后缀表达式为:a b c * +。因为*的优先级比+高,所以先计算b*c,即b c *;+的操作数是a和b c *,即a b c * +。
中缀表达式:(a+b)*c,其后缀表达式为:a b + c *。先计算圆括号中a+b,即a b +;*的操作数是a b +和c,即a b + c *。
中缀表达式:(a*b+c)/d+e,其后缀表达式为:a b * c + d / e +。先计算圆括号中a*b+c,即a b * c +;/的操作数是a b * c +和d,即a b * c + d /;+的操作数是a b * c + d /和e,即a b * c + d / e +。
后缀表达式求值使用一个存放操作数的栈。求值过程顺序扫描后缀表达式,每次遇到操作数就将它入栈;遇到运算符时,就从栈中弹出两个操作数进行计算,并将结果入栈。到扫描结束,留在栈顶的操作数就是所求算术表达式的值。
例如:
4 2 7 *+
如下图一所示,顺序读取操作数4、2、7,并入栈。如下图二所示,读取运算符*,操作数7、2出栈,计算2*7,结果为14并入栈。如下图三所示,读取运算符+,操作数14、4出栈,计算4+14,结果为18并入栈。扫描后缀表达式后,栈中惟一元素即为最终结果。
本章教材组合向量类Vector实现了一个Stack类模板。请组合栈类Stack,声明并实现一个PostfixEvaluation类,求后缀表达式的值。PostfixEvaluation类包括:
- string类型的私有数据成员postfixExpression,存放后缀表达式。
- Stack类型的私有数据成员operandStack,存放操作数(单数字非负整数)。
- 私有成员函数getOperands,连续从栈顶出栈两个操作数。
- 私有成员函数calculate,求出栈的两个操作数的计算结果,并将结果入栈。
- 私有成员函数isOperator,确定输入的运算符是有效运算符(+、-、*、/、%)
- 有参构造函数。新建一个后缀表达式对象。
- 访问器函数getPostfixExpression,获取后缀表达式。
- 更改器函数setPostfixExpression,设置新的后缀表达式。
- 成员函数evaluate,计算并返回后缀表达式的值。
PostfixEvaluation类如下:
class PostfixEvaluation {
public:
PostfixEvaluation(const string&postfixExpression); // 构造函数
stringgetPostfixExpression() const; // 获取后缀表达式
void setPostfixExpression(const string&postfixExpression); // 设置后缀表达式
int evaluate(); // 计算并返回后缀表达式值
private:
string postfixExpression; // 存放要计算的后缀表达式
Stack<int> operandStack; // 存放操作数
void getOperands(int &left, int&right); // 操作数出栈
int calculate(int left, int right, char op) const; // 求操作数运算值
bool isOperator(char ch) const; // 是否是运算符
};
【输入】
输入一个后缀表达式。
【输出】
输出后缀表达式的值。
【输入示例1】
4 2 7 * +
【输出示例1】
18
【输入示例2】
8 4 0 % +
【输出示例2】
Divisor cannot be zero!
【输入示例3】
2 3 ^ 4 +
【输出示例3】
Illegal input!
【输入示例4】
4 2 / *
【输出示例4】
Too many operators!
【输入示例5】
1 2 3 +
【输出示例5】
Too many operands!
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
template <typename T>
class Vector {
public:
Vector(int size); // 构造函数
Vector(int size, const T &value); // 构造函数
Vector(const Vector<T> &v); // 拷贝构造函数
virtual ~Vector(); // 析构函数
const Vector<T> &operator=(const Vector<T> &right); // 重载赋值运算符
T &operator[](int index); // 重载下标运算符
T operator[](int index) const; // 重载下标运算符
int getSize() const;
void resize(int size);
private:
T *pVector; // 指针,指向存放数组元素的动态分配内存空间
int size; // 数组长度
};
template <typename T>
Vector<T>::Vector(int size) {
if (size > 0)
this->size = size;
else
throw invalid_argument("数组长度必须是正整数!");
pVector = new T[size];
}
template <typename T>
Vector<T>::Vector(int size, const T &value) {
if (size > 0)
this->size = size;
else
throw invalid_argument("数组长度必须是正整数!");
pVector = new T[size];
for (int i = 0; i < size; ++i)
pVector[i] = value;
}
template <typename T>
Vector<T>::Vector(const Vector<T> &v) {
size = v.size;
pVector = new T[size];
for (int i = 0; i < size; ++i)
pVector[i] = v.pVector[i];
}
template <typename T>
Vector<T>::~Vector() {
delete[] pVector;
}
template <typename T>
const Vector<T> &Vector<T>::operator=(const Vector<T> &right) {
if (this != &right) {
if (size != right.size) {
delete[] pVector;
size = right.size;
pVector = new T[size];
}
for (int i = 0; i < size; ++i)
pVector[i] = right.pVector[i];
}
return *this;
}
template <typename T>
T &Vector<T>::operator[](int index) {
if (index < 0 || index > size - 1)
throw out_of_range("数组下标超出允许范围!");
return pVector[index];
}
template <typename T>
T Vector<T>::operator[](int index) const {
if (index < 0 || index > size - 1)
throw out_of_range("数组下标超出允许范围!");
return pVector[index];
}
template <typename T>
int Vector<T>::getSize() const {
return size;
}
template <typename T>
void Vector<T>::resize(int size) {
if (size > 0) {
if (this->size != size) {
T *old = pVector;
pVector = new T[size];
int newSize = (this->size > size) ? size : this->size;
for (int i = 0; i < newSize; ++i)
pVector[i] = old[i];
this->size = size;
delete[] old;
}
} else
throw invalid_argument("数组长度必须是正整数!");
}
template <typename T>
class Stack {
public:
Stack(int size = 16); // 构造函数
Stack(const Stack<T> &v); // 拷贝构造函数
void clear(); // 将栈设置为空栈
bool isEmpty() const; // 判断栈是否为空
void push(T value); // 入栈
T pop(); // 出栈
T peek() const; // 获取栈顶元素
private:
Vector<T> data; // 存放栈元素
int top; // 记录栈顶位置
};
template <typename T>
Stack<T>::Stack(int size): data(size) {
clear();
}
template <typename T>
Stack<T>::Stack(const Stack<T> &v)
: data(v.data), top(v.top) { }
template <typename T>
void Stack<T>::clear() {
top = 0;
}
template <typename T>
bool Stack<T>::isEmpty() const {
return top == 0;
}
template <typename T>
void Stack<T>::push(T value) {
if (top >= data.getSize())
data.resize(2 * data.getSize());
data[top++] = value;
}
template <typename T>
T Stack<T>::pop() {
return data[--top];
}
template <typename T>
T Stack<T>::peek() const {
return data[top - 1];
}
class PostfixEvaluation {
public:
PostfixEvaluation(const string &postfixExpression); // 构造函数
string getPostfixExpression() const; // 获取后缀表达式
void setPostfixExpression(const string &postfixExpression); // 设置后缀表达式
int evaluate(); // 计算并返回后缀表达式值
private:
string postfixExpression; // 存放要计算的后缀表达式
Stack<int> operandStack; // 存放操作数
void getOperands(int &left, int &right); // 操作数出栈
int calculate(int left, int right, char op) const; // 求操作数运算值
bool isOperator(char ch) const; // 是否是运算符
};
void PostfixEvaluation::getOperands(int &left, int &right) {
if (operandStack.isEmpty())
throw runtime_error("Too many operators!");
right = operandStack.pop();
if (operandStack.isEmpty())
throw runtime_error("Too many operators!");
left = operandStack.pop();
}
int PostfixEvaluation::calculate(int left, int right, char op) const {
int value;
switch (op) {
case '+':
value = left + right;
break;
case '-':
value = left - right;
break;
case '*':
value = left * right;
break;
case '/':
if (right == 0)
throw runtime_error("Divisor cannot be zero!");
value = left / right;
break;
case '%':
if (right == 0)
throw runtime_error("Divisor cannot be zero!");
value = left % right;
break;
}
return value;
}
bool PostfixEvaluation::isOperator(char ch) const {
return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%';
}
PostfixEvaluation::PostfixEvaluation(const string &postfixExpression) {
this->postfixExpression = postfixExpression;
}
string PostfixEvaluation::getPostfixExpression() const {
return postfixExpression;
}
void PostfixEvaluation::setPostfixExpression(const string &postfixExpression) {
this->postfixExpression = postfixExpression;
}
int PostfixEvaluation::evaluate() {
int left, right, value;
char ch;
for (string::size_type i = 0; i < postfixExpression.size(); ++i) {
ch = postfixExpression[i];
if (isdigit(ch))
operandStack.push(ch - '0');
else if (isOperator(ch)) {
getOperands(left, right);
operandStack.push(calculate(left, right, ch));
} else if (!isspace(ch))
throw runtime_error("Illegal input!");
}
value = operandStack.pop();
if (!operandStack.isEmpty())
throw runtime_error("Too many operands!");
return value;
}
int main() {
string expression;
getline(cin, expression);
PostfixEvaluation exp(expression);
try {
cout << exp.evaluate() << endl;
} catch (runtime_error &ex) {
cout << ex.what() << endl;
}
return 0;
}
3.
【描述】
矩阵是数学里的一种抽象对象,可以用C++提供的静态数组来表示矩阵,其大小在编译时就已经确定,在运行时无法修改,而且不检查下标是否越界。可以利用教材本章提供的向量类Vector,用向量的方式实现矩阵,用一个指针向量来表示矩阵,其中的每个指针又各指向一个向量,用它们来表示矩阵的行向量。矩阵的逻辑结构如下图所示。
组合向量类Vector,声明并实现一个Matrix类模板,表示矩阵。Matrix类模板包括:
- Vector类型的私有数据成员rows,存放矩阵元素。
- 构造函数,将矩阵的行、列大小设置为给定的参数。
- 构造函数,将矩阵的行、列大小设置为给定的参数,给矩阵元素赋相同的初始值。
- 重载下标运算符[]。
- 访问器函数getRows,用于获取矩阵行数。
- 访问器函数getColumns,用于获取矩阵列数。
Matrix类模板如下:
template <typename T>
class Matrix {
public:
Matrix(int row, int column);
Matrix(int row, int column, const T &value);
Vector<T> &operator[](int index);
Vector<T> operator[](int index) const;
int getRows() const;
int getColumns() const;
private:
Vector<Vector<T>*> rows; // 存放矩阵元素
};
以普通函数的形式重载*运算符函数,实现矩阵乘法。
template <typename T>
Matrix<T> operator*(const Matrix<T> &lhs, const Matrix<T> &rhs);
printMatrix函数输出矩阵的值。
template <typename T>
void printMatrix(const Matrix<T> &m);
【输入】
输入3×3矩阵a和矩阵b。
【输出】
矩阵a乘以矩阵b的结果。每个元素输出宽度为4。
【输入示例】
1 1 7
7 5 6
9 6 1
6 1 6
4 1 5
1 5 1
【输出示例】
17 37 18 68 42 73 79 20 85
#include <iostream>
#include <iomanip>
#include <stdexcept>
using namespace std;
template <typename T>
class Vector {
public:
Vector(int size); // 构造函数
Vector(int size, const T &value); // 构造函数
Vector(const Vector<T> &v); // 拷贝构造函数
virtual ~Vector(); // 析构函数
const Vector<T> &operator=(const Vector<T> &right); // 重载赋值运算符
T &operator[](int index); // 重载下标运算符
T operator[](int index) const; // 重载下标运算符
int getSize() const;
void resize(int size);
private:
T *pVector; // 指针,指向存放数组元素的动态分配内存空间
int size; // 数组长度
};
template <typename T>
Vector<T>::Vector(int size) {
if(size > 0)
this->size = size;
else
throw invalid_argument("数组长度必须是正整数!");
pVector = new T[size];
}
template <typename T>
Vector<T>::Vector(int size, const T &value) {
if(size > 0)
this->size = size;
else
throw invalid_argument("数组长度必须是正整数!");
pVector = new T[size];
for(int i = 0; i < size; ++i)
pVector[i] = value;
}
template <typename T>
Vector<T>::Vector(const Vector<T> &v) {
size = v.size;
pVector = new T[size];
for(int i = 0; i < size; ++i)
pVector[i] = v.pVector[i];
}
template <typename T>
Vector<T>::~Vector() {
delete[] pVector;
}
template <typename T>
const Vector<T> &Vector<T>::operator=(const Vector<T> &right) {
if(this != &right) {
if(size != right.size) {
delete[] pVector;
size = right.size;
pVector = new T[size];
}
for(int i = 0; i < size; ++i)
pVector[i] = right.pVector[i];
}
return *this;
}
template <typename T>
T &Vector<T>::operator[](int index) {
if(index < 0 || index > size - 1)
throw out_of_range("数组下标超出允许范围!");
return pVector[index];
}
template <typename T>
T Vector<T>::operator[](int index) const {
if(index < 0 || index > size - 1)
throw out_of_range("数组下标超出允许范围!");
return pVector[index];
}
template <typename T>
int Vector<T>::getSize() const {
return size;
}
template <typename T>
void Vector<T>::resize(int size) {
if(size > 0) {
if(this->size != size) {
T *old = pVector;
pVector = new T[size];
int newSize = (this->size > size) ? size : this->size;
for(int i = 0; i < newSize; ++i)
pVector[i] = old[i];
this->size = size;
delete[] old;
}
}
else
throw invalid_argument("数组长度必须是正整数!");
}
template <typename T>
class Matrix {
public:
Matrix(int row, int column);
Matrix(int row, int column, const T &value);
Vector<T> &operator[](int index);
Vector<T> operator[](int index) const;
int getRows() const;
int getColumns() const;
private:
Vector<Vector<T>*> rows; // 存放矩阵元素
};
template <typename T>
Matrix<T>::Matrix(int row, int column): rows(row) {
for (int i = 0; i < row; ++i)
rows[i] = new Vector<T>(column);
}
template <typename T>
Matrix<T>::Matrix(int row, int column, const T &value): rows(row) {
for (int i = 0; i < row; ++i) {
rows[i] = new Vector<T>(column, value);
}
}
template <typename T>
Vector<T> &Matrix<T>::operator[](int index) {
return *rows[index];
}
template <typename T>
Vector<T> Matrix<T>::operator[](int index) const {
return *rows[index];
}
template <typename T>
int Matrix<T>::getRows() const {
return rows.getSize();
}
template <typename T>
int Matrix<T>::getColumns() const {
return rows[0]->getSize();
}
template <typename T>
Matrix<T> operator*(const Matrix<T> &lhs, const Matrix<T> &rhs) {
int lhsRow = lhs.getRows();
int lhsColumn = lhs.getColumns();
int rhsColumn = rhs.getColumns();
Matrix<T> result(lhsRow, rhsColumn, 0);
for (int i = 0; i < lhsRow; ++i) {
for (int j = 0; j < rhsColumn; ++j) {
for (int k = 0; k < lhsColumn; ++k)
result[i][j] += lhs[i][k] * rhs[k][j];
}
}
return result;
}
template <typename T>
void printMatrix(const Matrix<T> &m) {
int row = m.getRows();
int column = m.getColumns();
for (int i = 0; i < row; ++i) {
for (int j = 0; j < column; ++j)
cout << setw(4) << m[i][j];
cout << endl;
}
}
int main() {
const int ROW_SIZE = 3;
const int COLUMN_SIZE = 3;
Matrix<int> a(ROW_SIZE, COLUMN_SIZE);
Matrix<int> b(ROW_SIZE, COLUMN_SIZE);
for(int i = 0; i < ROW_SIZE; ++i) {
for(int j = 0; j < COLUMN_SIZE; ++j) {
cin >> a[i][j];
}
}
for(int i = 0; i < ROW_SIZE; ++i) {
for(int j = 0; j < COLUMN_SIZE; ++j) {
cin >> b[i][j];
}
}
printMatrix(a * b);
return 0;
}
4.【描述】
给定一个链表,链表的每个节点只含有一个int型元素和Node*指针,该链表共有十个节点,输出链表元素值为奇数的项。部分代码已经写好,请补全output函数即可。
【输入】
输入10个整数。
【输出】
输出奇数值,以空格隔开。
【输入示例】
1 3 4 5 6 7 8 10 11 15
【输出示例】
1 3 5 7 11 15
#include <iostream>
using namespace std;
class Node {
public:
int value;
Node *next;
Node() { }
Node(int x) : value(x), next(NULL) { }
};
class SingleLinkedList {
public:
SingleLinkedList() {
head = NULL;
}
void init() { // 链表初始化
int val;
cin >> val;
head = new Node(val);
Node *tmpNode = head;
for (int i = 0; i < 9; i++) { // 链表共有10个节点,head后还有9个
cin >> val;
Node *pNode = new Node(val);
tmpNode->next = pNode;
tmpNode = pNode;
}
tmpNode->next = NULL;
}
void output() { // 输出链表
Node *p = head;
while (p != NULL) {
if (p->value % 2 != 0)
cout << p->value << " ";
p = p->next;
}
}
private:
Node *head;
};
int main() {
SingleLinkedList list;
list.init();
list.output();
return 0;
}
5.【描述】
本章教材组合向量类Vector实现了一个Stack类模板。也可以用链表的方式实现栈。利用本章教材提供的链表类LinkedList,组合链表类LinkedList来实现一个新的Stack类模板。
template <typename T>
class Stack {
public:
Stack();
void clear();
bool isEmpty() const;
void push(const T &value);
T pop();
T peek() const;
private:
LinkedList<T> data;
};
【输入】
一系列正整数并入栈,输入-1表示结束,-1不是输入的数据的一部分。
【输出】
输出栈中所有的整数,每个整数后面跟一个空格以与后面的整数区分。
【输入示例】
1 3 5 2 -1
【输出示例】
2 5 3 1
#include <iostream>
#include <stdexcept>
using namespace std;
template <typename T>
class Node {
public:
Node() {
next = NULL;
}
Node(const T &value) {
this->value = value;
next = NULL;
}
T value;
Node<T> *next;
};
template <typename T>
class LinkedList {
public:
LinkedList();
void addFirst(const T &value);
void addLast(const T &value);
void add(int index, const T &value);
void removeFirst();
void removeLast();
void removeAt(int index);
T getFirst() const;
T getLast() const;
void clear();
bool isEmpty() const;
int getSize() const;
void print() const;
private:
Node<T> *head, *tail;
int size;
};
template <typename T>
LinkedList<T>::LinkedList() {
head = tail = NULL;
size = 0;
}
template <typename T>
void LinkedList<T>::addFirst(const T &value) {
Node<T> *temp = new Node<T>(value);
temp->next = head;
head = temp;
++size;
if (tail == NULL)
tail = head;
}
template <typename T>
void LinkedList<T>::addLast(const T &value) {
if (tail == NULL)
head = tail = new Node<T>(value);
else {
tail->next = new Node<T>(value);
tail = tail->next;
}
++size;
}
template <typename T>
void LinkedList<T>::add(int index, const T &value) {
if (index == 0)
addFirst(value);
else if (index >= size)
addLast(value);
else {
Node<T> *current = head;
for (int i = 1; i < index; ++i)
current = current->next;
Node<T> *temp = current->next;
current->next = new Node<T>(value);
current->next->next = temp;
++size;
}
}
template <typename T>
void LinkedList<T>::removeFirst() {
if (head == NULL)
throw runtime_error("空链表!");
else {
Node<T> *temp = head;
head = head->next;
if (head == NULL)
tail = NULL;
delete temp;
--size;
}
}
template <typename T>
void LinkedList<T>::removeLast() {
if (tail == NULL)
throw runtime_error("空链表!");
else if (head == tail) {
Node<T> *temp = head;
head = tail = NULL;
size = 0;
delete temp;
} else {
Node<T> *current = head;
while (current->next != tail)
current = current->next;
Node<T> *temp = tail;
tail = current;
tail->next = NULL;
delete temp;
--size;
}
}
template <typename T>
void LinkedList<T>::removeAt(int index) {
if (index < 0 || index >= size)
throw runtime_error("下标越界!");
else if (index == 0)
return removeFirst();
else if (index == size - 1)
return removeLast();
else {
Node<T> *previous = head;
for (int i = 1; i < index; ++i)
previous = previous->next;
Node<T> *current = previous->next;
previous->next = current->next;
delete current;
--size;
}
}
template <typename T>
T LinkedList<T>::getFirst() const {
if (head == NULL)
throw runtime_error("空链表!");
else
return head->value;
}
template <typename T>
T LinkedList<T>::getLast() const {
if (tail == NULL)
throw runtime_error("空链表!");
else
return tail->value;
}
template <typename T>
void LinkedList<T>::clear() {
while (head != NULL) {
Node<T> *temp = head;
head = head->next;
delete temp;
}
tail = NULL;
}
template <typename T>
bool LinkedList<T>::isEmpty() const {
return head == NULL;
}
template <typename T>
int LinkedList<T>::getSize() const {
return size;
}
template <typename T>
void LinkedList<T>::print() const {
Node<T> *current = head;
while (current != NULL) {
cout << current->value << " ";
current = current->next;
}
cout << endl;
}
/* 请在此处编写Stack类 */
template <typename T>
class Stack {
public:
Stack();
void clear();
bool isEmpty() const;
void push(const T &value);
T pop();
T peek() const;
private:
LinkedList<T> data;
};
template <typename T>
Stack<T>::Stack() { }
template <typename T>
void Stack<T>::clear() {
data.clear();
}
template <typename T>
bool Stack<T>::isEmpty() const {
return data.isEmpty();
}
template <typename T>
void Stack<T>::push(const T &value) {
data.addLast(value);
}
template <typename T>
T Stack<T>::pop() {
T temp = data.getLast();
data.removeLast();
return temp;
}
template <typename T>
T Stack<T>::peek() const {
return data.getLast();
}
int main() {
Stack<int> intStack;
int num;
cin >> num;
while (num != -1) {
intStack.push(num);
cin >> num;
}
while (!intStack.isEmpty())
cout << intStack.pop() << " ";
cout << endl;
return 0;
}