课程作业(五)


GitHub develop

因为类的.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语言的学习中有做过相关的题目,而在这次的四则运算程序就能够直接运用的就是表达式求值。栈的相关应用网络上资源很多,我就不再赘述。接下来,我以后缀表达式求值为示例体现一下栈在编程当中的实际应用。

后缀表达式求值的步骤:

  1. 初始化一个空操作数栈;
  2. 从前到后读取后缀表达式的元素。如果是操作数直接入栈;如果读到操作符,弹出栈顶元素a,对新的栈顶元素b,执行b 操作符 a,将结果压入栈中;
  3. 最后的栈顶元素即为表达式的值。

代码示例如下:

//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();
}

参考链接

关于栈及其应用示例
c++利用链表写一个简单的栈
栈的经典运用
栈和队列的应用举例
C++ 栈和队列的介绍与使用

posted @ 2017-05-22 21:43  Eventide  阅读(314)  评论(1编辑  收藏  举报