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

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

链表:结点和结点相连

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

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

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

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

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

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

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

链表操作:增删改查

单链表操作:

结构体作为结点

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

链表优缺点:

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

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

相关推荐
黑岚樱梦5 分钟前
代码随想录打卡day25:56.合并区间
数据结构·算法
小年糕是糕手30 分钟前
【数据结构】常见的排序算法 -- 插入排序
c语言·开发语言·数据结构·学习·算法·leetcode·排序算法
墨染点香1 小时前
LeetCode 刷题【142. 环形链表 II】
算法·leetcode·链表
Cx330❀2 小时前
《C++ 搜索二叉树》深入理解 C++ 搜索二叉树:特性、实现与应用
java·开发语言·数据结构·c++·算法·面试
墨染点香5 小时前
LeetCode 刷题【144. 二叉树的前序遍历】
数据结构·算法·leetcode
im_AMBER12 小时前
算法笔记 09
c语言·数据结构·c++·笔记·学习·算法·排序算法
凯芸呢12 小时前
Java中的数组(续)
java·开发语言·数据结构·算法·青少年编程·排序算法·idea
AI柠檬13 小时前
几种排序算法的实现和性能比较
数据结构·算法·c#·排序算法
zz07232015 小时前
数据结构 —— 栈
数据结构
Madison-No716 小时前
【C++】关于list的使用&&底层实现
数据结构·c++·stl·list·模拟实现