数据结构-(一元多项式的相加,表达式求值)含代码

作业一:一元多项式的相加

单链表

 

申请一个结点
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域
RgcuI.png
  1. 工作指针p初始化

  2. 查找第i-1个结点并使用、工作指针p指向该结点

  3. 若查找不成功,则返回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;
RgQaM.png
插入第一个元素
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;
RgSNG.png
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

输入

RrkBG.png

 

示例
请输入第一个多项式的系数和指数,以(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
RrWlM.png

 

示例
请输入第一个多项式的系数和指数,以(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
RrUJr.png

源代码

#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
由此可以列出“±*/”之间的优先级。如下图

RUmdr.png
代码实现

先将上表生成一个字符型的数组,我们的目的是比较两个操作符之间的优先级,用一个函数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栈顶元素和当前读入的字符均为’#')

RUgvc.png

先生成一个操作符和一个操作数的链栈来分别将其储存,表达式的最后一位是操作符#,当我们读取完这个式子时,就是读取字符和栈顶字符都是#的时候,读取完毕即为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 #
输出

image-20221215175904357

 

输入(多位数)
225 +5  *4 * (5 -2)+60 #
输出

image-20221215175921468

 

源代码

#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;
}

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江江江江江江江江江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值