数据结构~常用链表介绍

数据结构(几种常用链表):

1:环形链表(应用:约瑟夫环)
代码内有部分注视方便阅读

#include <bits/stdc++.h>
using namespace std;

typedef struct ycc{
  int number;
  struct ycc* next;
}Y;

typedef struct ycc * YPro;

//约瑟夫环, N:游戏人数, M:数到M的人退出
void ysf(int n,int m);

int main() {
    ysf(5,3);
    return 0;
}

/**
 * @param n:游戏人数
 * @param m:数到M的玩家退出环
 */
void ysf(int n,int m){
    int i=1;
    //一共5个人玩约瑟夫环,每次数到数字3的退出,从1开始数到3
    YPro friends=(YPro)malloc(sizeof(Y));
    friends->next=friends;
    friends->number=1;
    YPro tem=friends;
    for(int i=2;i<=n;i++){
        YPro kk=(YPro)malloc(sizeof(Y));
        kk->number=i;
        kk->next=friends;
        tem->next=kk;
        tem=kk;
    }
    tem=friends;
    while (tem->next!=tem){
        tem=tem->next;
        i++;
        if (i==m-1){
            YPro f=tem->next;//记录一下被删除的地址
            tem->next=tem->next->next;//删除此玩家
            free(f);//释放此地址指向的内存
            i=0;//重新计数
        }
    }
    cout<<"win:   "<<tem->number;
}

2:单链表(带有头结点,应用:一元多项式的乘法与加法运算)
代码内有丰富注视,很好理解

题目描述:

设计函数分别求两个一元多项式的乘积与和。

输入格式:

输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。

输出格式:

输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出0 0。

输入样例:

4 3 4 -5 2 6 1 -2 0

3 5 20 -7 4 3 1

输出样例:

15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1

5 20 -4 4 -5 2 9 1 -2 0

首先提一下测试用例,我猜测的有一下几种特殊情况,

乘积为0
0
1 1 1

和为0
1 1 1
1 -1 1

二者都为0
0
0

虽然题目上说的输入不能为0,但是咱也考虑进去。提一下,我就是没考虑0,最后一个2分的测试用例一直没过。。。也可能是解决0问题的时候顺带解决了用例的问题。

使用的带有头结点的链表,代码如下:

#include <bits/stdc++.h>

using namespace std;

typedef struct dxs* DPro;
typedef struct dxs{
    int x;///系数
    int z;///指数
    DPro next;///指向下一个节点
}D;

DPro creat(int n);///创建一个数据长度为n的链表,带头节点
void sout(DPro L);///输出链表L,带头节点
void attach(int c,int e,DPro *tail);///创建新节点,插入到链表中,tail为链表的尾巴
DPro multiply(DPro P1,DPro P2);///两个链表的乘法,返回结果链表
DPro sum(DPro P1,DPro P2);///两个链表的额加法,返回结果链表

int main(){
    int d1Num,d2Num;///分别记录两个多项式的项数

    cin>>d1Num;
    DPro d1=creat(d1Num);///创建第一个多项式链表
    DPro d1t=d1;///创建一个临时使用的指针,指向第一个多项式链表的头

    cin>>d2Num;
    DPro d2=creat(d2Num);///创建第二个
    DPro d2t=d2;///创建第二个临时使用

    sout(multiply(d1t,d2t));///输出乘后的结果链表
    d1t=d1;///临时指针1恢复指向到第一个多项式链表的头
    d2t=d2;///临时指针2恢复指向到第二个多项式链表的头
    sout(sum(d1t,d2t));///输出加后的结果链表
    return 0;
}


/**
 * 创建一个有头节点的链表
 *
 * @param n 这个多项式的项数
 * @return 返回创建好的链表的头地址
 */
DPro creat(int n){
    int x,z;
    DPro head=NULL,tail=NULL;
    head = (DPro)malloc(sizeof(D));
    head->next=NULL;tail=head;
    while (n--){
        cin>>x>>z;
        attach(x,z,&tail);///将新项加到多项式的尾巴上,同时尾巴变为新项,然后尾巴的下一个指向null
    }
    return head;///返回头节点,也就是火车的列车长,这个车头可以理解为不坐乘客,也就是无内容,但他可以派遣多个列车工作人员分别到其他车厢,对该车厢 做 增删改查 的工作
}

/**
 * 输出一个有头结点的链表
 * @param L 传入链表的头
 */
void sout(DPro L) {
    int sign=0;///用于输出格式的控制,最后面不输出多余空格
    DPro a = L;///OK,a现在来到火车头,静待车头里的列车长的安排
    a = a->next;///现在a走出列车头,开始往后走
    if (!a) {///如果是个空链表。也就是就到刚出车头,就到空着的车尾了
        cout << "0 0" << endl;///输出零多项式后退出函数
        return;
    }
    while (a != NULL) {
        if (!sign){
            sign=1;
        }else {
            cout <<" ";
        }
        cout<< a->x << " " << a->z;
        a = a->next;
    }
    cout << endl;
}



/**
 * 将一个新数据插入到老链表的尾巴,然后尾巴的next指向null
 * @param c 新数据的系数
 * @param e 新数据的指数
 * @param tail 被插入的老链表的尾巴
 */
void attach(int c,int e,DPro *tail){
    DPro P;///这是一个新车厢,需要加到列车的后边
    P = (DPro)malloc(sizeof(D));///给这个车厢内部空间
    P->x = c;
    P->z = e;///输入内容,乘客上车
    P->next = NULL;///车尾指向空
    (*tail)->next = P;///新车厢成为尾部
    *tail = P;///一直在尾部工作的这个人,往后走一个车厢,到最后一个车厢继续工作,,,他又开始等待着新的车厢的到来...
}

DPro sum(DPro P1,DPro P2){///两个多项式的和操作
    DPro P,tail,t1,t2;///这天有4个人,被火车公司录用,等待工作
    int sum;///用来记录系数和
    t1 = P1;///现在t1收到P1列车长的面见,
    t2 = P2;///接着t2收到P2列车长的面见,
    DPro tem1=t1->next,tem2=t2->next;///他们两个被两个车长秘密安排后,开始执行各自的任务
    P = (DPro)malloc(sizeof(D));///P这个员工想搞事情,于是开辟了一个新车厢需要的内存。当然P代表的就是和结果的链表的头
    P->next = NULL;///然后P妄图当列车长,控制车头
    tail = P;///然后这个憨憨的tail,被P召见,P现在已经当上了车长,很得劲儿,于是直接开始使用自己的权利,交给tail的工作是,扩展自己的车厢,也就是在车尾做添加车厢的工作

    if(!tem1&&!tem2)///如果P1,P2两个列车都是只有车头和空车尾,就直接让自封的列车长P出去办事。也就是如果两个都是空,返回带头的空链表,
        return P;
    else if(!tem1)///如果第一个为空,返回第二个多项式链表
        return t2;
    else if(!tem2)///第二个为空,就返回第一个
        return t1;

    t1=t1->next;
    t2=t2->next;///t1,t2继续各自的工作,往后走

    while(1){
        if(t1 != NULL&&t2 != NULL){///当他们都没有走到车尾的时候
            if(t1->z == t2->z) {///如果这俩人分别到的他们的这节车厢的指数相等,就把他们的系数加一块,然后,嘿嘿嘿,tail来一下有点事。tail:好嘞!!!
                sum = t1->x + t2->x;
                if(sum != 0)
                    attach(sum,t1->z,&tail);
                t1 = t1->next;
                t2 = t2->next;///他俩继续走
            }
            else if(t1->z > t2->z) {///如果t1的指数更大,就把t1安排到自封列车长P的列车的尾部,当然这个工作就又交给憨憨的tail了
                attach(t1->x,t1->z,&tail);
                t1 = t1->next;
            }
            else {///如果t2的指数更大,就把t2安排到自封列车长P的列车的尾部,当然这个工作就又交给憨憨的tail了
                attach(t2->x,t2->z,&tail);
                t2 = t2->next;
            }
        }
        else if(t1 != NULL) {///如果t2走到了P2的尾部,就把t1存到tail
            attach(t1->x,t1->z,&tail);
            t1 = t1->next;
        }
        else if(t2 != NULL) {///如果t1走到了P1的尾部,就把t1存到tail
            attach(t2->x,t2->z,&tail);
            t2 = t2->next;
        }
        else ///如果t1 t2 都到尾部了,就退出循环,tail的工作完成
            break;
    }
    return P;///现在P控制的列车变长了,都是tail努力的成果,换来了车长P的意气风发,返回头结点P。/
}


DPro multiply(DPro P1,DPro P2) {///两个多项式的乘的计算
    DPro head, tail, t1, t2, t;///录用新工作人员
    int c, e;///用于新车厢的内容填充,可以理解为候车室的人
    t1 = P1;///P1面见t1
    t2 = P2;///P2面见t2
    ///构建新列车
    head = (DPro) malloc(sizeof(D));///领导给head一个创建新车的任务,并且画了一个大饼,head于是去创建自己的车头,先给自己一个工作的地方
    head->next = NULL;///head现在只有一个车头,车尾是空的
    tail = head;///tail被head叫了过来,面见一下
    t1=t1->next;
    t2=t2->next;///这俩工具人,常年工作在P1跟P2上。。。
    if (!t1 || !t2) {///如果P1 P2有一个为空链表,就直接返回空的head
        return head;
    }
    while (t2) {///先用P1的第一项乘以P2
        attach(t1->x * t2->x, t1->z + t2->z, &tail);///tail给head扩建车厢
        t2 = t2->next;
    }
    t1 = t1->next;///P1的第一节车厢给P2的所有车厢乘过后,t1向后走一个车厢
    while (t1) {
        t2 = P2->next;///t2回到P2的第一节车厢,重复之前的继续往后,t1每乘完P2的所有车厢就往后走一个,同时t2回到P2的第一节车厢
        tail = head;///tail回到head身边汇报一下,然后继续从第一节车厢往后
        while (t2) {
            c = t1->x * t2->x;///系数相乘
            e = t1->z + t2->z;///指数相加
            while (tail->next && tail->next->z > e)///要插入的与链表中的比较,如果比链表中的小,就将tail后移
                tail = tail->next;
            if (tail->next && tail->next->z == e) {///如果相等
                if (tail->next->x + c)///加起来不等于0的话就直接系数累加
                    tail->next->x += c;
                else {///等于0的话直接删掉,然后释放内存即可
                    t = tail->next;
                    tail->next = t->next;///删除操作
                    free(t);///释放这节车厢
                }
            } else {///要插入的与链表中的比较,如果比链表中的大,就要构造空结点,进行插入操作
                t = (DPro) malloc(sizeof(D));///开辟新车厢,等待插入
                t->x = c;
                t->z = e;///填充内容

                ///插入
                t->next = tail->next;
                tail->next = t;
                tail = tail->next;
            }
            t2 = t2->next;
        }
        t1 = t1->next;
    }
    return head;
}

3:双向链表(创建一个双向链表,左右依次储存一串数,并输出)

#include <bits/stdc++.h>
using namespace std;
typedef struct node* NPro;
typedef struct node{
    int data;
    NPro left;//左节点
    NPro right;//右节点
}N;

//左边尾部增加节点
void addLeftNode(int newData,NPro list);
//右边尾部增加节点
void addRightNode(int newData,NPro list);
//输出一条双向链表
void sout(NPro list);

int main() {
    NPro list=(NPro)malloc(sizeof(N));
    list->left=NULL;
    list->right=NULL;
    list->data=10;//先给中间这个节点赋一下值
    NPro tem=list;
    for(int i=0;i<9;i++){
        if(i%2==0){
            addRightNode(i,tem);//如果是偶数,就放到最右边
        }else{
            addLeftNode(i,tem);//奇数去左边
        }
    }
    sout(list);//此时传入的是中间节点
    return 0;
}

//从左向右输出一条双向链表
void sout(NPro list){
    NPro tem=list;
    NPro r=tem;

    while (r->right){
        cout<<r->data<<" ";
        r=r->right;
    }
    cout<<endl;
    while(tem->left!=NULL){
        tem=tem->left;
    }
    while (tem->right!=NULL){
        cout<<tem->data<<" ";
        tem=tem->right;
    }
    cout<<tem->data;
}
//左边尾部增加节点
void addLeftNode(int newData,NPro list){
    NPro left=list;
    while (left->left!=NULL){
        left=left->left;
    }
    NPro kk=(NPro)malloc(sizeof(N));
    kk->data=newData;
    kk->right=left;
    left->left=kk;
    left=kk;
    left->left=NULL;
}
//右边尾部增加节点
void addRightNode(int newData,NPro list){
    NPro right=list;
    while (right->right!=NULL){
        right=right->right;
    }
    NPro kk=(NPro)malloc(sizeof(N));
    kk->data=newData;
    kk->left=right;
    right->right=kk;
    right=kk;
    right->right=NULL;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值