链表知识总结

本文介绍了线性表的概念,包括线性关系和线性表的顺序存储(顺序表)与链式存储(链表)的比较。链表的结构包括单链表、双向链表和循环链表,以及哨兵节点的作用。此外,详细阐述了单链表的基本操作,如创建、长度计算、判断空表、查找、插入和删除等操作,还包括了链表的反转和循环链表的查找方法。
摘要由CSDN通过智能技术生成

一、线性表的概念

线性关系

  1. 当1<i<n时,ai的直接前驱为ai-1, ai的直接后继为ai+1
  2. 除了第一个元素与最后一个元素,序列中任何一个元素有且仅有一个直接前驱元素, 有且仅有一个直接后继元素。
  3. 数据元素之间的先后顺序为“一对一”的关系。

线性表

  • 数据元素之间逻辑关系为线性关系的数据元素集合称为线性表。
  1. 线性表的顺序存储(顺序表):用一组地址连续的存储单元依次存储线性表的数据元素,数据元素之间的逻辑关系通过数据元素的存储位置直接反映。一般情况下采用数组存储。

  2. 线性表的链式存储(链表):用一组地址任意的存储单元(连续的或不连续的)依次存储表中各个数据元素, 数据元素之间的逻辑关系通过指针间接地反映出来。

顺序表与链表的比较

  • 存储分配方式

    • 顺序存储用一段连续的存储单元依次存储线性表的数据元素
    • 链表采用链式储存结构,用一组不连续的存储单元存放线性表的元素
  • 时间性能

    • 查找

      • 顺序存储:无序O(n),有序O(log2 n)
      • 链表O(n)
    • 插入和删除

      • 顺序存储需要平均移动表长一半的元素,时间为O(n)
      • 链表在给出结点位置后,插入和删除时间仅为O(1)
  • 空间性能

    • 顺序存储需要事先分配存储空间,分大了浪费,分小了易发生溢出
    • 链表不需要事先分配存储空间,需要时分配结点,元素个数不受限制

在这里插入图片描述

二、链表的概念

定义:链表是一种物理存储上非连续、非顺序的存储结构,数据元素的逻辑顺序通过链表中的指针链接次序实现。

在这里插入图片描述

链表的结构:自引用结构

自引用结构分为两部分:

  1. 数据域:存储实际的数据
  2. 指针域:一个或多个指向自身结构类型的指针,用于存储数据的关系(如:下一个元素的位置)
//ElemType为数据类型,使用前需定义。
//如 #define ElemType int 或 typedef int ElemType
typedef struct node
{
    ElemType val;
    struct node *next;
}LNode,*LinkList;

链表的分类

单链表

在这里插入图片描述

双向链表
  • 双向链表是指链表的每一个结点中除了数据域以外设置两个指针域,其中之一指向结点的直接后继结点,另外一个指向结点的直接前驱结点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ucfwRP93-1683127239732)(图片/链表/双链表.png)]

循环链表
  • 循环链表是指链表中最后那个链结点指针域存放指向链表最前面那个结点的指针,整个链表形成一个环

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZQthHx5K-1683127239733)(图片/链表/循环链表.png)]

哨兵节点

在这里插入图片描述

  • 定义一个空结点(不存储任何数据),链表初始化时直接创建。

  • 该结点创建后,地址不做任何修改;链表的头指针指向哨兵节点

  • 第一个数据结点为头结点后面的第一个结点,后续操作只可能在

    头结点后面进行操作,不涉及任何头指针的修改

  • 设置头结点的最大好处是对链表结点的插入及删除操作统一了,不用单独考虑是否需要修改头指针。其数据域一般无意义(也可存放链表的长度)

三、单链表的基本操作

链表的创建

链表的创建可分为头插法尾插法

头插法
  • 在头节点后面插入新的节点,每个新产生的节点都会被接在头节点后面。

    在这里插入图片描述

LinkList create_head(int n)
{
    LinkList head =(LinkList)malloc(sizeof(LNode));
    head->val = n;//哨兵节点,方便插入与删除操作。如果ElemType类型为int可以存储链表的长度
    head->next = NULL;
    for (int i = 0; i < n;i++)
    {
        LinkList p=(LinkList)malloc(sizeof(LNode));
        p->next = NULL;
        scanf("%d", &p->val);//ElemType类型默认int
        p->next = head->next;
        head->next = p;
    }
    return head;
}
尾插法
  • 每个新节点都插在表尾

在这里插入图片描述

LinkList create_tail(int n)
{
    LinkList head =(LinkList)malloc(sizeof(LNode));
    head->val = n;//哨兵节点,方便插入与删除操作。如果ElemType类型为int可以存储链表的长度
    head->next = NULL;
    struct node *p=head, *q;
    for (int i = 0; i < n;i++)
    {
        q=(LinkList)malloc(sizeof(LNode));
        q->next = 0;
        scanf("%d", &q->val);//ElemType类型默认int
        p->next = q;
        p = p->next;
    }
    return head;
}

求线性链表的长度

int length(LinkList head)
{
    int num = 0;
    LinkList p = head->next;
    while(p)
    {
        num++;
        p = p->next;
    }
    return num;
    /*
    如果哨兵节点维护链表长度,直接输出哨兵节点数据
    return head->val;
    */
}

判断链表是否为空

int isempty(LinkList head)
{
    if(head->next)
        return 0;
    else
        return 1;
}

查找

按值查找
//查找成功,返回被查找节点地址,否则返回NULL
LinkList locate(LinkList head,ElemType item)
{
    LinkList p = head->next;
    while(p!=NULL&&p->val!=item)
        p = p->next;
    return p;
}
按序号查找
//查找成功,返回被查找节点地址,否则返回NULL
LinkList search(LinkList head,int i)
{
    int j = 0;
    LinkList p = head;
    while(p->next!=NULL&&j<i)
    {
        p = p->next;
        j++;
    }
    if(j==i)
        return p;
    else
        return NULL;
}

插入

在这里插入图片描述

尾结点插入
void add_node(LinkList head,int item)
{
    /*链表并非自己创造,手动添加哨兵节点
    LinkList dummy=(LinkList)malloc(sizeof(LNode));
    dummy->next=head;
    LinkList p = dummy;
    */
    LinkList p = head;
    LinkList q=(LinkList)malloc(sizeof(LNode));
    q->val = item;
    q->next = NULL;
    while(p->next!=NULL)
    {
        p = p->next;
    }
    p->next = q;
}
节点后插入
void insert_tail(LinkList p,ElemType item)
{
    LinkList q=(LinkList)malloc(sizeof(LNode));
    q->val = item;
    q->next = p->next;
    p->next = q;
}
节点前插入
void insert_head(LinkList head,LinkList p,ElemType item)
{
    LinkList pre = head;
    LinkList q=(LinkList)malloc(sizeof(LNode));
    q->val = item;
    while(pre->next!=p&&pre->next!=NULL)
        pre = pre->next;//找到p的前驱节点
    if(pre->next!=NULL)
    {
        q->next = pre->next;
        pre->next = q;
    }
    /*
    也可以将节点插入p节点后,然后交换两个节点数据,时间复杂度降低
    LinkList q=(LinkList)malloc(sizeof(LNode));
    q->val = item;
    q->next = p->next;
    p->next = q;
    ElemType tem=p->val;
    p->val=q->val;
    q->val=tem;
    */
}
按位置插入
//返回1则插入成功,返回0则插入失败,第i-1个节点不存在
int insert_pos(LinkList head,int i,ElemType item)
{
    LinkList p,q=(LinkList)malloc(sizeof(LNode));
    q->next = item;
    p = search(head, i - 1);
    if(p==NULL)
        return 0;
    else
    {
        q->next = p->next;
        p->next = q;
        return 1;
    }
}
有序链表插入
void insert_seq(LinkList head,ElemType item)
{
    LinkList p, q, r;
    r=(LinkList)malloc(sizeof(LNode));
    r->val = item;
    p = head;
    q = head->next;
    while (q != NULL&&item>=q->val)
    {
        p = q;
        q = q->next;
    }
    r->next = q;
    p->next = r;
}

删除

在这里插入图片描述

删除指定节点
void delete_node(LinkList head,LinkList p)
{
    LinkList pre = head;
    while(pre->next!=p&&pre->next!=NULL)
        pre = pre->next;//找到p的前驱节点
    if(pre->next!=NULL)
    {
        pre->next = p->next;
        free(p);
    }
}
按值删除节点
void delete_data(LinkList head,ElemType item)
{
    LinkList p = head,q;
    while(p->next!=NULL)
    {
        if(p->next->val==item)
        {
            q = p->next;
            p->next = p->next->next;
            free(q);
        }
        p = p->next;
    }
}
按位置删除节点
int delete_pos(LinkList head,int i)
{
    LinkList p, q;
    p = search(head, i - 1);
    if(p==NULL)
        return -1;
    else if (p->next == NULL)
        return 0;
    else
    {
        q = p->next;
        p->next = q->next;
        free(q);
        return 1;
    }
}
删除链表
void delete_list(LinkList head)
{
    LinkList p = head->next,q;
    while(p!=NULL)
    {
        q = p->next;
        free(p);
        p = q;
    }
}

反转链表

在这里插入图片描述

void reverse_list(LinkList head)
{
    LinkList p = head->next,q;
    head->next = NULL;
    while(p)
    {
        q = p;
        p = p->next;
        q->next = head->next;
        head->next = q;
    }
}

循环链表查找

LinkList search_circle(LinkList head,ElemType item)
{
    LinkList p = head->next;
    while(p!=head)
    {
        if(p->val==item)
            return p;
        p = p->next;
    }
    return NULL;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值