线性表的链式存储实现称为链表。
 每一个节点都需要一个结构体变量存储。
前一个节点的指针域指向下一个节点的数据域起始位置。
最后一个节点的指针域内存储的是NULL(即0)。
每一个节点都需要一个结构体变量存储。
前一个节点的指针域指向下一个节点的数据域起始位置。
最后一个节点的指针域内存储的是NULL(即0)。
 ::: tip
为了简单,考研设计时,单链表都会包含头节点,业界不使用。
头指针L指向的空间称为头节点,认为是0号位置,a1称为第一个节点。考研时认为头节点的数据域为空。
列表为空表示a1-an不存在。
:::
链表的初始化插入:
::: tip
为了简单,考研设计时,单链表都会包含头节点,业界不使用。
头指针L指向的空间称为头节点,认为是0号位置,a1称为第一个节点。考研时认为头节点的数据域为空。
列表为空表示a1-an不存在。
:::
链表的初始化插入:
 如下图,插入时的新节点q需要使用malloc申请一个结构体大小的空间(sizeof(LNode)),再强转成结构体指针的类型:
如下图,插入时的新节点q需要使用malloc申请一个结构体大小的空间(sizeof(LNode)),再强转成结构体指针的类型:
 上图中,q->data为数据域,q->next为指针域。p->next为第一个节点a1的地址,保存在头节点p中。
链表的删除、查询:
上图中,q->data为数据域,q->next为指针域。p->next为第一个节点a1的地址,保存在头节点p中。
链表的删除、查询:
 上图中的第一二行代码作用是确定p和q节点的位置,i为删除位置,
::: warning
  每一个节点的空间都是malloc出来的,删除节点后必须free。
:::
上图中的第一二行代码作用是确定p和q节点的位置,i为删除位置,
::: warning
  每一个节点的空间都是malloc出来的,删除节点后必须free。
:::
 上图中while循环中的p用来控制是否遍历到列表的尾部(最后一个元素的指针域是NULL)
上图中while循环中的p用来控制是否遍历到列表的尾部(最后一个元素的指针域是NULL)
 ::: tip
  while循环中的p!=NULL和p等价。
:::
::: tip
  while循环中的p!=NULL和p等价。
:::
头插法新建链表
头插法是每次新增节点时从头节点后的位置插入链表。
流程如下:
 头插法代码:
头插法代码:
#include <stdio.h>
#include <stdlib.h>
typedef int Elemtype;
typedef struct LNode
{
    Elemtype data;
    struct LNode* next;
}LNode,*LinkList;
//LNode*是结构体指针,等同于LinkList,写*LinkList只是为了方便认为是链表而非结构体节点指针
//void list_head_insert(LNode* &L)
//{
//    L = (LinkList)malloc(sizeof(LNode));  //申请头节点空间(头指针指向头节点)
//    //malloc开辟的空间默认是void类型,上述代码中LinkList可以换成LNode*
//    Elemtype x;  //读取的元素值放在第一个节点上(头节点是空的),需要再申请一个节点
//    L->next = NULL;
//    scanf("%d", &x);
//    //申请第一个节点空间
//    LNode* s = (LinkList)malloc(sizeof(LNode));
//    s->data = x;
//    s->next = NULL;  //头插法中第一个创建的节点会变为最后一个节点,需要将next设置成NULL
//    L->next = s;  //使得L的next(指针域)指向第一个节点
//    while (x!=9999)
//    {
//        scanf("%d", &x);
//        s = (LinkList)malloc(sizeof(LNode));  //s指向新开辟的节点
//        s->data = x;
//        s->next = L->next;  //新节点的next值为头节点L的next,即指向上一个创建的节点
//        L->next = s;  //头节点的next指向新建的节点
//    }
//}
//上述函数在插入节点时会插入最后一个作为结束标志的9999的数据,函数改进如下:
void list_head_insert(LNode*& L)
{
    L = (LinkList)malloc(sizeof(LNode));  //申请头节点空间(头指针指向头节点)
    //malloc开辟的空间默认是void类型,上述代码中LinkList可以换成LNode*
    Elemtype x;  //读取的元素值放在第一个节点上(头节点是空的),需要再申请一个节点
    L->next = NULL;  //循环中将L的next赋给第一次循环创建的节点的next,即链表最后一个节点
    scanf("%d", &x);  //供while循环判断是否结束
    //申请第一个节点空间
    LNode* s = (LinkList)malloc(sizeof(LNode));
    while (x != 9999)
    {
        s = (LinkList)malloc(sizeof(LNode));  //s指向新开辟的节点
        s->data = x;
        s->next = L->next;  //新节点的next值为头节点L的next,即指向上一个创建的节点
        L->next = s;  //头节点的next指向新建的节点(头插法新建的节点在头节点后面一个位置)
        scanf("%d", &x);
    }
}
void print_list(LinkList L)
{
    L = L->next;
    while (L != NULL)
    {
        printf("%3d", L->data);
        L = L->next;
    }
}
int main()
{
    LinkList L;  //等同于LNode* L
    list_head_insert(L);
    print_list(L);
    return 0;
}尾插法新建链表
流程如下:

链表的增删查改操作:
//输入9999表示输入结束
#include <stdio.h>
#include <stdlib.h>
typedef int Elemtype;
typedef struct LNode
{
    Elemtype data;
    struct LNode* next;
}LNode, * Linklist;
//尾插法插入
void list_tail_insert(Linklist& L)
{
    L = (LNode*)malloc(sizeof(LNode));  //头节点
    L->next = NULL;
    LNode* s, * r = L;  //r->next=NULL;
    Elemtype x;
    scanf("%d", &x);
    while (x != 9999)
    {
        s = (LNode*)malloc(sizeof(LNode));
        r->next = s;
        s->data = x;
        r = s;
        scanf("%d", &x);
    }
    r->next = NULL;
}
//节点查找
LNode* value_find(LNode* L,Elemtype x)
{
    Elemtype a = 0;
    if (x < 0)
    {
        return NULL;
    }
    while (L && a < x)
    {
        L = L->next;
        a++;
    }
    /*printf("%d\n", L->data);*/
    return L;
}
//值插入
bool value_insert(LNode* L, Elemtype x, Elemtype y)  //在某位置上插入节点
{
    Elemtype i = 0;
    LNode* s = value_find(L, x - 1);  //找到要插入位置的前一个节点
    if (s == NULL)
    {
        return false;
    }
    LNode* q = (LNode*)malloc(sizeof(LNode));  //新节点
    q->data = y;
    q->next = s->next;
    s->next = q;
    return true;
}
//删除节点
bool Dele_list(LNode* L, Elemtype x)
{
    //1.调用位置查找函数
    LNode* p = value_find(L, x - 1);  //要删除节点的前一个节点
    if (p == NULL)
    {
        return false;
    }
    LNode* q = p->next;  //要删除的节点
    p->next = q->next;
    free(q);
    return true;
    //2.直接遍历查找
    //Elemtype i = 0;
    //while (L && i < x - 1)
    //{
    //    L = L->next;
    //    i++;
    //}
    //LNode* s = L;
    //L = L->next;
    //s->next = L->next;
    //free(L);
    //return true;
}
//打印节点
void Print_list(LNode* L)
{
    L = L->next;
    while (L)
    {
        printf("%3d", L->data);
        L = L->next;
    }
    printf("\n");
}
int main()
{
    LNode* L;
    list_tail_insert(L);
    LNode* search = value_find(L, 2);
    if (search != NULL)
    {
        printf("%d\n", search->data);
    }
    int ret = 0;
    ret = value_insert(L, 2, 99);
    if (ret)
    {
        Print_list(L);
    }
    else
    {
        printf("false\n");
    }
    ret = Dele_list(L, 4);
    if (ret)
    {
        Print_list(L);
    }
    return 0;
} 
  
  
  
 

 
 
 
 
