数据结构之---线性表其二---单向链表

线性表的链式存储结构---用链式存储结构实现的线性表就叫(单向)链表

链表:结点和结点相连

结点:包含数据域和指针域

头指针:保存第一个结点地址的指针,头指针通过标记第一个结点,从而标记了整个链表,因此用头指针来命名整个链表。

链表分为带头结点的链表和不带头结点的链表

头结点:带头结点的链表的第一个结点(头结点数据域有数据但不是程序员放的,是随机的,只要分配了空间就是有数据的)

首元结点:保存线性表中第一个数据的结点

第一个节点:头指针指向的结点

链表包含:头指针和结点(或头结点)

链表操作:增删改查

单链表操作:

结构体作为结点

复制代码
//定义一个结构体结点
typedef struct Node
{
    int data;//存储数据
    struct Node *next;//下一个结点地址
}Node,*LinkList;

(1)初始化

复制代码
//初始化单链表,定义一个头结点
LinkList InitLinkList(){
    Node *node = (Node*)malloc(sizeof(Node));
    if(node!=NULL)
    {
    node->next = NULL;
    return node;
    }else{
        printf("内存申请失败\n");
        return node;
    }
    /*
    这样行吗?
    Node d;
    d.next = NULL;
    return &d;
    答案是不行的,
    因为d是一个变量,存放在栈区,当函数调用完毕之后该变量内存会被系统回收,此时&d = NULL;
    */
}

(2)添加数据

头插法:

复制代码
//头插法(在头结点后一个位置添加数据k)
LinkList headInsert(LinkList l,int k){
    //1.新结点s
    Node *s = (Node*)malloc(sizeof(Node));
    //2.加入数据
    if(s!=NULL)
    {
    s->data = k;
    //3.指针域指向首元结点,因为是在头结点和首元结点之间插入数据
    s->next = l->next;//
    //4.头结点指向s;
    l->next = s;

    return l;
    }else{
        printf("内存申请失败\n");
        return s;
    }
}

尾插法:

复制代码
//尾插法
LinkList rearInsert(LinkList l,int k){
    Node *s = (Node*)malloc(sizeof(Node));
    if(s!=NULL)
    {
    s->data = k;
    s->next = NULL;
    Node *n = l;
    while(n->next!=NULL)
    {
        n = n->next;
    }
    n->next = s;
    return l;
    }else{
        printf("内存申请失败\n");
        return s;
    }
}

中间插入(在数据x后面插入数据k):

复制代码
//指定位置插入在x后面插入k
LinkList middleInsert(LinkList l,int x,int k){
    Node *s = (Node*)malloc(sizeof(Node));
    if(s == NULL)
    {
        printf("内存申请失败\n");
        return l;
    }
    s->data = k;
    Node *n = Find(l,x);
    if(n!=NULL)
    {
        s->next = n->next;
        n->next = s;
        return l;
    }else{
        printf("查无此数据\n");
        return l;
    }

}

(3)查找

复制代码
//查找
Node *Find(LinkList l,int k){
    Node *p = l->next;//从首元结点开始找
    while(p!=NULL)
    {
        if(p->data == k)
        {
            return p;
        }else{
            p = p->next;
        }
    }
    return p;
}

(4)删除

改正:第三行是从首元结点开始

复制代码
//删除结点x
LinkList delete(LinkList l,int x){
    Node *s = l->next;//从头结点开始
    Node *preS = l;//指向前一个结点
    while(s!=NULL&&s->data!=x)
    {
        preS = s;
        s = s->next;
    }
    if(s == NULL)
    {
        printf("%d不存在\n",x);
        return l;
    }
    preS->next = s->next;
    free(s);//释放空间,但地址值依然保存
    s = NULL;//防止野指针情况出现
    return l;

}

(5)输出

复制代码
//输出
void printff(LinkList l){
    Node *s = l->next;
    if(s == NULL)
    {
        printf("空指针\n");
    }
    while(s!=NULL)
    {
        printf("%d ",s->data);
    }
}

(6)修改

复制代码
//修改结点数据y为k
LinkList changeNode(LinkList l ,int y,int k){
    Node *n = Find(l,y);
    if(n == NULL)
    {
        printf("查无此数据\n");
        return l;
    }
    n->data = k;
    return l;

链表优缺点:

优点:灵活,便捷,因为要修改链表中的某一个数据时,不用移动其他的数据

缺点: 不支持随机存取,只能从头指针开始查找。

相关推荐
晚枫歌F32 分钟前
最小堆定时器
数据结构·算法
嫩萝卜头儿2 小时前
2 - 复杂度收尾 + 链表经典OJ
数据结构·算法·链表·复杂度
样例过了就是过了2 小时前
LeetCode热题100 分割等和子集
数据结构·c++·算法·leetcode·动态规划
木木_王3 小时前
嵌入式Linux学习 | 数据结构 (Day05) 栈与队列详解(原理 + C 语言实现 + 实战实验 + 易错点剖析)
linux·c语言·开发语言·数据结构·笔记·学习
北顾笙9803 小时前
day38-数据结构力扣
数据结构·算法·leetcode
m0_629494733 小时前
LeetCode 热题 100-----14.合并区间
数据结构·算法·leetcode
@小码农4 小时前
2026年3月Scratch图形化编程等级考试一级真题试卷
开发语言·数据结构·c++·算法
_日拱一卒5 小时前
LeetCode:226翻转二叉树
数据结构·算法·leetcode
风筝在晴天搁浅7 小时前
手撕快速排序
数据结构
图码7 小时前
矩阵数据结构入门指南:声明、初始化与基本操作
运维·数据结构·线性代数·算法·矩阵