课程作业(五)
因为类的.cpp部分太长,这里仅贴出Fraction类的完整代码。
类图编码(框架)
这里贴出VS资源管理器的源文件和头文件的截图作为框架的大致展现,.h文件和.cpp文件对应分离。具体可看上一篇的头文件实现和GitHub。
类图编码(Fraction类)
由于代码过长,无法全部粘贴,这里只贴出Fraction类的代码,其余部分可在GitHub中查看。
/*************************************************************
文件名:fraction.h
作者:许郁杨 日期:2017/05/07
描述: fraction.cpp对应头文件
*************************************************************/
#pragma once
#include"assistant_functions.h"
#include<iostream>
using namespace std;
class Fraction
{
private:
int m_nnumerator;
int m_ndenominator;
string m_snumerator;
string m_sdenominator;
public:
Fraction();
void GetFraction(int l, int h);
bool isDivisorZero();
bool IsInt();
void TransferIntIntoFraction(int up, int down);
void Simplify();
string TransferIntoStringNoInt();
string TransferIntoString();
friend const Fraction operator +(Fraction frac1, Fraction frac2);
friend const Fraction operator -(Fraction frac1, Fraction frac2);
friend const Fraction operator *(Fraction frac1, Fraction frac2);
friend const Fraction operator /(Fraction frac1, Fraction frac2);
};
/*************************************************************
文件名:fraction.cpp
作者:许郁杨 日期:2017/05/07
描述: 分数类
主要功能包括:分数的生成、转换和四则运算
作者:许郁杨 日期:2017/05/10
更新:补充了注释,对格式排版进行一些调整
*************************************************************/
#include"fraction.h"
#include<iostream>
#include<sstream>
using namespace std;
Fraction::Fraction() { }
/*生成分数 日期:2017/05/07*/
void Fraction::GetFraction(int l, int h)
{
int ntmp1 = 0, ntmp2 = 0;
stringstream sstmp1, sstmp2;
while (Max(ntmp1, ntmp2) == 0)
{
ntmp1 = RandomNumber(l, h);
ntmp2 = RandomNumber(l, h);
}
m_nnumerator = Min(ntmp1, ntmp2);
m_ndenominator = Max(ntmp1, ntmp2);
sstmp1 << m_nnumerator;
sstmp1 >> m_snumerator;
sstmp2 << m_ndenominator;
sstmp2 >> m_sdenominator;
}
/*检查除数是否为零,是为true,否为false 日期:2017/05/07
更新:格式调整 日期:2017/05/10*/
bool Fraction::isDivisorZero()
{
if (m_nnumerator == 0)
{
return true;
}
else
{
return false;
}
}
/*检查是否可化简整数,是为true,否为false 日期:2017/05/07
更新:注释补充,格式调整 日期:2017/05/10*/
bool Fraction::IsInt()
{
if (m_ndenominator == 1)//如果除数为一,即可化简为整数
{
return true;
}
else//如果不可化简为整数
{
return false;
}
}
/*将整数转换为分数形式 日期:2017/05/07*/
void Fraction::TransferIntIntoFraction(int up, int down)
{
stringstream sstmp1, sstmp2;
m_nnumerator = up;
m_ndenominator = down;
sstmp1 << m_nnumerator;
sstmp1 >> m_snumerator;
sstmp2 << m_ndenominator;
sstmp2 >> m_sdenominator;
sstmp1.clear();
sstmp2.clear();
}
/*化简分数 日期:2017/05/07
更新:注释补充,格式调整 日期:2017/05/10*/
void Fraction::Simplify()
{
int ntmp;
stringstream sstmp1, sstmp2;
if (m_ndenominator < 0)//如果分母为负数
{
m_ndenominator = -m_ndenominator;
m_nnumerator = -m_nnumerator;
}
if (m_nnumerator == 0)//如果分子为零
{
m_ndenominator = 1;
}
else
{
ntmp = GreatestCommonDivisor(abs(m_ndenominator), abs(m_nnumerator));
m_nnumerator /= ntmp;
m_ndenominator /= ntmp;
}
sstmp1 << m_nnumerator;
sstmp1 >> m_snumerator;
sstmp2 << m_ndenominator;
sstmp2 >> m_sdenominator;
sstmp1.clear();
sstmp2.clear();
}
/*将分数转换为字符串形式(不区分整数) 日期:2017/05/07*/
string Fraction::TransferIntoStringNoInt()
{
return "(" + m_snumerator + "\\" + m_sdenominator + ")";
}
/*将分数转换为字符串形式(区分整数) 日期:2017/05/07
更新:注释补充,格式调整 日期:2017/05/10*/
string Fraction::TransferIntoString()
{
if (m_ndenominator == 1)//如果分母为一
{
return m_snumerator;
}
else
{
return "(" + m_snumerator + "\\" + m_sdenominator + ")";
}
}
/*重载加法运算符 日期:2017/05/07*/
const Fraction operator +(Fraction frac1, Fraction frac2)
{
Fraction answer;
answer.m_nnumerator = frac1.m_nnumerator*frac2.m_ndenominator + frac1.m_ndenominator*frac2.m_nnumerator;
answer.m_ndenominator = frac1.m_ndenominator*frac2.m_ndenominator;
answer.Simplify();
return answer;
}
/*重载减法运算符 日期:2017/05/07*/
const Fraction operator -(Fraction frac1, Fraction frac2)
{
Fraction answer;
answer.m_nnumerator = frac1.m_nnumerator*frac2.m_ndenominator - frac1.m_ndenominator*frac2.m_nnumerator;
answer.m_ndenominator = frac1.m_ndenominator*frac2.m_ndenominator;
answer.Simplify();
return answer;
}
/*重载乘法运算符 日期:2017/05/07*/
const Fraction operator *(Fraction frac1, Fraction frac2)
{
Fraction answer;
answer.m_nnumerator = frac1.m_nnumerator*frac2.m_nnumerator;
answer.m_ndenominator = frac1.m_ndenominator*frac2.m_ndenominator;
answer.Simplify();
return answer;
}
/*重载除法运算符 日期:2017/05/07*/
const Fraction operator /(Fraction frac1, Fraction frac2)
{
Fraction answer;
answer.m_nnumerator = frac1.m_nnumerator*frac2.m_ndenominator;
answer.m_ndenominator = frac1.m_ndenominator*frac2.m_nnumerator;
answer.Simplify();
return answer;
}
栈的定义
栈作为一种常见的数据结构,其最主要的特点为后进先出(区别于队列的先进先出)。栈与线性表类似,都可以用数组和链表两种方式来实现。通常情况下,我们用数组来进行栈的实现。
需要注意的是,栈无法遍历。
栈的结构特点如下图所示:
标准库的栈
下面对c++ STL中的栈(stack)的用法进行一定说明。
头文件:#include< stack >;
声明:stack<类型> 变量名;
push(a)
在栈顶压入新元素a;
pop()
出栈;
empty()
判断栈是否为空,如果栈为空返回true,否则返回false;
size()
返回栈中元素的个数;
top()
返回栈顶元素;
示例:
#include<iostream>
#include<stack>
using namespace std;
int main()
{
stack<int> a;
a.push(1);//进栈
a.push(2);
a.pop();//出栈
cout << a.top() << endl;//返回栈顶元素
cout << a.size() << endl;//返回栈中元素的个数
cout << a.empty() << endl;//判断栈是否为空,如果栈为空返回true,否则返回false
return 0;
}
栈的代码实现(数组)
class Stack
{
private:
int *m_data;
int m_point;
public:
Stack();
bool push(int n);
bool pop();
bool empty();
int top();
int size();
};
Stack::Stack()
{
m_data = new int[1000];
}
bool Stack::push(int n)
{
if (m_point < 1000)
{
m_data[m_point] = n;
m_point++;
return true;
}
else
{
return false;
}
}
bool Stack::pop()
{
if (m_point > 0)
{
m_point--;
return true;
}
else
{
return false;
}
}
bool Stack::empty()
{
if (m_point == 0)
{
return true;
}
else
{
return false;
}
}
int Stack::size()
{
return m_point;
}
int Stack::top()
{
if (!empty())
{
return m_data[m_point - 1];
}
else
{
return -1;
}
}
栈的代码实现(链表)
class Stack
{
private:
struct Node
{
int data;
Node *next;
};
Node *m_head;
Node *m_present;
int m_size;
public:
Stack()
{
m_head = NULL;
m_size = 0;
}
void push(int n);
bool pop();
bool empty();
int top();
int size();
};
void Stack::push(int n)
{
Node *tmp = new Node;
tmp->data = n;
if (m_head == NULL)
{
tmp->next = m_head;
m_head = tmp;
m_present = tmp;
}
else
{
tmp->next = m_present;
m_present = tmp;
}
m_size++;
}
bool Stack::pop()
{
if (m_size <= 0)
{
return false;
}
else
{
Node *tmp;
int data;
tmp = m_present;
data = m_present->data;
m_present = m_present->next;
delete(tmp);
m_size--;
return true;
}
}
bool Stack::empty()
{
if (m_size == 0)
{
return true;
}
else
{
return false;
}
}
int Stack::size()
{
return m_size;
}
int Stack::top()
{
if (!empty())
{
return m_present->data;
}
else
{
return -1;
}
}
栈的简单应用示例
栈在算法中的基本应用主要是数制转换、符号匹配检查、表达式求值、行编辑以及二叉树的遍历。其中,符号匹配在之前c语言的学习中有做过相关的题目,而在这次的四则运算程序就能够直接运用的就是表达式求值。栈的相关应用网络上资源很多,我就不再赘述。接下来,我以后缀表达式求值为示例体现一下栈在编程当中的实际应用。
后缀表达式求值的步骤:
- 初始化一个空操作数栈;
- 从前到后读取后缀表达式的元素。如果是操作数直接入栈;如果读到操作符,弹出栈顶元素a,对新的栈顶元素b,执行b 操作符 a,将结果压入栈中;
- 最后的栈顶元素即为表达式的值。
代码示例如下:
//string postfix;
int CalculateResult()
{
int i = 0;
stack<int> numberStack;
while (postfix[i] != '\0')
{
if ((postfix[i] >= '0') && (postfix[i] <= '9'))
{
double k = 0;
while ((postfix[i] >= '0') && (postfix[i] <= '9'))
{
k = 10 * k + postfix[i] - '0';
i++;
}
numberStack.push(k);
}
else
{
int tmp = numberStack.top();
switch (postfix[i])
{
case '+':
{
numberStack.push(tmp + numberStack.top());
break;
}
case '-':
{
numberStack.push(tmp - numberStack.top());
break;
}
case '*':
{
numberStack.push(tmp * numberStack.top());
break;
}
case '/':
{
numberStack.push(tmp / numberStack.top());
}
}
}
i++;
}
return numberStack.top();
}