作业一:一元多项式的相加
单链表
申请一个结点
typedef struct node
{
DataType data; //数据域
struct node *next; //指针域
}Node,*Link;
//用typedef去声明结构体时,Node和*Link两个位置就被定义成了类型
Node st; //struct node st;
Link p; //struct node *p; //p是一个指向结构体的指针
申请结点
p=(Link)malloc(sizeof(Node));
sizeof(node); //计算出node结点的大小
malloc(sizeof(Node)); //用malloc分配给Link这么大的空间 malloc返回函数时viod*
分配地址以后,其把首地址分配给了指针p,在使用这块空间的时候,需要对这块地址进行强制转换。转换成指针p希望看到的类型。
指针p是一个Link类型,所以把malloc也定义成Link类型
链表的实现
单链表的遍历操作
操作接口:void displayNode(Link head);
void displayNode(Link head)
{
p= head->next;
while(p!=NULL)
{
cout<<p->next<<endl;
p = p->next;
}
}
求单链表的元素个数
操作接口:int length(Link head);
int length(Link head){
p = head->next; //p指向头指针的next域
count = 0; //count的数值为零
while(p!=NULL)
{
p = p->next; //如果p不为空,则p指向下一个结点的 // next域
count++;
}
return count; //注意count和初始化返回值之间的关系
}
单链表的查找操作
int queryNode(Link head,DaraType x){
p = head->next;
count = 0;
while(p!=NULL)
{
if(p—>data==x)
{
cout<<data<<endl; //找到则调用输出函数,并提 //前返回true
return true;
}
p = p->next;
}
//如果链表结束,说明没有找到
return false;
}
单链表的插入操作
操作接口:void insertNode(Link head,int i,DataType x);
node = (Link)malloc(sizeof(Node)); //申请一个结点node
node->data = x; //结点的数据域是x
node -> next = p->next; //p的next域赋给node的 //next域
p->next = node; //将node的数据域赋值给p的next域
-
工作指针p初始化
-
查找第i-1个结点并使用、工作指针p指向该结点
-
若查找不成功,则返回false
3.1生成一个元素值为x的新结点;
3.2将新结点s插入到结点p之后;
3.3返回true;
bool insertNode(Link head,int i,DataType x)
{
p = head; //工作指针p指向头结点
count = 0;
while (p!=NULL&&count<i-1) //查找第i-1个结点
{
p=p->next;
count++;
}
if(p==NULL)
return false; //没有找到第i-1个结点
else{
node = (Link)malloc(sizeof(Node));//申请一个结点 //node
node->data=x;
node->next=p->next; //结点node插入结点p之后
p->next=node;
return ture;
}
}
创建一个单链表—头插法
操作接口:Link newList(DataType a[],int n)
头插法:将待插入结点插在头结点的后面。
初始化头结点
head = (Link)malloc(sizeof(Node));
head->next=NULL;
插入第一个元素
node = (Link)malloc(sizeof(Node));
node->data=a[0];
node->next=head->next;
head->next=node;
node = (Link)malloc(sizeof(Node));
node->data=a[1];
node->next=head->next;
head->next=node;
template <class DataType>
Link newList(DataType a[],int n)
{
head=(Link)malloc(sizeof(Node));
head->next=NULL;
//创建后续结点
for(i = 0; i < n;i++)
{
node = (Link)malloc(sizeof(Node));
node->data = a[i];
node->next = head->next;
head->next = node;
}
return head;
}
单链表结点的删除
操作接口:bool deleteNode(Link head, Datatype x);
q->next = p->next;
free(p);
将q的next域指向p的next域,将被删除的p空间释放。
查找结点
在查找过程中,如果发现p所指向的结点data值不是要找的x,则p,q同时后移;一旦找到则执行删除操作
查找到p结点并将其删除
1.如何找到p结点。
2.如何保证p,q指针一前一后。
初始化
p = head->next;
q = head;
指针移动一次
q = p;
p = p->next;
删除中的特殊情况
在查找过程中,如果一直没有找到data域为x的结点,或者发现待删除的表是空表,则提前返回false
if(head==NULL||head->next==NULL){
return false;
}
单链表的删除
1.判断是否是空表,如果是空表返回false;
2.工作指针p,q初始化
3.若p指针不为空,则继续下列循环:
3.1如果找到data域等于x的结点,则:
3.1.1摘链,将结点p的从链表上摘下来
3.1.2释放别删除的结点
3.1.3提前返回true,代表删除成功
4.循环结束了,说明没有找到和x相等的结点,则返回false
bool deleteNode(Link head,DataType x){
if(head==NULL||head->next==NULL){
return false;
}
p=head->next;
q=head;
while(p!=NULL){
if(p->data==x){
q->next=p->next;
free(p); //单链表的释放
return true;
}
else{
q = p;
p = p->next;
}
}
//如果循环结束了,说明没有找到和x相关的结点
return false;
}
一元多项式的相加
题目描述:
实现两个一元n次多项式的加法。例如P(A)=x+3x2-5x5+7,P(B)=2x2+6x3+x5-4x6,求P(A)+P(B)。
首先弄清楚一元多项式的加法原理,然后明确多项式的存储方法。链表节点存储系数和指数,只存系数非0的项。
输入二项式数据的函数
给用户合适的提示,读入用户输入的系数和指数。
调用函数insert,将用户输入的二项式的一项插入到链表中去。
代码实现
void inputPoly(Link head)
{
int coefficient, exp;//系数和指数
cout << "请输入系数和指数(如:\"2 3\"表示2x^3):" << endl;
cin >> coefficient>>exp;
while (coefficient != 0 || exp != 0)//连续输入多个系数和指数
{
insert(head, coefficient, exp);//调函数输入多项式
cout << "请输入系数和指数" << endl;
cin >> coefficient>>exp;
}
}
向多项式链表中插入元素的函数
int coefficient 一个多项式项的系数
int exp 一个多项式项的幂
代码实现
bool insert(Link head, int coefficient, int exp)
{
Link node; //node指针指向新创建的节点
Link q, p; //q,p两个节点一前一后
//创建一个新结点
q = head;
p = head->next;
node = (Link)malloc(sizeof(Node));
node->coefficient = coefficient;
node->exp = exp;
node->next = NULL;
if (head->next == NULL)//空表,插第1个
{
head->next = node;
}
else
{
while (p != NULL) {
if (exp == p->exp) {
p->coefficient += coefficient;
return true;
}
//大于当前次数
else if (exp > p->exp) {
q->next = node;
node->next = p;
return true;
}
else {
q = p;
p = p->next;
}
}
if (p == NULL) {
q->next = node;
node->next = NULL;
return true;
}
//如果退出循环是当前指针p移动到链表结尾,则说明之前没有插入,那么当前node节点的指数值是最大值,此时插在链表的最后面
}
return true;
}
多项式的输出
数字转换为字符串函数itoa
标志是否为第一个节点的flag的设置
字符串连接函数strcat
字符串清空函数memset。memset(item,0,20);清空长20的字符串item
代码实现
void Cout(Link head) {
Link p; //指向链表要输出的结点
cout << "多项式如下" << endl;
p = head->next;
if (p == NULL) {
cout << "多项式为空" << endl;
return;
}
// 不是空表
char item[20] = ""; //要打印的当前多项式的一项
char number[7] = ""; //暂时存放系数转换成的字符串
bool isFirstItem = true;//标志是否为第一个节点的flag
int flag = 0;
//打印节点
while (p != NULL) {
memset(item, 0, 20); //清空字符串item
_itoa_s(p->coefficient, number, 10);
if (p->coefficient == 0) {//当为0时的判断非常容易出错
if (flag == 0) {
isFirstItem = true; //如果第一项系数为0,移动指针,判断仍为true
p = p->next;
continue;
}
else if (flag == 1) {
p = p->next;
continue;
}
}
else {
if (isFirstItem != true && p->coefficient > 0) {
strcat_s(item, "+");
}
if (p->coefficient == 1) {}
else if (p->coefficient == -1) {
strcat_s(item, "-");
}
else if (p->coefficient != 0) {
strcat_s(item, number);
}
if (p->exp == 1) {
strcat_s(item, "x");
}
else if (p->exp == 0) {
if (p->coefficient == 1 || p->coefficient == -1)
strcat_s(item, "1");
}
else {
strcat_s(item, "x^");
_itoa_s(p->exp, number, 10);
strcat_s(item, 20,number);
//strcat_s(item, _itoa_s(p->exp, number, 10));
}
flag = 1;
}
cout << item ;//打印当前节点代表的项
p = p->next;//指向下个结点
isFirstItem = false; //flag标志不是第一项了
}
cout << endl;
return;
}
链表合并
合并两个有序链表a,b到链表ab
heada.headb,headab分别为链表a,b,ab的头指针
代码实现
void combin2List(Link heada, Link headb, Link headab)
{
Link pa, pb;//指向a,b链表和ab的指针
pa = heada->next;
pb = headb->next;
while (pa != NULL && pb != NULL)//a,b链表都没有没有访问完毕
{
//如果指数a>指数b,a节点插入ab链表,a指针后移
if (pa->exp > pb->exp) {
insert(headab, pa->coefficient, pa->exp);
pa = pa->next;
}
//如果指数a<指数b,b节点插入ab链表,b指针后移
else if (pa->exp < pb->exp) {
insert(headab, pb->coefficient, pb->exp);
pb = pb->next;
}
//如果指数a==指数b,a、b系数相加,插入ab链表,a、b指针后移
else if (pa->exp == pb->exp) {
int coefficient;//系数
coefficient = pa->coefficient + pb->coefficient;
insert(headab, coefficient, pa->exp);
pa = pa->next;
pb = pb->next;
}
//如果a,b链表后还有尾巴,则加到链表后面 是否可以去掉
while (pa != NULL) {
insert(headab, pa->coefficient, pa->exp);
pa = pa->next;
}
while (pb != NULL) {
insert(headab, pb->coefficient, pb->exp);
pb = pb->next;
}
return;
}
//如果a、b链表还有尾巴,将它加到ab链表后面
while (pa != NULL)
{
insert(headab, pa->coefficient, pa->exp);
pa = pa->next;
}
while (pb != NULL)
{
insert(headab, pb->coefficient, pb->exp);
pb = pb->next;
}
return;
}
释放空间
在main函数中一定不能忘记释放空间
代码实现
void clearLink(Link head) {
Link p, q;
if (head == NULL)
return;
q = head->next;
free(head);
while (q != NULL) {
p = q;
q = q->next;
free(p);
}
}
定义结点
其中,数据域包含指数和系数,还有一个指向下一个结点的指针
代码实现
typedef struct PNode
{
int coefficient;//系数
int exp;//指数
struct PNode* next;
}*Link, Node;
示例
请输入第一个多项式的系数和指数,以(0 0)结束:
请输入系数和指数(如:"2 3"表示2x^3):1 1
请输入系数和指数:-1 1
请输入系数和指数:2 2
请输入系数和指数:0 0
第一个多项式如下:
2x^2
请输入第二个多项式的系数和指数,以(0 0)结束:
请输入系数和指数(如:"2 3"表示2x^3):-2 2
请输入系数和指数:2 3
请输入系数和指数:4 5
请输入系数和指数:0 0
第二个多项式如下:
4x^5+2x^3-2x^2
合并后多项式如下:
4x^5+2x^3
输入
示例
请输入第一个多项式的系数和指数,以(0 0)结束:
请输入系数和指数(如:2 3表示2x^3):4 2
请输入系数和指数:-3 3
请输入系数和指数:-1 1
请输入系数和指数:2 0
请输入系数和指数:0 0
第一个多项式如下:
-3x^3+4x^2-x+2
请输入第二个多项式的系数和指数,以(0 0)结束:
请输入系数和指数(如:2 3表示2x^3):4 5
请输入系数和指数:3 3
请输入系数和指数:-3 1
请输入系数和指数:0 0
第二个多项式如下:
4x^5+3x^3-3x
合并后多项式如下:
4x^5+4x^2-4x+2
示例
请输入第一个多项式的系数和指数,以(0 0)结束:
请输入系数和指数(如:2 3表示2x^3):3 5
请输入系数和指数:3 4
请输入系数和指数:-3 0
请输入系数和指数:1 4
请输入系数和指数:0 0
第一个多项式如下:
3x^5+4x^4-3
请输入第二个多项式的系数和指数,以(0 0)结束:
请输入系数和指数(如:2 3表示2x^3):-3 5
请输入系数和指数:7 1
请输入系数和指数:2 4
请输入系数和指数:3 0
请输入系数和指数:0 0
第二个多项式如下:
-3x^5+2x^4+7x+3
合并后多项式如下:
6x^4+7x
源代码
#include<iostream>
#include<string.h>
#include<malloc.h>
#include <cstring>
#undef UNICODE
#undef _UNICODE
using namespace std;
typedef struct PNode
{
int coefficient;//系数
int exp;//指数
struct PNode* next;
}*Link, Node;
void inputPoly(Link head);//用于从控制台读入链表的函数
void Cout(Link head);//打印链表用的函数
bool insert(Link head, int coefficient, int exp);//向链表插入一个元素的函数
void combin2List(Link heada, Link headb, Link headab);//合并两个链表
void clearLink(Link head);
int main()
{
Link headA, headB;//两个多项式的头指针
Link headAB;//合并后的多项式的头指针
/*链表的初始化*/
headA = (Link)malloc(sizeof(Node));
headA->next = NULL;
headB = (Link)malloc(sizeof(Node));
headB->next = NULL;
headAB = (Link)malloc(sizeof(Node));
headAB->next = NULL;
cout << "请输入第一个多项式的系数和指数,以(0 0)结束" << endl;
inputPoly(headA);
cout << "第一个" ;
Cout(headA);
cout << "请输入第二个多项式的系数和指数,以(0 0)结束" << endl;
inputPoly(headB);
cout << "第二个" ;
Cout(headB);
combin2List(headA, headB, headAB);
cout << "合并后" ;
Cout(headAB);
clearLink(headA);
clearLink(headB);
clearLink(headAB);
return 0;
}
/**输入二项式数据的函数*/
/*这个函数用来输入二项式,给用户合适的提示,读入用户输入的系数和指数。
调用函数insert,将用户输入的二项式的一项插入到链表中去。*/
void inputPoly(Link head)
{
int coefficient, exp;//系数和指数
cout << "请输入系数和指数(如:\"2 3\"表示2x^3):" << endl;
cin >> coefficient>>exp;
while (coefficient != 0 || exp != 0)//连续输入多个系数和指数
{
insert(head, coefficient, exp);//调函数输入多项式
cout << "请输入系数和指数" << endl;
cin >> coefficient>>exp;
}
}
/**向多项式链表中插入元素的函数
int coefficient 一个多项式项的系数
int exp 一个多项式项的幂
*/
bool insert(Link head, int coefficient, int exp)
{
Link node; //node指针指向新创建的节点
Link q, p; //q,p两个节点一前一后
//创建一个新结点
//.....
q = head;
p = head->next;
node = (Link)malloc(sizeof(Node));
node->coefficient = coefficient;
node->exp = exp;
node->next = NULL;
if (head->next == NULL)//空表,插第1个
{
head->next = node;
//......
}
else
{
while (p != NULL) { //循环访问链表中的所有节点
//如果node节点的指数比p节点的指数大,则插在p的前面,完成插入后,提前退出
//if (node->exp < p->exp) {
// q->next = node;
// node->next = p;
// return true;
//}
如果node节点的指数和p节点的指数相等,则合并这个多项式节点,提前退出
//else if (node->exp == p->exp) {
// p->coefficient = p->coefficient + node->coefficient;
// return true;
//}
如果node节点的指数比p节点的指数小,继续向后移动指针(依然保持p,q一前一后)
//else {
// q = p;
// p = p->next;
//}
if (exp == p->exp) {
p->coefficient += coefficient;
return true;
}
//大于当前次数
else if (exp > p->exp) {
q->next = node;
node->next = p;
return true;
}
else {
q = p;
p = p->next;
}
}
if (p == NULL) {
q->next = node;
node->next = NULL;
return true;
}
//如果退出循环是当前指针p移动到链表结尾,则说明之前没有插入,那么当前node节点的指数值是最大值,此时插在链表的最后面
}
return true;
}
/**
数字转换为字符串函数itoa
标志是否为第一个节点的flag的设置
字符串连接函数strcat
字符串清空函数memset。memset(item,0,20);清空长20的字符串item
*/
//void Cout(Link head)
//{
// Link p; //指向链表要输出的结点
// cout << "多项式如下" << endl;
//
// p = head->next;
//
// if (p == NULL)
// {
// cout << "多项式为空" << endl;
//
// return;
// }
// // 不是空表
// char item[20] = "";//要打印的当前多项式的一项
// char number[7] = "";//暂时存放系数转换成的字符串
//
// bool isFirstItem = true;//标志是否为第一个节点的flag
// int flag = 0;
// //打印节点
// do {
// memset(item, 0, 20);//清空字符串item
// _itoa_s(p->coefficient, number, 10);//itoa()函数把 整数转换成字符串 ,并返回指向转换后的字符串的指针
//
// if (p->coefficient == 0) {
// isFirstItem = true; //如果第一项为0,移动指针,判断仍然为true
// p = p->next;
// continue;
// }
// else if(flag == 1){
// p = p->next;
// continue;
// }
// //如果是第一项,不要打+号
// else {
// if (isFirstItem != true && p->exp > 0) {
// strcat_s(item, "+");//把+添加在字符串item所指向的结尾
// //如果不是第一项,且系数为正数,要打加号
// }//如果系数为负数,系数自身带有符号
// if (p->coefficient == 1) {}//如果系数为1,不用打系数
// else if (p->coefficient == -1) { //系数为-1打印负号
// strcat_s(item, "-");
// }
// else if (p->coefficient != 0){ //如果系数不为1或-1,打印系数
// strcat_s(item, number);
// }
// if (p->exp == 1) {
// strcat_s(item, "x");
// }
// else if (p->exp == 0) { //如果指数为0,直接打系数不用打x^和指数
// if (p->coefficient == 1 || p->coefficient == -1)
// strcat_s(item, "1"); //如果系数是-1或1,需要打1出来,不能只打符号
// }
// else { //指数不为0
// strcat_s(item, "x^"); //打印x
// _itoa_s(p->exp, number, 10);
// strcat_s(item, 20,number);
// //strcat_s(item, _itoa_s(p->exp, number, 10)); //如果指数为1,不打指数,否则打指数
// }
// flag = 1;
//
// }
// cout << item << endl;//打印当前节点代表的项
// p = p->next;//指向下个结点
// isFirstItem = false;//flag标志不是第一项了
// } while (p != NULL);
// cout << endl;
//
// return;
//}
void Cout(Link head) {
Link p; //指向链表要输出的结点
cout << "多项式如下" << endl;
p = head->next;
if (p == NULL) {
cout << "多项式为空" << endl;
return;
}
// 不是空表
char item[20] = ""; //要打印的当前多项式的一项
char number[7] = ""; //暂时存放系数转换成的字符串
bool isFirstItem = true;//标志是否为第一个节点的flag
int flag = 0;
//打印节点
while (p != NULL) {
memset(item, 0, 20); //清空字符串item
_itoa_s(p->coefficient, number, 10);
if (p->coefficient == 0) {//当为0时的判断非常容易出错
if (flag == 0) {
isFirstItem = true; //如果第一项系数为0,移动指针,判断仍为true
p = p->next;
continue;
}
else if (flag == 1) {
p = p->next;
continue;
}
}
else {
if (isFirstItem != true && p->coefficient > 0) {
strcat_s(item, "+");
}
if (p->coefficient == 1) {}
else if (p->coefficient == -1) {
strcat_s(item, "-");
}
else if (p->coefficient != 0) {
strcat_s(item, number);
}
if (p->exp == 1) {
strcat_s(item, "x");
}
else if (p->exp == 0) {
if (p->coefficient == 1 || p->coefficient == -1)
strcat_s(item, "1");
}
else {
strcat_s(item, "x^");
_itoa_s(p->exp, number, 10);
strcat_s(item, 20,number);
//strcat_s(item, _itoa_s(p->exp, number, 10));
}
flag = 1;
}
cout << item ;//打印当前节点代表的项
p = p->next;//指向下个结点
isFirstItem = false; //flag标志不是第一项了
}
cout << endl;
return;
}
/**
合并两个有序链表a,b到链表ab
heada.headb,headab分别为链表a,b,ab的头指针
*/
void combin2List(Link heada, Link headb, Link headab)
{
Link pa, pb;//指向a,b链表和ab的指针
pa = heada->next;
pb = headb->next;
while (pa != NULL && pb != NULL)//a,b链表都没有没有访问完毕
{
//如果指数a>指数b,a节点插入ab链表,a指针后移
if (pa->exp > pb->exp) {
insert(headab, pa->coefficient, pa->exp);
pa = pa->next;
}
//如果指数a<指数b,b节点插入ab链表,b指针后移
else if (pa->exp < pb->exp) {
insert(headab, pb->coefficient, pb->exp);
pb = pb->next;
}
//如果指数a==指数b,a、b系数相加,插入ab链表,a、b指针后移
else if (pa->exp == pb->exp) {
int coefficient;//系数
coefficient = pa->coefficient + pb->coefficient;
insert(headab, coefficient, pa->exp);
pa = pa->next;
pb = pb->next;
}
//如果a,b链表后还有尾巴,则加到链表后面 是否可以去掉
while (pa != NULL) {
insert(headab, pa->coefficient, pa->exp);
pa = pa->next;
}
while (pb != NULL) {
insert(headab, pb->coefficient, pb->exp);
pb = pb->next;
}
return;
}
//如果a、b链表还有尾巴,将它加到ab链表后面
while (pa != NULL)
{
insert(headab, pa->coefficient, pa->exp);
pa = pa->next;
}
while (pb != NULL)
{
insert(headab, pb->coefficient, pb->exp);
pb = pb->next;
}
return;
}
void clearLink(Link head) {
Link p, q;
if (head == NULL)
return;
q = head->next;
free(head);
while (q != NULL) {
p = q;
q = q->next;
free(p);
}
}
作业二—表达式求值
栈的应用–表达式求值
一、表达式求值的规则
表达式求值是程序设计语言编译中的一个基本问题。它的实现就是对“栈”的典型应用。
首先了解算术四则运算的运算规则:
(1)先乘除,后加减。
(2)从左到右计算
(3)先算括号内,再算括号外
任何一个表达式都由操作数(operand)、运算符(operator)和界定符组成:
二、运算符优先级
对于两个相继出现的操作符
θ
1
\theta_1
θ1和
θ
2
\theta_2
θ2有三种关系:
θ
1
\theta_1
θ1 <
θ
2
\theta_2
θ2
θ
1
\theta_1
θ1的优先级低于
θ
2
\theta_2
θ2
θ
1
\theta_1
θ1 =
θ
2
\theta_2
θ2
θ
1
\theta_1
θ1的优先级等于
θ
2
\theta_2
θ2
θ
1
\theta_1
θ1 >
θ
2
\theta_2
θ2
θ
1
\theta_1
θ1的优先级高于
θ
2
\theta_2
θ2
由此可以列出“±*/”之间的优先级。如下图
代码实现
先将上表生成一个字符型的数组,我们的目的是比较两个操作符之间的优先级,用一个函数precede,通过查找其前后所在的行或者列,从而最后返回优先字符 > < = 0
//运算优先表/
#define M 8
#define N 8
char CalPriority[M][N] =
{ 0 ,'+','-','*','/','(',')','#',
'+','>','>','<','<','<','>','>',
'-','>','>','<','<','<','>','>',
'*','>','>','>','>','<','>','>',
'/','>','>','>','>','<','>','>',
'(','<','<','<','<','<','=', 0 ,
')','>','>','>','>', 0 ,'>','>',
'#','<','<','<','<','<', 0 ,'='
};
//查表函数 使用前判断是否都为 运算符
char precede(char first, char second)
{
int num1 = 0, num2 = 0;
for (; num1 < 8; num1++)
{
if (CalPriority[0][num1] == first) {
break; //找到第几行
}
}
for (; num2 < M; num2++)
{
if (CalPriority[num2][0] == second) {
break; //找到第几列
}
}
return CalPriority[num1][num2]; //返回优先级字符 < > = 0
}
三、算法思路
为实现优先算法,可以使用两个工作栈,一个是OPTR,用于寄存运算符,一个是OPND,用于寄存操作数和运算结果。算法的基本思想是:
(1) 首先置操作数栈为空栈,表达式起始符’#‘为栈底元素。
(2)依次读入表达式中的每个字符,若是操作数则进OPND栈,若是运算符则和OPTR栈的栈顶运算符比较优先级作相应操作,直至整个表达式求值完毕(OPTR栈顶元素和当前读入的字符均为’#')
先生成一个操作符和一个操作数的链栈来分别将其储存,表达式的最后一位是操作符#,当我们读取完这个式子时,就是读取字符和栈顶字符都是#的时候,读取完毕即为while ((ch != ‘#’) or (OPTR.gettop() != ‘#’));
下一步时分别将运算符和操作数入栈,操作数可以直接进行入栈但对于操作符需要判断其的优先级
如果是小于号“<”就可以直接将运算符压入操作符栈
case '<':
OPTR.push(ch);//压入堆栈
ch = input[++chcount];
break;
如果是大于号“>”就需要将此运算符和前后的两个操作数和运算符进行计算,然后将运算后的结果压入数堆栈
case '>':
theta = OPTR.pop();
b = OPND.pop();
a = OPND.pop();
OPND.push(operate(a, theta, b)); //压入操作数堆栈
break;
如果是等于号,就是"(")"相遇的时候,此时需要把“(”弹出运算符栈
case '=':
if (ch == ')')
{
OPTR.pop();
}
ch = input[++chcount];
break;
代码实现
//计算多项式函数
double Calmultinomial(string input)
{
LinkStack<char> OPTR;//操作符
LinkStack<double> OPND;//操作数
char theta;
double a, b, out, number = 0;
int multiply = 1; //累加倍率
char ch;
int chcount = 0;
ch = input[chcount];
OPTR.push('#'); //压入 ‘#’
if (ch == '#') {
cout << "头部不能是 #" << number << endl;
exit(0);
}
do {
if (isOptr(ch)) //判断是否为运算符
{
if (multiply != 1) //避免重复压入
{
OPND.push(number); //ascii 转 数字 -48
multiply = 1; number = 0;
}
switch (precede(OPTR.gettop(), ch))
{
case '<':
OPTR.push(ch);//压入堆栈
ch = input[++chcount];
break;
case '=':
if (ch == ')')
{
OPTR.pop();
}
ch = input[++chcount];
break;
case '>':
theta = OPTR.pop();
b = OPND.pop();
a = OPND.pop();
OPND.push(operate(a, theta, b)); //压入操作数堆栈
break;
}
}
else
{
if (ch == ' ') //碰到空格 后移一位
{
ch = input[++chcount];
}
else if (isOpnd(ch))
{
number = number * multiply + (ch - 48); //累加 ascii 转数字 ch-48
multiply = 10; //为多个数字叠加准备倍率 同时作为 压入标志位
ch = input[++chcount];
}
else
{ //不是符号 也不是 数字 跳出非法字符 结束程序
cout << "存在非法字符" << endl;
exit(0);
}
}
} while ((ch != '#') or (OPTR.gettop() != '#'));
out = OPND.gettop();
return out;
}
四,计算b,oprt和a
代码实现
如果optr是运算符,那么对optr进行识别,从而计算出a optr b的值
//运算符表//
const int lenofOptr = 8;
char Optr[lenofOptr] = { '+','-','*','/','(',')','#' };
bool isOptr(char input)
{
for (int i = 0; i < lenofOptr; i++)
{
if (input == Optr[i])
return true;
}
return false;
}
//计算操作函数 返回-1无效
double operate(double a, char optr, double b)
{
if (isOptr(optr)) //判断是否为 运算符
{
switch (optr)
{
case '+':
return a + b;
break;
case '-':
return a - b;
break;
case '*':
return a * b;
break;
case '/':
return (double)(a) / (double)(b);
break;
}
}
return -1;
}
五,主函数
主函数有注释掉的部分,我们可以选择之间在代码中写入我们需要的求得表达式值,当然用cin>>input,也可以在运行后输入input表达式,从而对其进行求解
int main()
{
//string input = "225 +5 *4 * (5 -2)+60 #";
//cout << "输入多项式计算 以'#'结尾" << endl;
//cin >>input; //手动输入
//cout <<"输入的多项式为 "<< input << endl;
//cout << input;
//cout << "result =" << Calmultinomial(input) << endl;
string input = "5*( 8- 1)+1 2 5+500*(3-1)+123 #";
cout << input;
cout << "result =" << Calmultinomial(input) << endl;
cout << "main end!" << endl;
return 0;
}
示例
输入
5*( 8- 1)+1 2 5+500*(3-1)+123 #
输出
输入(多位数)
225 +5 *4 * (5 -2)+60 #
输出
源代码
#include <iostream>
using namespace std;
template<class DateType> //链栈结构体
class LinkStack
{
private:
typedef struct Node {
DateType date; //数据域
struct Node* next; //指针领域
}node, * Link;
Link top;// 链表节点指针
static int LinkCount;
//int LinkCount = 0;
public:
LinkStack(); //构造函数
virtual ~LinkStack(); //析构函数
void push(DateType x); //压入一个栈节点
DateType gettop(); //得到最后一个节点内容
DateType pop(); //弹出最后最后一个 节点的内容
bool isEmpty(); //判断是否为空栈
int getLinkCount(); //输出节点数量
//bool isFull; //一般不会满除非内存满了
};
template<class DateType>
int LinkStack<DateType>::LinkCount = 0; //节点记录数字
template<class DateType>
LinkStack<DateType>::LinkStack()
{
Link s;
s = new node;
top = s;
s->next = nullptr;
}
template<class DateType>
LinkStack<DateType>::~LinkStack()
{
for (int i = 0; i < LinkCount; i++)
{
delete top;
top = top->next;
}
}
template<class DateType>
void LinkStack<DateType>::push(DateType x) {
Link s;
s = new node;
s->date = x;
s->next = top;
top = s;
LinkCount++;
}
template<class DateType>
DateType LinkStack<DateType>::pop() {
DateType p = gettop();
Link q = top->next;
delete top;
top = q; //指向top下一地址
LinkCount--;
return p; //返回top内容
}
template<class DateType>
DateType LinkStack<DateType>::gettop() {
if (!isEmpty()) { //不为空
return top->date; //返回top内容
}
}
template<class DateType>
bool LinkStack<DateType>::isEmpty() {
return top == nullptr;
}
template<class DateType>
int LinkStack<DateType>::getLinkCount() {
return LinkCount;
}
//运算符表//
const int lenofOptr = 8;
char Optr[lenofOptr] = { '+','-','*','/','(',')','#' };
bool isOptr(char input)
{
for (int i = 0; i < lenofOptr; i++)
{
if (input == Optr[i])return true;
}
return false;
}
//数字符表///
const int lenofOpnd = 10;
char Opnd[lenofOpnd] = { '0','1','2','3','4','5','6','7','8','9' };
//判断是否为操作符
//判断是否为数字
bool isOpnd(char input)
{
for (int i = 0; i < lenofOpnd; i++)
{
if (input == Opnd[i])
return true;
}
return false;
}
//运算优先表/
#define M 8
#define N 8
char CalPriority[M][N] =
{ 0 ,'+','-','*','/','(',')','#',
'+','>','>','<','<','<','>','>',
'-','>','>','<','<','<','>','>',
'*','>','>','>','>','<','>','>',
'/','>','>','>','>','<','>','>',
'(','<','<','<','<','<','=', 0 ,
')','>','>','>','>', 0 ,'>','>',
'#','<','<','<','<','<', 0 ,'='
};
//计算操作函数 返回-1无效
double operate(double a, char optr, double b)
{
if (isOptr(optr)) //判断是否为 运算符
{
switch (optr)
{
case '+':
return a + b;
break;
case '-':
return a - b;
break;
case '*':
return a * b;
break;
case '/':
return (double)(a) / (double)(b);
break;
}
}
return -1;
}
//查表函数 使用前判断是否都为 运算符
char precede(char first, char second)
{
int num1 = 0, num2 = 0;
for (; num1 < 8; num1++)
{
if (CalPriority[0][num1] == first) {
break; //找到第几行
}
}
for (; num2 < M; num2++)
{
if (CalPriority[num2][0] == second) {
break; //找到第几列
}
}
return CalPriority[num1][num2]; //返回优先级字符 < > = 0
}
//计算多项式函数
double Calmultinomial(string input)
{
LinkStack<char> OPTR;//操作符
LinkStack<double> OPND;//操作数
char theta;
double a, b, out, number = 0;
int multiply = 1; //累加倍率
char ch;
int chcount = 0;
ch = input[chcount];
OPTR.push('#'); //压入 ‘#’
if (ch == '#') {
cout << "头部不能是 #" << number << endl;
exit(0);
}
do {
if (isOptr(ch)) //判断是否为运算符
{
if (multiply != 1) //避免重复压入
{
OPND.push(number); //ascii 转 数字 -48
multiply = 1; number = 0;
}
switch (precede(OPTR.gettop(), ch))
{
case '<':
OPTR.push(ch);//压入堆栈
ch = input[++chcount];
break;
case '=':
if (ch == ')')
{
OPTR.pop();
}
ch = input[++chcount];
break;
case '>':
theta = OPTR.pop();
b = OPND.pop();
a = OPND.pop();
OPND.push(operate(a, theta, b)); //压入操作数堆栈
break;
}
}
else
{
if (ch == ' ') //碰到空格 后移一位
{
ch = input[++chcount];
}
else if (isOpnd(ch))
{
number = number * multiply + (ch - 48); //累加 ascii 转数字 ch-48
multiply = 10; //为多个数字叠加准备倍率 同时作为 压入标志位
ch = input[++chcount];
}
else
{ //不是符号 也不是 数字 跳出非法字符 结束程序
cout << "存在非法字符" << endl;
exit(0);
}
}
} while ((ch != '#') or (OPTR.gettop() != '#'));
out = OPND.gettop();
return out;
}
int main()
{
string input = "225 +5 *4 * (5 -2)+60 #";
//cout << "输入多项式计算 以'#'结尾" << endl;
//cin >>input; //手动输入
//cout <<"输入的多项式为 "<< input << endl;
cout << input;
cout << "result =" << Calmultinomial(input) << endl;
//string input = "5*( 8- 1)+1 2 5+500*(3-1)+123 #";
//cout << input;
//cout << "result =" << Calmultinomial(input) << endl;
cout << "main end!" << endl;
return 0;
}