利用广义表解决下列多项式的存储问题

问题抛出:利用广义表解决下列多项式的存储问题


实验内容
实验4 用广义表表示和存储m元多项式

一个m元多项式的每一项,最多有m个变元。如果用线性表来表示,则每个数据元素需要m+1个数据项,以存储一个系数值和m个指数值。这将产生两个问题,一是无论多项式中各项的变元数是多是少,若都按m个变元分配存储空间,将造成浪费;反之,若按各项实际的变元数分配存储空间,就会造成结点的大小不匀,给操作带来不便。二是对m值不同的多项式,线性表中的结点大小也不同,这同样会引起存储管理的不便。因此,m元多项式不适于用线性表表示和存储。
任何一个m元多项式都可先分解出一个主变元,随后再分解出第二个变元,等等。由此,一个m元的多项式首先是它的主变元的多项式,而其系数又是第二变元的多项式,由此可用广义表来表示m元多项式。如

x^10 * y^3 * z^2 + 2 * x^6 * y^3 * z^2 + 3 * x^5 * y^2 * z^2 + x^4 * y^4 * z + 6 * x^3 * y^4 * z + 2 * y * z + 15

可表示为

(( x^10 + 2 * x^6 ) y^3 + 3 * x^5 * y^2 ) * z^2 + (( x^4 + 6 * x^3 ) * y^4 + 2 * y ) * z + 15

要求:
1、 用广义表设计实现多项式类,存储和表示m元多项式;
2、 实现两个多项式的相加;
3、 求取多项式是几元多项式,以及多项式的次数、项数。

注意:
1) m元多项式的输入和输出格式为

(( x^10 + 2 * x^5 ) y^3 + 3 * x^5 * y^2 ) * z^2 + (( x^4 + 6 * x^3 ) * y^4 + 2 * y ) * z + 15

2) 次数和项数输出格式为

3元多项式次数:3
3元多项式项数:3

3) 提交源代码必须包含测试代码。


《数据结构》(殷人昆)有关于广义表部分内容源码

广义表的基本类定义及其具体函数的实现

GenList.h

#ifndef GENLIST_H
#define GENLIST_H
#include <iostream>
#include <cassert>
#include <cstdlib>
#include "SeqList.h"
// 广义表结点的类结构定义
template <typename T>class GenListNode{
public:
    int utype;                  // =0/1/2
    int mark;                   // 访问标记
    GenListNode<T> *tlink;      // 指向同一层下一个结点的指针
    union{
        int ref;                // utype=0: 表头,存放引用计数
        T value;                // utype=1: 元素,存放原子结点数值
        GenListNode<T> *hlink;  // utype=2: 子表,存放子表头指针
    }info;
    GenListNode(){
        mark = 0;
        utype = 0;
        tlink = NULL;
        info.ref = 0;
    }
    GenListNode(GenListNode<T> &RL) {
        mark = RL.mark;         //复制构造函数
        utype = RL.utype;
        tlink = RL.tlink;
        info = RL.info;
    }
};

// 广义表返回值的类结构定义
template <typename T>class Items{
public:
    int utype;                  // =0/1/2
    int mark;                   // 访问标记
    union{
        int ref;                // utype=0: 表头,存放引用计数
        T value;                // utype=1: 元素,存放数值
        GenListNode<T> *hlink;  // utype=2: 子表,存放子表头指针
    }info;
    Items(){                    //构造函数
        utype = 0;
        mark = 0;
    }
    Items(Items<T> &RL){
        utype = RL.utype;
        mark = RL.mark;
        info = RL.info;
    }
};

// 广义表类的定义
template <typename T>class GenList{
public:
    GenList();
    ~GenList();
    bool Head(Items<T> &x);              //返回表头元素x
    bool Tail(GenList<T> &lt);           //返回表尾,除了首元素以外剩下的元素
    GenListNode<T> *First();
    GenListNode<T> *Next(GenListNode<T> *elem);
    void Copy(const GenList<T> &R);      //广义表的复制
    int Length();                        //计算广义表的长度
    int depth();                         //计算非递归表的深度
    void delvalue(const T &x);
    void Print(ostream &out = cout) {Print(first, out);}
    bool equal(GenList<T>& t){
        return equal(first,t.first);
    }
    friend istream& operator >> (istream &in, GenList<T> &L){
        SeqList<T> Ls1;
        SeqList<GenListNode<T> *> Ls2;
        L.CreateList (in, L.first, Ls1, Ls2);   //建立存储结构
        GenListNode<T> *p = L.first;            //删除广义表头部多出来的子表结点
        L.first = L.first->info.hlink;
        delete p;
        return in;
    }
    friend ostream& operator << (ostream &out, GenList<T> &L){
        L.Print(out);
        return out;
    }
private:
    GenListNode<T> *first;                      //头指针
    GenListNode<T> *Copy(GenListNode<T> *ls);   //复制一个ls指示的无共享非递归表
    int Length(GenListNode<T> *ls);             //求广义表的长度
    int depth(GenListNode<T> *ls);              //求广义表的深度
    bool equal(GenListNode<T> *s, GenListNode<T> *t);//判断s和t指示的广义表是否相等
    void delvalue(GenListNode<T> *ls, const T &x);  //删除含定值x的结点
    void Remove(GenListNode<T> *ls);                 //释放以ls为附加头结点的广义表
    void Print(GenListNode<T>* p, ostream &out);  //实现广义表的整体输出
    void CreateList(istream &in, GenListNode<T> *& ls,//利用输入流中已知的字符串建立一个广义表
            SeqList<T> &L1, SeqList <GenListNode<T> *> &L2);
};

template <typename T>GenList<T>::GenList(){    //构造函数,创建一个起始结点@
    first = new GenListNode<T>;
    assert(first);
}

template <typename T>GenList<T>::~GenList(){   //析构函数~Genlist()调用函数Remove(GenListNode<T>);
    Remove(first);
}

template <typename T>bool GenList<T>::Head(Items<T> &x){//返回表头元素值,只需返回标记以及信息域的值即可
    if (first!=NULL){
        x.utype = first->tlink->utype;
        x.info = first->tlink->info;
        return true;
    }
    else    return false;
}

template <typename T>bool GenList<T>::Tail(GenList<T> &lt){//返回表尾
    if (first->tlink!=NULL){
        lt.first->utype = 0;
        lt.first->info.ref = 0;
        lt.first->tlink = Copy(first->tlink->tlink);
        return true;
    }
    else    return false;
}

template <typename T>GenListNode<T> *GenList<T>::First(){//返回第一个元素的地址
    return first->tlink;
}

template <typename T>GenListNode<T> *GenList<T>::Next(GenListNode<T> *elem){//返回直接后继元素的地址
    return elem->tlink;
}

template <typename T>
void GenList<T>::Copy(const GenList<T> &R){//广义表复制,函数的形参为一个广义表的子表
    first = Copy(R.first);                 //调用另一个Copy()函数,将广义表R复制给调用该函数的广义表
}

template <typename T>GenListNode<T>* GenList<T>::Copy(GenListNode<T> *ls){//副本实际未共享,但ref标识不变,equal()判相同,Remove()因ref>1漏删
    GenListNode<T> *q = NULL;                                             //函数的形参为一个指向广义表结点的指针
    if (ls!=NULL){ //if(ls==NULL)递归调用的终止条件
        q = new GenListNode<T>;
        q->utype = ls->utype;
        switch (ls->utype){
        case 0:
            q->info.ref = ls->info.ref;
            break;
        case 1:
            q->info.value = ls->info.value;cout<<q->info.value<<endl;
            break;
        case 2:
            q->info.hlink = Copy(ls->info.hlink);//下一层:递归调用Copy(GenListNode<T> *ls)实现子表的复制
            break;
        }
        q->tlink = Copy(ls->tlink);//同一层:复制q的后继结点
    }
    return q; //最后返回的q为复制后所得的广义表的头指针
}

template <typename T>int GenList<T>::Length(){//广义表长度,即求第一层次所含有的元素的个数
    return Length(first)-1;                   //嵌套调用Length()调用Length(GenListNode<T>)函数
}

template <typename T>int GenList<T>::Length(GenListNode<T> *ls){
    return (ls == NULL)?0:(1+Length(ls->tlink));//利用递归算法,在同一层元素中沿着tlink向后压栈求解广义表的长度
}

template <typename T>int GenList<T>::depth(){   //嵌套调用depth()调用depth(GenListNode<T>)函数
    return depth(first);
}

template <typename T>int GenList<T>::depth(GenListNode<T> *ls){//广义表深度:从广义表的最深处开始往上求解广义表的深度
    if (ls==NULL){                                             //递归调用栈中每一次调用函数时m为每一个被调用的函数的局部变量
        return 1;                                              //m每一次的值通过return m+1语句建立联系
    }
    GenListNode<T> *temp = ls->tlink;//temp为当前指针
    int m = 0, n;
    while (temp!=NULL){
        if (temp->utype == 2){//当标记为子表类型时
            n = depth(temp->info.hlink);//利用递归算法求解子表的深度
            if (m < n){//m用于记录当前所查找完的广义表的深度
                m = n;//m用于记录同层所查到的广义表的子表的最大深度
            }
        }
        temp = temp->tlink;//查找同一层的下一个元素
    }
    return m+1;//该层元素已经查找完,跳回到上一层的元素当中进行查找
}

template <typename T>bool GenList<T>:: equal(GenListNode<T> *s, GenListNode<T> *t){//广义表是否相等,不适用共享表副本
    bool x;
    if (s->tlink == NULL && t->tlink == NULL)   return true;//两个表均为空表,相等返回true
    if (s->tlink!=NULL && t->tlink!=NULL && s->tlink->utype == t->tlink->utype) {//均为非空表,且第一个元素的信息域类型相同
        if (s->tlink->utype == 0){//信息域为头指针
            if(s->tlink->info.ref== t->tlink->info.ref) x=true;
            else x=false;
        }
        if (s->tlink->utype == 1){//信息域为原子类型
            x = (s->tlink->info.value == t->tlink->info.value)?true:false;
        }
        if (s->tlink->utype == 2){//信息域为子表类型
            x = equal(s->tlink->info.hlink, t->tlink->info.hlink);//利用递归(向深处递归)判断子表是否相等
        }

        if (x!=0)   {//前面所进行的Remove(GenListNode<T> *ls)操作(第一层的第一个元素)过程两个表均相等
            return equal(s->tlink, t->tlink);//(向后递归)判断后续结点对应的元素是否相等
        }
    }
    return false;
}

template <typename T>void GenList<T>::delvalue(const T &x){//删除含定值x的结点
    delvalue(first, x);     //利用函数delvalue(const T &x)调用函数delvalue(GenListNode<T> *ls, const T &x)
}
template <typename T>void GenList<T>::delvalue(GenListNode<T> *ls, const T &x){
    if (ls->tlink!=NULL)    {//递归的终止条件,到了该层的最后一个结点
        GenListNode<T> *p = ls->tlink;//p指向ls所指的下一个元素
        while (p!=NULL && (p->utype == 1 && p->info.value == x)){
            cout<<p->info.value;
            ls->tlink = p->tlink;
            delete p;
            p = ls->tlink;
        }
        if (p!=NULL){
            if (p->utype == 2){//当p所指的结点存在子表时
                cout<<'#'<<endl;
                delvalue(p->info.hlink, x);//进入下一层次
            }
            delvalue(p, x);//当p所指的结点不存在子表时,由本结点开始向着同一层的尾指针向后搜索
        }
    }
}

template <typename T>void GenList<T>::Remove(GenListNode<T> *ls){//删除指定子表,不适用共享表副本
    ls->info.ref--;                                          ///疑问:如果调用一次Remove(GenListNode<T> *ls)函数那么引用计数-1
    if (ls->info.ref <= 0){                                  ///那么,当引用计数仍不为0时就不进行任何操作,怎么知道-1之后是撤
        GenListNode<T> *q;                                   ///销了哪一个子表对其的引用?
        while (ls->tlink){
            q = ls->tlink;
            if (q->utype == 2){
                Remove(q->info.hlink);
                if (q->info.hlink->info.ref <= 0){
                    delete q->info.hlink;
                }
            }
            ls->tlink = q->tlink;
            delete q;
        }
    }
}
///********************************************有 ******************************************//
///*********************************************待 ******************************************//
///********************************************* 解 ******************************************//
///*********************************************  决******************************************//
// 从广义表的字符串描述s出发, 建立一个带头结点的广义表,要求T为char型。
// 在表L1存储大写字母的表名, 在表L2存储表名对应子表结点的地址。
template <typename T>void GenList<T>::CreateList(istream& in, GenListNode<T> *& ls,
            SeqList<T> &L1, SeqList <GenListNode<T> *> &L2){
    T chr;
    in >> chr;  //以 D(B(a,b),C(u,(x,y,z),B),A(#)) 为例
    cout<<chr;
    //读入一个字符,只可能读入#、左括号和字母
    if (isalpha(chr) && isupper(chr) || chr == '('){ //大写字母或'('
        bool b=true;
        ls = new GenListNode<T>;          //建子表结点
        cout<<'&';
        ls->utype = 2;
        if (isalpha(chr) && isupper(chr)){ //表名处理,有名子表
            int n = L1.Length();
            int m = L1.Search(chr);
            if (m != 0){                  //该表已建立
                b=false;                  //共享
                ls->info.hlink = *L2.getData(m);//查子表地址
                ls->info.hlink->info.ref++;     //引用计数加1
                cout<<'@';
                in >> chr;
                if (chr != '('&&chr!=','&&chr != ')') exit(1);  //表名后必跟'('或','或')'
                if(chr=='(')
                    do{
                        in>>chr; //共享表可以只输入表名,其它内容程序忽略
                    }while(chr!=')');
                else if(chr==','||chr == ')') in.putback(chr);//逗号或')'送回缓冲区
            }
            else{       //该表未建立
                ls->info.hlink = new GenListNode<T>;         //建附加头结点
                L1.Insert(n, chr);                           //保存表名及地址
                L2.Insert(n, ls->info.hlink);
                in >> chr;
                cout<<chr;
                cout<<'%';
                ls->info.hlink->utype = 0;
                ls->info.hlink->info.ref = 1;
                if (chr != '(') exit(1);    //表名后必跟'('
                CreateList(in, ls->info.hlink->tlink, L1, L2);//递归建子表
            }
        }
        else{//无名子表
            ls->info.hlink = new GenListNode<T>;
            cout<<'%';
            ls->info.hlink->utype = 0;         //建头结点
            ls->info.hlink->info.ref = 1;
            CreateList(in, ls->info.hlink->tlink, L1, L2);//递归建子表
        }
        CreateList(in, ls, L1, L2);                   //递归建后继表
    }
    else if (isalpha(chr) && islower(chr)){ //建原子结点。本程序现在仅在T为char时有效
            ls = new GenListNode<T>;
            cout<<'*';
            ls->utype = 1;
            ls->info.value = chr;//这里应该有将字符与T类型具体数据一一对应的表,最终把具体数据存入info.value
            CreateList(in, ls, L1, L2);
        }
    else if (chr == ','){       //建后继结点
            if (ls->tlink) delete ls->tlink;
            ls->tlink = new GenListNode<T>;
            CreateList(in, ls->tlink, L1, L2);
        }
    else if (chr == ')')    ls->tlink = NULL;  //链收尾
    else if (chr == '#')    ls = NULL; //空表, 链收尾
}

//打印数据
template<typename T>
void GenList<T>::Print(GenListNode<T>* p, ostream &out){ //共用一个out,out可以看作是一个全局变量
    if (p==NULL)
        return;                           //p为NULL结束
    if (p->utype==1)                      //原子结点
        out << (p->info).value << "   ";   //输出原子结点内的value的值
    else if (p->utype == 0)               //附加表头结点
            while (p->tlink!=NULL){           //关注此句,因为无返回指针,必须由while显式循环
                Print(p->tlink, out);         //以循环来代替通过返回值进行递归的操作
                p=p->tlink;               //返回指向同一层的下一个结点
            }
        else    Print(p->info.hlink, out);//子表结点
}

#endif

顺序表的相关头文件

SeqList.h

#ifndef SEQLIST_H
#define SEQLIST_H

#include <iostream>
#include <cstdlib>
#include <cassert>
using namespace std;

const int defaultSize = 100;

template <typename T>class SeqList
{
protected:
    T *data;
    int maxSize;
    int last;
public:
    SeqList(int sz = defaultSize);
    SeqList(SeqList<T> &L);
    ~SeqList(){
        delete []data;
    }
    void reSize(int newSize);
    int Size() const{
        return maxSize;
    }
    int Length()const{
        return last+1;
    }
    int Search(T &x) const;
    int Locate(int i) const;
    T* getData(int i) const{
        return (i>0 && i<=last+1)?&data[i-1]:NULL;
    }
    void setData(int i, T &x){
        if (i>0 && i<=last+1){
            data[i-1] = x;
        }
    }
    bool Insert(int i, T &x);
    bool Remove(int i, T &x);
    bool IsEmpty(){
        return (last == -1);
    }
    bool IsFull(){
        return (last == maxSize-1);
    }
    void Sort();
    void input();
    void output();
    SeqList<T> operator = (SeqList<T> &L);
    friend istream& operator >> (istream &in, SeqList<T> &R)    {
        R.last = -1;
        while (!in.eof()){
            R.last++;
            if (R.last == R.maxSize){
                R.reSize(2*R.maxSize);
            }
            assert(in >> R.data[R.last]);
        }
        return in;
    }
    friend ostream& operator << (ostream &out, SeqList<T> &R){
        for (int i = 0; i <= R.last; i++){
            cout << "#" << i+1 << ":\t" << R.data[i] << endl;
        }
        return out;
    }
};

template <typename T>SeqList<T>::SeqList(int sz){
    if (sz > 0){
        maxSize = sz;
        last = -1;
        data = new T[maxSize];
        if (data == NULL){
            cerr << "Memory allocating error!" << endl;
            exit(1);
        }
    }
}

template <typename T>SeqList<T>::SeqList(SeqList<T> &L){
    maxSize = L.Size();
    last = L.Length() - 1;
    data = new T[maxSize];
    if (data == NULL){
        cerr << "Memory allocating error!" << endl;
        exit(1);
    }
    for (int i = 1; i <= last+1; i++){
        data[i-1] = *(L.getData(i));
    }
}

template<typename T>void SeqList<T>::reSize(int newSize){
    if (newSize <= 0){
        cerr << "Invalid array index!" << endl;
        return;
    }
    if (newSize != maxSize){
        T *newarray = new T[newSize];
        if (newarray == NULL){
            cerr << "Memory allocating error!" << endl;
            exit(1);
        }
        int n = last + 1;
        T *srcptr = data;
        T *destptr = newarray;
        while (n--){
            *destptr++ = *srcptr++;
        }
        delete []data;
        data = newarray;
        maxSize = newSize;
    }
}

template<typename T>int SeqList<T>::Search(T &x)const{
    for (int i = 0; i <= last; i++){
        if (data[i] == x){
            return i+1;
        }
    }
    return 0;
}

template<typename T>int SeqList<T>::Locate(int i)const{
    if (i >= 1 && i <= last+1){
        return i;
    }
    else    return 0;
}

template<typename T>bool SeqList<T>::Insert(int i, T &x){
    if (last == maxSize-1)  return false;
    if (i < 0 || i > last+1) return false;
    for (int j = last; j >= i; j--)     data[j+1] = data[j];
    data[i] = x;
    last++;
    return true;
}

template<typename T>bool SeqList<T>::Remove(int i, T &x){
    if (last == -1){
        return false;
    }
    if (i < 1 || i > last+1){
        return false;
    }
    x = data[i-1];
    for (int j = i; j <= last; j++){
        data[j-1] = data[j];
    }
    last--;
    return true;
}

template<typename T>void SeqList<T>::Sort(){
    for (int i = 1; i <= last; i++){
        for (int j = last; j >= i; j--){
            if (data[j-1] > data[j]){
                T tmp = data[j-1];
                data[j-1] = data[j];
                data[j] = tmp;
            }
        }
    }
}

template<typename T>void SeqList<T>::input(){
    cout << "Input the size of the list which will be created:";
    while (1){
        assert(cin >> last);
        last--;
        if (last < 0){
            cout << "Input error, the size must be positive!\n";
            cout << "Input the size again:";
        }
        else if (last > maxSize-1){
            cout << "Input error, the size must be less than maxSize!\n";
            cout << "Input the size again:";
        }
        else    break;
    }
    cout << "\nInput the data for each element to create the list:" << endl;
    for (int i = 0; i <= last; i++){
        cout << "#" << i+1 << ":";
        assert(cin >> data[i]);
    }
}

template<typename T>void SeqList<T>::output(){
    cout << "\nThe size of the list is:" << last+1 << endl;
    for (int i = 0; i <= last; i++){
        cout << "#" << i+1 << ":\t" << data[i] << endl;
    }
}

template<typename T>SeqList<T> SeqList<T>::operator = (SeqList<T> &L){
    maxSize = L.Size();
    last = L.Length()-1;
    data = new T[maxSize];
    if (data == NULL){
        cerr << "Memory allocating error!" << endl;
        exit(1);
    }
    for (int i = 1; i <= last+1; i++){
        data[i-1] = L.getData(i);
    }
}

#endif

main.cpp测试函数

#include "GenList.h"
#include <fstream>
#include <string>
#include <cassert>
using namespace std;
#include<iostream>
int main(){
    ifstream fin1("data.txt");
    assert(fin1);
    string str;
    fin1 >> str;
    cout << "The genlist in the file is: \n" << str << endl;
    GenList<char> gl1;
    fin1.close();
    ifstream fin("data.txt");
    assert(fin);
    fin >> gl1;
    cout << "\nSome information about Genlist gl1:\n";
    cout << "\nThe data of GenList is:" << endl;
    cout << gl1 << endl;

    cout << "\nThe depth of the GenList is: " << gl1.depth() << endl;
    cout << "The length of the GenList is: " << gl1.Length() << endl;

    cout << "The First Element is: ";
    int temp = 0;
    if (gl1.First()){
        temp = gl1.First()->utype;
        if (temp == 1){
            cout << "AtomNode: " << gl1.First()->info.value << endl;
        }
        else if (temp == 0){
            cout << "HeadNode." << endl;
        }
        else{
            cout << "SubListNode." << endl;
        }
    }
    else{
        cout << "NULL!" << endl;
    }

    cout << "The Second Element is: ";
    if (gl1.Next(gl1.First())){
        temp = gl1.Next(gl1.First())->utype;
        if (temp == 1){
            cout << "AtomNode: " << gl1.First()->info.value << endl;
        }
        else if (temp == 0){
            cout << "HeadNode! " << endl;
        }
        else{
            cout << "SubListNode!" << endl;
        }
    }
    else{
        cout << "NULL!" << endl;
    }

//  GenList<char> gl2(gl1);//浅复制
    GenList<char> gl2;
    gl2.Copy(gl1);
    cout << "\ngl2 is a copy of gl1:\n";
    cout << "The data of gl2 is: " << endl;
    cout << gl2 << endl;

    if(gl1.equal(gl2)) cout<<"gl1 equals gl2.";
    else cout<<"gl1 do not equals gl2.";

    char rem;
    cout << "\nInput the data that you want to Remove: " << endl;
    cin >> rem;
    gl2.delvalue(rem);
    cout << "The current GenList gl2 is: " << endl;
    cout << gl2<< endl;

    cout << "\nInput the data that you want to Remove: " << endl;
    cin >> rem;
    gl1.delvalue(rem);
    cout << "The current GenList gl1 is: " << endl;
    cout << gl1<< endl;
    return 0;
}

今天对广义表的基本类定义以及函数的实现进行了统一的源码阅读,并标注了相应的注释,
主要收获是理解了一些和递归相关的问题。但还有一个最为重要的函数没有看懂CreateGenList()
函数,这个问题留着下一次解决
下一次将会对上面所抛出的实验问题进行代码的实行。
2017/4/23/ 11:47
问题的解决未完—-待续

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值