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

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

链表:结点和结点相连

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

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

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

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

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

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

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

链表操作:增删改查

单链表操作:

结构体作为结点

复制代码
//定义一个结构体结点
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;

链表优缺点:

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

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

相关推荐
dtq04249 小时前
数据结构 - 线性表 - 双向链表
c语言·数据结构·学习
晊晌_h17 小时前
嵌入式从0到精通——数据结构总结[特殊字符]
数据结构·算法·排序算法
我找到地球的支点啦18 小时前
Matlab系列(009) 一CRC循环冗余校验详解
开发语言·数据结构·算法·matlab·信息与通信
lisin-lee-cooper1 天前
【leetcode658】有序数组找出k个最接近x的数
java·数据结构·算法
sunburn-1 天前
Java堆(Heap)详解与实战教学
java·开发语言·数据结构·ide·算法
哭泣方源炼蛊1 天前
并查集进阶 P1(带权并查集,并查集分类)
数据结构·c++·算法·二进制·带权并查集
五_谷_丰_登1 天前
平衡二叉树(AVL)讲解二
数据结构·c++
fpcc1 天前
数据结构和算法—最短路径的算法
数据结构·算法
Mr. zhihao1 天前
从数组到 B+ 树:一棵树的进化史
数据结构·innodb·b+树
船厂电气自动化ai大模型1 天前
AI大模型与数学第64课:矩阵×向量乘法(神经网络矩阵运算底层)
数据结构·深度学习·线性代数·机器学习·推荐算法