2021.12.13
学习了两个算法题,分别是链表一元多项式和括号的匹配,接下来分别解析两道题。
一,链表一元多项式
题目如下:
自定义一元多项式中的“项”结构,自定义一元多项式的链表结构。
设计函数Add(……),用于实现两个多项式的加法运算。
编写main()函数,分别读入两个多项式的数据,创建两个多项式链表。利用Add等函数,实现两个多项式的加法运算,并输出“多项式之和”的数据。要求按照多项式的幂的降序输出。
测试案例:
输入:
3
1 2
2 9
3 8
4
-3 8
5 2
3 10
9 0
输出:
3 10
2 9
6 2
9 0
解释:
第一个多项式是 2x^9+3x^8+x^2
第二个多项式是 3x^10-3x^8+5x^2+9
多项式之和是 3x^10+2x^9+6x^2+9
接下来先进行我的解题思路分享
先把链表构建好(因为我是在学习中,所以我不使用库,而是手搓了链表),链表中需要有指数,系数和next,同时我们也把重载放在了这个结构体Poly中
struct Poly
{
int coef;
int index;
Poly *next;//多了个next域;
friend ostream & operator<<(ostream &out, Poly &p)
{
return out<<p.coef<<" "<<p.index<<endl;
}
};
因为我使用的是c++,我将会使用面向对象的方式来写函数部分
class PolyList
{
Poly *Head;
public:
PolyList(){}
// 按照指数降序插入*newp
void Insert(Poly *newp){}
~PolyList(){}
void RemoveHead(){}
void Add(PolyList &L){}
void Output(){}
};
在构造函数中我们将把数据放链表中,哦,别忘了头指针的初始化也是在构造函数中完成的。
PolyList()
{
Head=NULL;
int n; cin>>n;
for(int i=0; i<n; i++)
{
Poly *newp =new Poly;
cin>>newp->coef>>newp->index;
Insert(newp); // 按照指数降序插入*newp;
}
}
①
先把newp和p连起来,再把head和newp连接起来 ,newp是一直在更新的,从Insert()外面传进来的值
再把head赋值给p
Poly *prev=NULL, *p=Head;
for(; p!=NULL; prev=p,p=p->next)
//循环的部分我写在下面
然后我们来说循环的意义,这就是个来进行newp和p大小比较的,如果交换了我们会用到prev来帮忙辅助进行数值交换
if(p->index <= newp->index)
break;
此处,p->index是2,newp->index是9,所以直接break
那么我们聊下如果newp的指数比p小呢,那就直接把p链到prev,因为p的next是空的,所以把p这一节删了,至于怎么删,后面说。这一页我一开始理解错了
②
在p之后插入newp,在prev后插入newp,是这个代码的核心
else
{
// 在*p之前插入*newp 在*prev之后插入*newp
newp->next=p;
if(prev==NULL)
Head =newp;
else
prev->next=newp;
}
newp完全给了head那这个newp的任务也就完成啦!这是我们第一次循环
小提一嘴,不想看的朋友这段可以直接跳过去3,但这一段在后面会用到
如果是9 2而非2 9,那我们就要动用prev,来进行排序交换了,最后会把prev链上newp
③
哦,第一次循环我就不提了,因为prev和p都是空,直接把newp给head基本就ok了
第三次循环,之前进行过的交换我就不提了,只提新的东西了
newp这次传进来的值是3 8
会初始化prev,并且把之前排好的,head完全给p,要知道,我们之前已经把head给填了2 9->1 2了
然后我们进行比较,会发现,我们需要把9和8进行交换,所以不break,进行一个prev=p,p=p->next,前一个prev=p,是动用prev先保存下来p的东西,这时候你观察地址会发现,prev和p地址是一样的了。然后p=p->next是我们之前埋下的一个坑,说好后面要用的,其实是p让next链的下面一个数据把自己覆盖了,就完成了消灭。
只要把newp接上p,就能看到3 8接上1 2了,那后面一定是2 9接上3 8接上1 2对吧
ok,因为这里prev不是空了,我们就可以用
if(prev==NULL)
Head =newp;
else
prev->next=newp;
的else段了,第二次循环用的是if,prev是最大的2 9,接上newp就是2 9接上3 8接上1 2啦!
一个疑问
这里prev不再给head好吗?
等会,你去调试下看看,这里prev怎么已经把值给head了!!!???
ok,这就是我们最后一个部分了,最终回
④
先回答上面的问题,因为prev的next和head的next地址一样!所以 prev的next变,head的next也就变了
ok,那么这三次循环做完,其实也就差不多了,我们梳理下,这里面用到的三个主要的指针变量
head,它作为头,有背负数据走下去的重任!别随便修改它,小心被搞得晕头转向
prev在进行交换的时候启动
newp带新数据进入函数
p其实可以看作一个小head,不过它隔三岔五就会被改,而且在结束的时候也会被delete
那么我们就把这个Insert()的运作原理几乎讲完了,是把它里面数据变化的方式用一个字一个字的方式说出来,以后应该不会这么说了。
同时,合并部分我们还没说,下面小聊下,这个不是很关键
void Insert(Poly *newp)
{
Poly *prev=NULL, *p=Head;
for(; p!=NULL; prev=p,p=p->next)
if(p->index <= newp->index)
break;
if(p!=NULL && p->index==newp->index)
{
// 同类项;
p->coef += newp->coef;
delete newp;
if(p->coef==0)
{
// 删除*p 删除*prev的后继结点;
if(prev==NULL)
Head =p->next;
else
prev->next=p->next;
delete p;
}
}
else
{
// 在*p之前插入*newp 在*prev之后插入*newp
newp->next=p;
if(prev==NULL)
Head =newp;
else
prev->next=newp;
}
}
最后我们聊下合并和ADD,Output等函数
(1)
如果指数相同,就把newp的系数给p,删了newp
然后排除0的情况,排除prev空,也就是没交换的情况,没了
(2)
add就是给个新空间装对象2,把对象2进行插入就行了
void Add(PolyList &L)
{
for(Poly *p=L.Head; p!=NULL; p=p->next)
{
Poly *newp =new Poly;
newp->coef=p->coef; newp->index=p->index;
Insert(newp);
}
}
(3)
output()就是head给一个新造的p,输出
void Output()
{
for(Poly *p=Head; p!=NULL; p=p->next)
cout<<*p;
cout<<endl;
}
(4)
析构函数和removehead就不说了,用完把head放掉罢了
~PolyList()
{//释放头节点;
while(Head!=NULL)
RemoveHead();
}
void RemoveHead()
{
Poly *p=Head;
Head=Head->next;
delete p;
}
最后,完整给下源代码吧,感谢能一路读到这里的人
也许我用词不规范,但是道理应该不错的
#include <iostream>
#include <fstream>
using namespace std;
struct Poly
{
int coef;
int index;
Poly *next;//多了个next域;
friend ostream & operator<<(ostream &out, Poly &p)
{
return out<<p.coef<<" "<<p.index<<endl;
}
};
class PolyList
{
Poly *Head;
public:
PolyList()
{
Head=NULL;
int n; cin>>n;
for(int i=0; i<n; i++)
{
Poly *newp =new Poly;
cin>>newp->coef>>newp->index;
Insert(newp); // 按照指数降序插入*newp;
}
}
// 按照指数降序插入*newp
void Insert(Poly *newp)
{
Poly *prev=NULL, *p=Head;
for(; p!=NULL; prev=p,p=p->next)
if(p->index <= newp->index)
break;
if(p!=NULL && p->index==newp->index)
{
// 同类项;
p->coef += newp->coef;
delete newp;
if(p->coef==0)
{
// 删除*p 删除*prev的后继结点;
if(prev==NULL)
Head =p->next;
else
prev->next=p->next;
delete p;
}
}
else
{
// 在*p之前插入*newp 在*prev之后插入*newp
newp->next=p;
if(prev==NULL)
Head =newp;
else
prev->next=newp;
}
}
~PolyList()
{//释放头节点;
while(Head!=NULL)
RemoveHead();
}
void RemoveHead()
{
Poly *p=Head;
Head=Head->next;
delete p;
}
void Add(PolyList &L)
{
for(Poly *p=L.Head; p!=NULL; p=p->next)
{
Poly *newp =new Poly;
newp->coef=p->coef; newp->index=p->index;
Insert(newp);
}
}
void Output()
{
for(Poly *p=Head; p!=NULL; p=p->next)
cout<<*p;
cout<<endl;
}
};
int main()
{
PolyList L1;
PolyList L2;
L1.Add(L2); L1.Output();
return 0;
}
二,括号的匹配
坏了,我已经写不动了
自定义栈结构,及其基本运算。
设计函数Match(……),判断字符串中的圆括号的匹配情况。
编写main()函数,读入一个字符串(长度小于1000),调用Match等函数。
若左右圆括号匹配,则输出"ok";
若左括号多于右括号,则输出"left"及所有失配的左括号的下标;
若右括号多于左括号,则输出"right"及第一个失配的右括号的下标。
测试案例1:
输入:
((a+b)*(c+d))
输出:
ok
测试案例2:
输入:
a+((a+b)*((c+d)+z
输出:
left 9 2
输出案例3:
输入:
(a+b)*(c+d))
输出:
right 11
简单概括下思想,就是左括号进栈,右括号出栈,最后检测栈内状况
直接丢代码吧,啊啊啊,我要死了。。。
#include<iostream>
#include <string>
using namespace std;
class LinkStack
{
char stack[1024];
int top = 1024;
bool gg = true;//判断是否需要进行ok和left
public:
LinkStack(){}
~LinkStack() {}
void push(char x)
{
top--;
stack[top] = x;
}
int pop()
{//删除栈顶数据;
char x = stack[top];
top++;
return x;
}
bool empty()
{
if (top == 1024)
return 1;
return 0;
}
//设计函数Match(……),判断字符串中的圆括号的匹配情况。;
void Match(char *x)
{
int n = 0,i=0,j=0;
int b[20],c[20];
while (*x != '\0')
{
char L = '/0';//左括号
char R = '/0';//右括号
char ch = *x;
switch (ch)
{
case'(':
push(ch);
i++;
b[i] = n;
if (j > 0)
j--;
break;
case')':
L = '(';
R = ch;
break;
default:
break;
}
n++;
if (R == ch)//11111111111
{
if (empty()==false)
{
char t = pop();//出栈
i--;
j++;
if (j != 0)
c[j] = n;
}
else
{
cout << "right"<<" ";
for (; j > 0; j--)
cout << c[j] << " ";
cout << endl;
gg = false;
}
}
x++;
}
if (gg == true)
{
if (int a = empty() == true)
cout << "ok" << endl;
else
{
cout << "left" <<" ";//
for (;i>0;i--)
cout << b[i]<<" ";
cout << endl;
}
}
}
};
int main()
{
char a[1024];
cin >> a;
LinkStack s;
s.Match(a);
return 0;
}