C++实现简单单向链表——以多项式为例

数据结构课堂笔记 —— 单链表

本篇主要是一步一步、循序渐进实现单链表的操作,比较适合初学者参阅。

一、分步讲解

理清单链表实现的过程,从输入单个节点到输出整个链表的过程

  1. 从创建一个结构体开始
    首先先定义我们的节点PNode,它包含了多项式的系数、指数,以及指向下一个节点的指针next。
 struct  PNode
 {
     int xishu;
     int zhishu;
     PNode* next;
 };
  1. 定义链表的头结点
    用new来新建头结点P
//initial the head Node
    //头结点建了之后再也不动,以后想用的时候就可以拿
    PNode *P;//head node: P
    P = new PNode;
    P->next = NULL;

萌新在做完这一步之后,可以测试一下,看看自己最开始的部分有没有出错。比如:

    p->xishu = 1;
    cout<<p->xishu;
  1. 创建一个操作指针s
 PNode* s = P;//现在有两个指针指向头节点,
                //P用来表示头指针,s用来遍历链表的指针

  1. 输入节点数量
    创建完两个重要指针之后,就考虑链表的节点,首先确定节点的数量n
 int n;//length of the polynomial
    cout<<"输入节点个数:"<<"\n";
    cin>>n;
  1. 正式输入节点——创建链表
    输入节点的时候,先新建一个节点q, 用来保存我们输入的节点,在得到新节点之后,把新的节点连接起来,之后,重复操作,直到所有节点都被输入并链接完整,至此整个链表创建完成。
 cout<<"开始输入节点:"<<"\n";

    //initial the data, Node
    for (int i = 0; i < n; i++)
    {
        //cout<<i;
        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
    }
  1. 输出链表
    输出链表主要可以参考输入链表时的操作,也是通过操作指针s来遍历每一个节点,逐个输出节点的内容。
   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移到下一个节点的位置
    }
二、整合成型

单链表最基本的操作已经完成了,此时我们把它整合在一起来测试一下。
整合成型的操作主要在于提函数

  • 提函数的要点:

    1. 函数返回值
      这段代码有返回值吗?返回值目的是什么,有什么值以后还用
      不需要返回值 ——void

    2. 函数名,不要冲突

    3. 参数
      这段代码哪个值最重要,哪个值传进来就能用了
      参数什么类型的,回去看
      并且这个参数传进来之后需不需要被改变
      如果不需要变,就不要被引用,就是不要&取地址符
      参数越少越好,能不传则不传

  • 由于输入和输出链表这几段代码我们会反复用到多次,所以我们把其封装成方法
    例:
    创建链表
    创建链表本应该返回这个链表的头指针,方法头:返回值类型+方法名+参数—— 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 <iostream>
using namespace std;
int main()
{
    PNode* L;
    createPolyn(L);
    output(L);
    return 0;
}
三、两个多项式相加的操作

在上面我们已经实现了一个表示多项式的单链表输入输出操作,而想要实现两个多项式相加首先我们得考虑到多项式相加会出现哪些情况:

  1. 将链表节点按指定顺序排列
    由于我们是通过操作指针来遍历操作链表,它的特点是逐个遍历链表的节点,那么多项式相加时先把每一项按指数从小大排好序才方便我们之后的操作。为此,我们把上面创建链表的方法重新完善一下。(在插入新节点时,增加了判断指数大小,按照指定位置插入新节点的操作,while循环的条件一个是这个链表是否还有下一个节点,一个是下一个节点和新输入的节点谁的指数更大)
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. 多项式相加时有几种情况:
    (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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值