数据结构-单链表

单链表

//单链表属于线性表

一、单链表的概念

单链表是什么?

链表是数据结构中线性表的一种,其中的每个元素实际上是一个单独的结构体对象,而所有对象都通过每个元素中的指针链接在一起。它是以结构体为节点,将一个结构体看成数据域和指针域两个部分,数据域用于存储数据,指针域用于连接下一个节点。链表中每个结构体对象叫做节点,其中第一个数据节点叫做链表的首元节点;如果第一个节点不用于存储数据,只用于代表链表的起始点,则这个节点称为链表的头节点。

单链表的特点:

1、单链表没有固定的长度,可以自由增加节点。 2、单链表能够实现快速的插入删除数据。 3、与数组类似,单链表也是一种线性数据结构。 4、单链表的尾结点的后继必定指向空。 单链表和数组的区别:数组是顺序存储的,而单链表是链式存储的。

单链表的节点类型

//结构体类型:单链表节点的类型
struct node
{
    int id;//节点要保存的数据
    struct node*next;//指针成员:指向下一个节点
};

二、单链表的初始化

//初始化单链表
//申请一个头节点:让head指向这个节点
//头节点:不保存数据,单链表开头的标志
struct node* init()
{
    //temp是一个临时指针变量:保存从堆区申请的内存首地址
    struct node*temp = (struct node*)malloc(sizeof(struct node));
    temp->id = 0;
    temp->next = NULL;
    return temp;
}

三、单链表元素的增加

//头插法三步骤
//1、申请新节点,把数据放进这个新节点S
//2、新节点S指针域保存头节点的下一个节点的地址
//3、头节点指针保存新节点S的地址
void insert(struct node*head,int data)//data:要增加的元素值
{
    //1、申请新节点,把数据放进这个新节点S
    struct node*S = (struct node*)malloc(sizeof(struct node));
    S->id = data; //新节点保存要增加的元素值
    //2、新节点S指针域保存头节点的下一个节点的地址
    S->next = head->next;
    //3、头节点指针保存新节点S的地址
    head->next = S;
}
​
//尾插法
//1、定义一个指针变量P,P用来保存当前单链表中的最后一个节点的地址
//2、定义一个指针变量S,申请一个新的节点(保存要增加的数据),生成新节点S
//3、新节点S指针为空,节点P的指针域指向新节点S
void insertEnd(struct node*head, int data)
{
    //1、定义一个指针变量P,P用来保存当前单链表中的最后一个节点的地址
    struct node*p = head;
    while (p->next != NULL)//P不是单链表中最后一个节点
    {
        //p++;//不可以的,因为内存 不连续
        p = p->next;//p指向下一个节点
    }
    //循环执行完之后,p指向单链表中的最后一个节点
    //2、定义一个指针变量S,申请一个新的节点(保存要增加的数据),生成新节点S
    struct node*S = (struct node*)malloc(sizeof(struct node));
    S->id = data; //新节点保存要增加的元素值
​
    //3、新节点S指针为空,节点P的指针域指向新节点S
    S->next = p->next;
    p->next = S;
}

四、输出单链表中的所有元素

void print(struct node*head)
{
    if (head == NULL)
    {
        printf("单链表不存在\n\n");
        return;
    }
    struct node*p = head->next;
​
    while (p != NULL)//是p指向下一个节点,当p是最后一个节点之后的NULL,结束循环
    {
        printf("%d --> ", p->id);
        p = p->next;
    }
    printf("NULL\n\n");
}

五、单链表元素的删除

/**************单链表——元素的删除*****************/
//1、定义两个指针变量P1、P2,P1指向头节点,P2指向头节点的下一个节点
//2、使用循环,使P1、P2同时往后移,当P2指向要删除的这个节点时,结束循环
//3、P1指向的节点里面的指针  保存 P2 下一个节点的地址
//4、释放P2指向的节点
void del(struct node*head,int val)//val表示要被删除的值
{
    //P1指向删除节点的前驱节点
    //P2指向删除节点
    struct node*P1 = head;
    struct node*P2 = head->next;
    while (P2 != NULL)//P2不为NULL,正在遍历单链表中的数据
    {
        if (P2->id == val)//当P2指向要被删除的节点时
        {
            P1->next = P2->next;
            free(P2);
            P2 = P1->next;
        }
        else//两个指针变量同时往后移
        {
            P1 = P1->next;
            P2 = P2->next;
        }
    }
}

六、单链表元素的查找

int find(struct node*head, int val)//val表示要查找的值
{
    int flag = 0;//标记是第几个节点
    struct node*p = head->next;
    while (p != NULL)
    {
        flag++;
        if (p->id == val)//找到要查找的值
        {
            printf("这个值:%d  在第 %d 个位置\n\n", p->id,flag);
        }
        p = p->next;
    }
    return val;
}

七、单链表元素的修改

void change(struct node*head, int val,int data)//val表示要被修改的值 ,data要被修改成的值
{
    struct node*p = head->next;
    while (p != NULL)
    {
        if (p->id == val)//找到要查找的值
        {
            p->id = data;
        }
        p = p->next;
    }
}

八、整个链表节点的释放

//需要改变主函数中head的值吗? 需要
void Allclear(struct node**list)//&head传过来  list=&head
{
    struct node*p = (*list)->next;//p指向头节点的下一个节点
    while (p != NULL)
    {
        //1、头节点里面的指针成员  保存  p指向的下一个节点的地址
        //2、释放p节点
        //3、更新要删除的节点,p指向头节点后的第一个节点
        (*list)->next = p->next;
        free(p);
        p = (*list)->next;
    }
    free(*list);//释放头节点
    *list = NULL;
}

九、主函数

//***********单链表——头节点的初始化
    //头指针变量——保存单链表节点的首地址
    struct node* head = NULL;
    head = init();
​
    //单链表元——元素的增加
        //头插法
    for (int j = 1; j <= 5; j++)
    {
        insert(head, j);
    }
    print(head);
​
        //尾插法
    for (int j = 1; j <= 5; j++)
    {
        insertEnd(head, j);
    }
    print2(head);
​
    //单链表元——元素的删除
    del(head, 3);
    print(head);
​
    //单链表元——元素的查找、修改
    find(head, 3);
    change(head, 3, 66);
    print(head);
​
    //单链表元——节点的释放
    Allclear(&head);
    printf("%p", head);
    print(head);
​
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为阿根廷助威

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值