数据结构--多项式的逆波兰计算器

这个题目挺简单的。但是由于我是第一次用C++写程序,花了大概15个小时做这个题目。

初步弄清楚了C++中类模板的使用方式。

然后通过实践,觉得类的继承是非常好用的东西。

但是还是有一些莫名其妙的东西。

直接放代码

main.cpp

#include 
#include  //for tolower()
using namespace std;
#include "polynomial.h"
#include "stack.h"

typedef Stack MyStack;
typedef Polynomial MyPolynomial;

void introduction();
bool do_command(char command, Stack &stored_polynomials);
char get_command();

int main()
{
    Stack stored_polynomial;
    introduction();
    while(do_command(get_command(), stored_polynomial));
    return 0;
}

bool do_command(char command, Stack &stored_polynomials)
//前态:第一个参数是一个合法的calculator command
//后态:执行由第一个参数决定的操作,作用在我们的多项式的栈上面。
//(在这里我们要使用类似物理中的整体法与隔离法的方法来做看待这些事情。)
// 如果command=='q' 返回false,否则返回true
//使用哪些东西:typedef Polynomial MyPolynomial;
//              typedef Stack MyStack;
// utility中的 Error_code,这个utility由linked_queue.h和stack.h都包含了
// 虽然这里重复定义了Error_code,但是在utility.h里面有一句话:
//#ifndef UTILITY_H_INCLUDED
//#define UTILITY_H_INCLUDED
//.....
//#endif
//所以,Error_code其实不会被重复定义的。
{
    MyPolynomial p;
    MyPolynomial q;
    MyPolynomial r;
    Error_code outcome;
    switch(command){
    case '?':
        p.read();
        outcome = stored_polynomials.push(p);
        if(outcome ==overflow)
            cout<<"Warning: Stack full, lost polynomial"<>command;
        if(command == '?' || command == '=' ||
           command=='+' || command =='-'  ||
           command == '*' || command =='q')
            waiting = false;
        else {
            cout<<"\n您选择的命令有误,请输入下列命令:\n"
                <<"[?] 读入一个多项式"<

utility.h  里面定义了一些需要用到的东西

#ifndef UTILITY_H_INCLUDED
#define UTILITY_H_INCLUDED

#include  // 使用这里面的NULL的定义
enum Error_code {success,underflow,overflow};

#endif // UTILITY_H_INCLUDED


node.h 定义了一个Node的模板,既用在栈里来存放多项式,也用在多项式里用来存放项

#ifndef NODE_H_INCLUDED
#define NODE_H_INCLUDED

#include "utility.h"
template 
struct Node{
    Node_entry entry;
    Node *next;
    Node(){next =NULL;} //不带参数的构造函数
    Node(Node_entry item, Node * add_on = NULL);  //复制构造函数
};


template 
//Node::Node(Node_entry item, Node * add_on = 0)
//一开始我是按照上面的写法写的。但是默认的数值只能在类定义的里面写(=0)
Node::Node(Node_entry item, Node * add_on)
{
    entry = item;
    /*===========================================*/
    // 因为这里是在对两个Node_entry类的对象进行赋值操作,所以
    //这里在定义Node_entry的类型的时候,要为Node_entry这个类写一个赋值号重载
    // 但是如果Node_entry为数字之类的,比如int, double,long之类的,就不需要。
    // 因为这些类型已经写好了赋值号的含义
    // 所以在我们的这个例子里面,我们需要对Polynomial和Term写赋值号的重载
    /*===========================================*/
    next = add_on;
}

#endif // NODE_H_INCLUDED




stack.h 这里有个很疑惑的问题,就是如果在构造函数里面申请空间,如果没有申请成功怎么办


#ifndef STACK_H_INCLUDED
#define STACK_H_INCLUDED
#include "utility.h" // for cstddef and Error_code
#include "node.h"

template 
class Stack
// Stack由一个一个的Node结构体链接而成,每个结构体里面存放的东西才是我们真正想要的东西
// 而Stack_entry是如何存放的,应该对用户隐藏起来。
// 所以,Stack_entry这个类应该和Node_entry的类是同样的类型。
{
public:
    // Standard Stack methods.
    Stack(); //构造函数
    bool empty() const;
    Error_code push(const Stack_entry &item); // 这个地方我们应该是要将item复制一份然后压到栈里面去。
    Error_code pop(); //弹出一个来以后,需要将Node节点delete掉,但是要注意还需要把Stack_entry先delete掉
    Error_code top(Stack_entry &item) const;
    // Safety features for linked structures
    ~Stack();
    Stack(const Stack &original);
    void operator=(const Stack &original);
protected:
    Node *top_node;
};


template 
Stack::Stack()
// 前态:没有
// 后态:头结点top_node定义为NULL
{
    top_node = NULL; //将头结点接地
}


template 
bool Stack::empty() const
// 前态: 没有
// 后态: 如果栈为空,则返回true,否则返回false
{
    return ((top_node)==NULL);
}

template 
Error_code Stack::push(const Stack_entry &item)
// 前态:没有
// 后态:动态申请一个节点用来保存Stack_entry,如果申请不到的话,返回overflow的Error_code
// 在这个题目中,我们的Stack_entry将会成为Polynomial类
{
    Node *new_top = new Node(item, top_node);
    /*
    *我们将会用到的是Polynomial类的对象作为item,那么在Node的复制构造函数里面就需要
    *对这个item做一个硬拷贝。
    */
    if(new_top == NULL) return overflow;
    top_node = new_top;
    return success;
}

template 
Error_code Stack::pop()

{
    Node *old_top = top_node;
    if(top_node == NULL) return underflow;
    top_node = top_node->next;
    (old_top->entry).clear();
    //这就要求Stack_entry类型必须要有一个public的方法clear()
    //这就要求Stack_entry类型必须要有一个public的方法clear()
    //这就要求Stack_entry类型必须要有一个public的方法clear()
    //这就要求Stack_entry类型必须要有一个public的方法clear()
    //这就要求Stack_entry类型必须要有一个public的方法clear()
    //这就要求Stack_entry类型必须要有一个public的方法clear()
    //这就要求Stack_entry类型必须要有一个public的方法clear()
    //这就要求Stack_entry类型必须要有一个public的方法clear()
    //这就要求Stack_entry类型必须要有一个public的方法clear()

    delete old_top;
    //这个时候是将Node节点的空间删除掉。但是这个会调用到Polynomial的析构函数吗???????
    //这个时候是将Node节点的空间删除掉。但是这个会调用到Polynomial的析构函数吗???????
    //这个时候是将Node节点的空间删除掉。但是这个会调用到Polynomial的析构函数吗???????
    //这个时候是将Node节点的空间删除掉。但是这个会调用到Polynomial的析构函数吗???????
    //这个时候是将Node节点的空间删除掉。但是这个会调用到Polynomial的析构函数吗???????
    //这个时候是将Node节点的空间删除掉。但是这个会调用到Polynomial的析构函数吗???????
    //这个时候是将Node节点的空间删除掉。但是这个会调用到Polynomial的析构函数吗???????
    //这个时候是将Node节点的空间删除掉。但是这个会调用到Polynomial的析构函数吗???????
    return success;
}


template 
Error_code Stack::top(Stack_entry &item) const

{
    if(top_node == NULL) return underflow;
    item = top_node->entry;
    //这里要为item这个类编写赋值号的重载
    //而且先要将item里面的节点都删除掉
    return success;
}

template 
Stack::~Stack()

{
    while(!empty())
        pop();
}

template 
void Stack::operator=(const Stack &original)

{
    Node *new_top, *new_copy, *original_node = original.top_node;
    if(original_node ==NULL) new_top=NULL;
    else {
        new_copy = new_top = new Node(original_node->entry);
        while(original_node->next != NULL){
            original_node = original_node->next;
            new_copy->next = new Node(original_node->entry);
            new_copy = new_copy->next;
        }
    }
    while(!empty()) // Clean out old Stack entries.
        pop();
    new_copy->next = NULL;
    top_node = new_top;  // And replace them with new entries.
}

template 
Stack::Stack(const Stack &original)

{
    Node *new_copy, *original_node = original.top_node;
    if(original_node ==NULL) top_node =NULL;
    else {
        top_node = new_copy = new Node(original_node->entry);
        while(original_node->next != NULL){
            original_node = original_node->next;
            new_copy->next = new Node(original_node->entry);
            new_copy = new_copy->next;
        }
    }
}
//  疑问: 在构造函数里面申请空间,如果没有申请成功怎么办,这不是很难受吗?
//  疑问: 在构造函数里面申请空间,如果没有申请成功怎么办,这不是很难受吗?
//  疑问: 在构造函数里面申请空间,如果没有申请成功怎么办,这不是很难受吗?
//  疑问: 在构造函数里面申请空间,如果没有申请成功怎么办,这不是很难受吗?
//  疑问: 在构造函数里面申请空间,如果没有申请成功怎么办,这不是很难受吗?
//  疑问: 在构造函数里面申请空间,如果没有申请成功怎么办,这不是很难受吗?
//  疑问: 在构造函数里面申请空间,如果没有申请成功怎么办,这不是很难受吗?
//  疑问: 在构造函数里面申请空间,如果没有申请成功怎么办,这不是很难受吗?


#endif // STACK_H_INCLUDED



queue.h


#ifndef QUEUE_H_INCLUDED
#define QUEUE_H_INCLUDED

#include "utility.h" // Error_code
#include "node.h"

/*
    struct Term{
        int degree;
        double coefficient;
        Term(int exponent, double scalar){
            degree = exponent;
            coefficient = scalar;
        }
    };
*/

// 在我们的这个应用里面,Queue_entry将会具体化化为Term
template 
class Queue{
public:
    Queue();
    bool empty() const;
    Error_code append(const Queue_entry &item);
    Error_code serve();
    Error_code retrieve(Queue_entry &item) const;
    // safety features for linked structures;
    ~Queue();
    Queue(const Queue &original);
    void operator=(const Queue &original);

protected:
    Node *front,*rear;
};




template 
Queue::Queue()

{
    front = rear = NULL;
}

template 
bool Queue::empty() const
//如果为空,则返回true,否则返回false
{
        return (front==NULL);
}


template 
Error_code Queue::append(const Queue_entry &item)
{
    Node *new_rear = new Node(item); //所以要为Node写复制构造函数
    if(new_rear == NULL) return overflow;
    if(rear == NULL) front = rear = new_rear;
    else {
        rear->next = new_rear;
        rear  = new_rear;
    }
    return success;
}

template 
Error_code Queue::serve()

{
    if(front==NULL) return underflow;
    Node *old_front = front;
    front = old_front->next;
    if(front ==NULL) rear = NULL;
    delete old_front;
    return success;
}

template 
Error_code Queue::retrieve(Queue_entry &item) const

{
    if(front==NULL) return underflow;
    item = front->entry; //要为Queue_entry写一个赋值号的重载
    return success;
}

template 
Queue::~Queue()
{
    while(!empty()){
        serve();
    }
}

template 
Queue::Queue(const Queue &original)
// 这个是复制构造函数
{
    Node *new_rear, *original_node = original.front;
    if(original_node==NULL){
        front = rear = NULL;
    }
    else {
        front = new Node(original_node->entry);
        new_rear = front;

        while(original_node->next!=NULL){
            original_node = original_node->next;
            new_rear->next = new Node(original_node->entry);
            new_rear = new_rear->next;
        }
        rear = new_rear;
        rear->next = NULL;
    }
}

template 
void Queue::operator=(const Queue &original)
{
    Node *new_front,*new_rear, *original_node = original.front;
    if(original_node ==NULL) {
        new_front = new_rear = NULL;
        return;
    }
    else {
        new_front = new_rear = new Node(original_node->entry);
        while(original_node->next!=NULL){
            original_node = original_node->next;
            new_rear->next = new Node(original_node->entry);
            new_rear = new_rear->next;
        }
    }
    while(!empty()){
        serve();
    }
    front = new_front;
    rear = new_rear;
    rear->next = NULL;
}
#endif // QUEUE_H_INCLUDED


extendedQueue.h

#ifndef EXTENDEDQUEUE_H_INCLUDED
#define EXTENDEDQUEUE_H_INCLUDED

#include "queue.h"

template 
class ExtendedQueue : public Queue
{
public:
    bool full() const;
    int size() const;

    Error_code serve_and_retrieve(Queue_entry &item);
};

template 
bool ExtendedQueue::full() const
// 如果无法再申请到空间的话,那么就返回true说明我们的队列已经吗,满了
// 无法再容纳下更多的元素了。
{
    Node *tmp;
    tmp = new Node;
    if(tmp == NULL) return true;
    else return false;
}

template 
int ExtendedQueue::size() const

{
    Node *window = this->front;
    int count = 0;
    while(window!=NULL){
        window = window->next;
        count++;
    }
    return count;
}

template 
Error_code ExtendedQueue::serve_and_retrieve(Queue_entry &item)
{
    this->retrieve(item);
    return this->serve();
}
#endif // EXTENDEDQUEUE_H_INCLUDED

polynomial.h

#ifndef POLYNOMIAL_H_INCLUDED
#define POLYNOMIAL_H_INCLUDED

//为了使得Polynomial类可以输入输出
#include 
using namespace std;
#include   ////为了使得Polynomial类可以输入输出
#include "extendedQueue.h"

struct Term{
    int degree;
    double coefficient;
    Term(int exponent=0, double scalar=0.0){
        degree = exponent;
        coefficient = scalar;
    }
    void operator=(const Term &item){
        degree = item.degree;
        coefficient = item.coefficient;
    }
};


class Polynomial: private ExtendedQueue {
public:
    void read();
    void print() const;
    void equals_sum(Polynomial p, Polynomial q);// 这里没有使用引用的方式,而是使用直接传值的方式
    // 因为我们这个方法需要修改形参p,q的值,但是我们不打算修改实参的值,所以这么做。
    // 可以说这个开销是由封装带来的。
    //(因为我们无法直接使用对象p的front和rear指针,而是需要通过对象p的公共方法来操控数据)
    void equals_difference(Polynomial p, Polynomial q);
    void equals_product(Polynomial p, Polynomial q);
    //Error_code equals_quotient(Polynomial p, Polynomial q);
    /*!!!safety!!!*/    void clear(){while(!this->empty()){this->serve();}  }
    //这一句话非常的重要,如果如果栈pop的时候,节点(Node)里面的
    // Polymonial类申请过的空间就无法回收回来。
    int degree() const;
private:
    void mult_term(Polynomial p,Term t);
    //只要实现了mult_term,那么让equals_product调用一下这个就可以啦
};


void Polynomial::read(){
    clear();
    double coefficient;
    int last_exponent, exponent;
    bool first_term = true;
    cout<<"输入多项式的系数和指数,\n"
        <<"每一行输入一个多项式里面的一个项,按照指数递减的方式输入"<> coefficient;
        scanf("%lf",&coefficient);
        if (coefficient != 0.0) {
            cout << "指数(unsigned int)" << flush;
            //cin>>exponent;
            scanf("%d",&exponent);
            //使用scanf而不使用cin可以方式输入一串乱七八糟的东西进来使得程序崩溃
            if ((!first_term && exponent >= last_exponent) || exponent < 0) {
                exponent = 0;
                cout << "检测到指数的顺序没有按照递减的方式输入,终止输入,截取有效的输入作为多项式的输入放入栈顶"
                    << endl;
            }
            else {
                Term new_term(exponent, coefficient); // 利用了复制构造函数
                append(new_term);
                first_term = false;
            }
            last_exponent = exponent;
        }
    } while (coefficient != 0.0 && exponent != 0);
}

void Polynomial::print() const
{
    Node *print_node = front;
    bool first_term = true;
    while(print_node!=NULL){
        Term &print_term = print_node->entry; // print_term现在就是Term

        //处理首项的符号
        if(first_term){ //如果现在正在处理第一项,那么要注意第一项的+不要输出
            first_term = false;
            if(print_term.coefficient<0) cout<<" -";
        }
        else if(print_term.coefficient<0)cout<<"-";
        else cout<<" + ";
        //处理系数
        double r = (print_term.coefficient>=0)? //获取系数的绝对值
                    print_term.coefficient:-(print_term.coefficient);
        if(r!=1) cout<1) cout<<" X^"<next;
    }
    if(first_term) cout<<"0";//给一个空的多项式输出一个0,注意这里的空的多项式 != 0多项式
    cout< q.degree()) {
            p.serve_and_retrieve(p_term);
            append(p_term);
        }
        else if (q.degree() > p.degree()) {
            q.serve_and_retrieve(q_term);
            append(q_term);
        }
        else {
            p.serve_and_retrieve(p_term);
            q.serve_and_retrieve(q_term);
            if (p_term.coefficient + q_term.coefficient != 0) {
                Term answer_term(p_term.degree,
                p_term.coefficient + q_term.coefficient);
                append(answer_term);
            }
        }
    }
}

void Polynomial::equals_difference(Polynomial p, Polynomial q){
    clear();
    //p-q = p+(-q)
    Polynomial tmp;
    tmp.clear();
    //tmp = -q;
    while(!q.empty()){
        Term q_term;
        q.serve_and_retrieve(q_term);
        (q_term).coefficient *= (-1);
        tmp.append(q_term);
    }
    equals_sum(p,tmp);

}

/*
void Polynomial::equals_product(Polynomial p, Polynomial q){
    value = p.value * q.value;
}
*/
/*
Error_code Polynomial::equals_quotient(Polynomial p, Polynomial q){
    Error_code outcome = success;
    if(q.value>-1e-10 && q.value<1e-10){
        outcome = overflow;
        return outcome;
    }
    value = p.value/q.value;
    return outcome;
}
*/

int Polynomial::degree() const
{
    if(empty())return -1;
    Term lead;
    retrieve(lead);
    return lead.degree;
}

//这是一个私有的方法
void Polynomial::mult_term(Polynomial p,Term t)
// 前态:传进来符合标准类型的2个参数
// 后态:使得this所指向的Polynomial类加上  多项式p乘以这个Term t
//      不过这样写的效率比较低
{
    if(t.coefficient==0) return; //如果乘以一个0,那么我们什么也不加
    Polynomial tmp;
    Term p_term;
    tmp.clear();
    while(!p.empty()){
        p.serve_and_retrieve(p_term);
        p_term.coefficient *= t.coefficient;
        p_term.degree += t.degree;
        tmp.append(p_term);
    }
    Polynomial self(*this);//调用复制构造函数
    this->equals_sum(self,tmp);
}


void Polynomial::equals_product(Polynomial p, Polynomial q){
    this->clear();
    Term q_term;
    while(!q.empty()){
        q.serve_and_retrieve(q_term);
        this->mult_term(p,q_term); //写上this只是为了增加可读性
    }
}
#endif // POLYNOMIAL_H_INCLUDED


你可能感兴趣的:(数据结构学习)