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

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

链表:结点和结点相连

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

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

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

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

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

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

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

链表操作:增删改查

单链表操作:

结构体作为结点

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

链表优缺点:

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

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

相关推荐
CYH&JK5 小时前
数据结构---双向链表
数据结构·链表
郝YH是人间理想11 小时前
408考研——单链表代码题常见套路总结
c语言·数据结构·c++·考研·链表
闪电麦坤9511 小时前
数据结构:哈希(Hashing)
数据结构·算法·哈希算法
野犬寒鸦12 小时前
力扣hot100:矩阵置零(73)(原地算法)
java·数据结构·后端·算法
J_HelloWorld12 小时前
从检索的角度聊聊数据结构的演进
数据结构
only-qi16 小时前
leetcode110. 平衡二叉树
数据结构·算法
萘柰奈16 小时前
Unity学习----【数据持久化】二进制数据(五)--由Excel自动生成数据结构类与二进制文件
数据结构·学习·unity
笨笨的摸索17 小时前
链表题类型注解解惑:理解Optional,理解ListNode
数据结构·经验分享·链表
你说今年的枫叶好像不够红啊17 小时前
LeetCode[两数之和] java版
数据结构·算法·leetcode