本篇主要是一步一步、循序渐进实现单链表的操作,比较适合初学者参阅。
理清单链表实现的过程,从输入单个节点到输出整个链表的过程
struct PNode
{
int xishu;
int zhishu;
PNode* next;
};
//initial the head Node
//头结点建了之后再也不动,以后想用的时候就可以拿
PNode *P;//head node: P
P = new PNode;
P->next = NULL;
萌新在做完这一步之后,可以测试一下,看看自己最开始的部分有没有出错。比如:
p->xishu = 1;
cout<<p->xishu;
PNode* s = P;//现在有两个指针指向头节点,
//P用来表示头指针,s用来遍历链表的指针
int n;//length of the polynomial
cout<<"输入节点个数:"<<"\n";
cin>>n;
cout<<"开始输入节点:"<<"\n";
//initial the data, Node
for (int i = 0; i < n; i++)
{
//cout<
PNode* q = new PNode;//新建节点q来存储输入的数据,形成单个的节点
cin>>q->xishu>>q->zhishu;
q->next = NULL;//这个不要落下
//这句话很重要,告诉链表结束了
//可以靠这个来判断结束
s->next = q; //把q节点给s,操作指针s的下一个节点指向新节点q
//即头结点P连接上了第一个节点q
s = s->next;//也可以写s = q->next;此时s 和 q 都是指向q那个节点
//s开始往后挪,s把每次上一个连接上新的节点p
}
s = P->next;//把s定位在首元结点的位置,即头结点P的后面连接的第一个节点
for (int i =0; i < n; i++)
{
cout<<s->xishu<<"x^"<<s->zhishu;
if(s->next)
if(s->next->xishu > 0)
cout<<'+';
s = s->next;//输出完一个节点内容后,操作指针s移到下一个节点的位置
}
单链表最基本的操作已经完成了,此时我们把它整合在一起来测试一下。
整合成型的操作主要在于提函数
提函数的要点:
函数返回值
这段代码有返回值吗?返回值目的是什么,有什么值以后还用
不需要返回值 ——void
函数名,不要冲突
参数
这段代码哪个值最重要,哪个值传进来就能用了
参数什么类型的,回去看
并且这个参数传进来之后需不需要被改变
如果不需要变,就不要被引用,就是不要&取地址符
参数越少越好,能不传则不传
由于输入和输出链表这几段代码我们会反复用到多次,所以我们把其封装成方法。
例:
创建链表
创建链表本应该返回这个链表的头指针,方法头:返回值类型+方法名+参数—— PNode* createPolyn(),同时返回创建完后的链表的头指针P,即: return P,然后把上面我们最开始写的创建链表那段代码(步骤2、3、4、5)放进方法里面。
在C++中有更简洁的操作引用——&,所以,我们可以直接在将该方法定义为void返回类型,在方法参数中,直接引用链表头结点来对头结点所要链接的内容直接操作。代码如下:
//创建一个链表
/**
首先要考虑返回值
*/
/**
不用这个,用引用来返回值
PNode* createPolyn()
*/
void createPolyn(PNode* &P)
{
/**
PNode *P;
*/
P = new PNode;
P->next = NULL;
PNode* s = P;
int n;
cin>>n;
for(int i = 0 ;i < n; i++)
{
PNode * q = new PNode;
cin>>q->xishu>>q->zhishu;
q->next = NULL;
s->next = q;
s = s->next;
}
//return P;
}
void output(PNode *P)
// void output(PNode *P, int n)
{
cout<<"输出链表:"<<"\n";
PNode* s;
s = P->next;
//用判断为空来结束,此时不用传n这个参数了
// while (s!=NULL)这两个有什么区别:多和少的区别,null就是0
while (s)
{
cout<<s->xishu<<"x^"<<s->zhishu;
if(s->next)
if(s->next->xishu > 0)
cout<<'+';
s = s->next;
}
}
#include
using namespace std;
int main()
{
PNode* L;
createPolyn(L);
output(L);
return 0;
}
在上面我们已经实现了一个表示多项式的单链表输入输出操作,而想要实现两个多项式相加首先我们得考虑到多项式相加会出现哪些情况:
void createPolyn(PNode* &P)
{
P = new PNode;
P->next = NULL;
PNode* s = P;
int n;//length of the polynomial
cin>>n;
PNode* pre;
for(int i = 0; i < n; i++)
{
PNode* q = new PNode;
cin>>q->xishu>>q->zhishu;
q->next = NULL;
//连接新的节点时,直接按照指数大小排列的顺序将新节点插到相应的位置
pre = P;
while (pre->next && pre->next->zhishu < q->zhishu)
{ //pre始终指向前一个pre的next的指数去比较的
pre = pre->next;
}
q->next = pre->next;//把刚刚找到的那个比新节点指数大的节点接在新节点后面
pre->next = q;
//这样就是从小到大排好的
//s->next = q;
//s = s->next;
}
}
多项式相加时有几种情况:
(1)指数相等,系数相加。
---->系数加出来得零,去掉这一项.
----->不为零,每个指针向后挪
(2) 指数不同时的操作。
我们是把最终结果的链表定位在第一条链表上,另一条链表释放掉。
相当于两条链表节点相加后,把结果输入在第一条链表的上一个节点里面,然后继续去加后面的节点的内容。
当遇到指数不同时,不能进行相加的操作,这种时候,有两种情况:
---->第一种是第一条链表的指数更小,按照指数由小到大的顺序,那么结果节点就应该是第一条链表的节点,指向结果链表的指针挪到第一条链表的那个更小的节点上,而第二条链表的操作指针不变,等待下一次判断。
---->第二种情况是第二条链表上的指数更小,由于我们的结果链表操作指针指向在第一条指针上,所以此时第一条链表的操作指针不动,结果链表操作指针指向第二条链表那个指数更小的节点,第二条链表的操作指针向后挪,结果链表操作指针再指回第一条链表。
void addPolyn(PNode* La, PNode* Lb,PNode* &P)
{
PNode* p1 = La->next;
PNode* p2 = Lb->next;
PNode* p3 = P = La;//P是引用,最后要带回去的,是最终结果的头结点
//P不能动,代表了整个链表
PNode* q; // 用来释放节点以及暂时储存节点的指针
while (p1 && p2)
{//只要一个为空,就停下来
if (p1->zhishu == p2->zhishu)
{
p1->xishu += p2->xishu;
q = p2;
p2 = p2->next;
delete q;//释放加完后的p2指向的Lb上的节点
/**
如果系数等于0,那就不需要把加好的节点连接在结果链表后面
只需要把加完后系数为零的这一项的节点释放就行,指针向后挪一位
*/
if (p1->xishu == 0)
{ //要是系数加起来等于0,
q = p1;
p1 = p1->next;
p3->next = p1;
delete q;
}else
{ //加完之后,把加好的那一项连接在p3指向的结果链表上面
p3 = p1;
p1 = p1->next;
}
}else if(p1->zhishu < p2->zhishu)
{
p3 = p1;
p1=p1->next;
}else
{
p3->next = p2;//p2指的这个节点连上p3指的节点
p3 = p2; //连接好之后,p3向后挪一位,来到刚刚连上的p2的位置
p2 = p2->next;//p2向后挪一位,注意先挪p2操作指针,再来调整p3的下一个指针该指向哪
p3->next = p1; //p3重新回到了p1指的那条链表La上面
}
delete Lb;
p3->next =p1?p1:p2;//谁先结束后,把还有剩下的接在p3后面
}
}
int main(int argc, char** argv)
{
PNode* La;
PNode* Lb;
PNode* Lc;
createPolyn(La);
createPolyn(Lb);
addPolyn(La,Lb,Lc);
output(Lc);
return 0;
}