浙大数据结构自用笔记(3)--线性表之链表

链表的基本概念

在这里插入图片描述

链表的基本操作

链表和结点的定义
/*
链表:定义结点

*/
typedef struct LNode *List;   //将《结点的地址》类型重命名为List
struct LNode  //定义《结点》类型
{
    ElementType Data; //结点的数据
    List Next;   //下一个结点的地址
};
struct LNode L; //定义一个《结点》类型的变量,变量名为L
List PtrL;  //定义一个《结点的地址》类型的变量,变量名为PtrL,即链表的头
计算链表的表长
/*
求表长
分析:遍历的方式
时间复杂度:O(n)
*/
int Length(List, PtrL0)
{
    List p = PtrL;  //将用于遍历的指针放到表头
    int j = 0;  //用于计数
    while (p) //当p不为null时,即链表不为空,循环继续
    {
        p = p->Next; //让p指针沿着链表往后挪一位,即p指向下一个结点
        j++;   //当前p指向的是第j个结点
    }
    return j;
}
查找:按序查找
/*
查找:按序号查找
时间复杂度:O(n)
结果:返回第K个结点的指针
*/
List FindKth(int K, List PtrL)
{
    List p = PtrL; //把p放在表头
    int i = 1;  //i表示第几个元素
    while (p != NULL && i<K)  //链表不为空 且 还没找到第K个元素
    {
        p = p->Next;  //p往后挪一个结点
        i++;
    } //循环终止:链表为空或者i = K,即找到了
    if (i == K)
        return p;  //找到第K个,返回指针
    else
        return NULL; //否则返回空
}
查找:按值查找
/*
查找:按值查找
时间复杂度:O(n)
结果:返回值为X的结点的指针
*/
List Find(ElementType X, List PtrL)
{
    List p = PtrL;
    while (p != NULL && p->Data!=X) //链表不为空 且 还没找到值=X的元素
        p = p->next; //p往后挪一个结点
    return p;
}

插入

/*
插入:在第i-1(1<=i<=n+1)个结点之后插入一个值为X的新结点
分析:
    1.构造一个新结点,用s指向
    2.找到链表的i-1个结点,用p指向
    3.然后修改指针,插入结点(p后面跟着s)
        ①s->Next = p->Next;
        ②p->Next = s;
        ①和②不可以交换顺序,必须要先把新结点和后面连起来
        如果交换顺序为②①,则无法找到中p原本后面那个结点的地址(原本是用p->next指向的)
结果:返回插入后的头指针
平均查找次数:n/2
时间复杂度:O(n)
*/
List insert( ElementType X, int i, List PtrL)
{
    List p, s; //定义存放结点地址的变量,其中p变量用于存放第i-1个结点的地址,s变量用于存放新结点的地址
    if(i == 1)  //头插
    {
        s = (List)malloc(sizeof(struct LNode)); //为新的结点申请内存,并用s存放这块内存的首地址
        s->Data = X;  //给这个结点装上数据X
        s->Next = PtrL; //把s装到链表的前面
        return s;
    }
    p = FindKth (i-1, Ptrl); //找第i-1个结点
    if (p == NULL)   //第i-1个结点不存在
    {
        printf("参数i错误");
        return NULL;
    }
    else //p存在,开始插入
    {
        s = (List)malloc(sizeof(struct LNode)); //为新的结点申请内存,并用s存放这块内存的首地址
        s->Data = X;  //给这个结点装上数据X
        s->Next = p->Next; //插入,这一行与下一行不能颠倒顺序
        p->Next = s;
        return Ptrl;
    }
}
/*
总结:
霸道的结点:每个结点有两个口袋,左口袋装着数据,右口袋装着下一个结点的地址
    如果我的口袋里面装着你的地址,即使我是新来的,我也在你的前面
    头插:虽然我是新来的,但是我右口袋里面装着你们一条街第一户的地址,那么我在你们这条街的前面
    非头插:我要知道上一家才能把我家地址放到它右口袋啊,首先要知道有没有上一家,如果没有,插入失败
*/

删除

/*
删除:删除链表的第i(1<=i<=n)个位置上的结点
分析:
    1.先找到链表的第i-1个结点,用p指向
    2.再用指针s指向要被删除的结点(p的下一个结点)
    3.然后修改指针,删除s所指的结点
    4.最后释放s所指结点的空间  //不free卡死你
*/
List Delete(int i, List PtrL)
{
    List p, s; //定义存放结点地址的变量,其中p变量用于存放第i-1个结点的地址,s变量用于存放第i个结点的地址
    if(i == 1) //删除头结点
    {
        s = PtrL; //s存放的是头结点的地址,PtrL一直存放的是头结点的地址,所以要单独定义一个s,这步不能省略
        if (PtrL != NULL) //链表不为空
            PtrL = PtrL->Next; //删除操作
        else
            return NULL;
        free(s); //释放被删结点的空间
        return PtrL;
    }
    p = FindKth(i-1, PtrL); //查找第i-1个结点,并用p存放这个结点的地址
    if (p == NULL) //第i-1个结点为空,没有第i个的地址,无法删除
        {
            printf("第%d个结点不存在", i-1);
            return NULL;
        }

    else if (p->Next == NULL) //第i个结点为空,无法找到第i-1个后面的后面那个结点,无法删除
        {
            printf("第%d个结点不存在", i);
            return NULL;
        }
    else
    {
        s = p->Next; //用s存放要被删除的结点地址
        p->Next = s->Next; //删除操作
        free(s); //释放被删除结点的空间
        return PtrL;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值