问题抛出:利用广义表解决下列多项式的存储问题
实验内容
实验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> <); //返回表尾,除了首元素以外剩下的元素
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> <){//返回表尾
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
问题的解决未完—-待续