【数据结构】3. 不带头节点的单链表(完整代码实现:初始化、尾插、尾删、头插、头删、任意位置的插入、任意位置的删除、获取有效元素的大小、查找、销毁)

SList.h

#pragma once 

typedef int DataType;

//定义节点
typedef struct SListNode
{
    DataType data;
    struct SListNode* next; //指向下一个节点,类型也是struct SListNode
}Node;

//初始化
//在函数操作中,如果需要修改head的指向,必须传递二级指针
void SListInit(Node** head);

//对于尾插、头插,没有节点需要head指向其他;尾删、头删,如果只有一个节点,需要让head指向空
//尾插
void SListPushBack(Node** head, DataType data);

//尾删
void SListPopBack(Node** head);

//头插
void SListPushFront(Node** head, DataType data);

//头删
void SListPopFront(Node** head);

//任意位置的插入,不牵扯到head
void SListInsert(Node* pos, DataType data);

//任意位置的删除
void SListErase(Node* pos);

//获得有效元素的大小,遍历,不牵扯到head
int SListSize(Node* head);

//查找,注意返回的是节点
Node* SListFind(Node* head, DataType data);

//销毁,所有节点没有了,head需要指向空
void SListDestroy(Node** head);

//测试
void SListPrint(Node* head);

SList.c

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#include "SList.h"

// head表示链表,  *head是操作链表(链表的首地址或者链表的首节点), **head是操作链表的第一个节点(即第一个元素的节点的地址)

//构造新节点(需要插入的节点和数)
Node* NewSListNode(DataType data)
{
    Node* node = (Node*)malloc(sizeof(Node)); //开辟Node结构体的大小
    if(NULL == node) //不能用assert
    {
        exit(0);
        return NULL;
    }

    node->data = data;
    node->next = NULL; //并不知道下一个节点是谁,给成空

    return node;
}

//初始化
//在函数操作中,如果需要修改head的指向,必须传递二级指针。**head就是第一个元素的节点的地址
void SListInit(Node** head)
{
    assert(head);
    *head = NULL;
}

//尾插
void SListPushBack(Node** head, DataType data)
{
    assert(head); 

    //1.当链表为空链表
    if(NULL == *head)
    {
        *head = NewSListNode(data); //构造一个新的链表
    }
    else
    {
        //2.当链表非空
        //2.1 找到链表中的最后一个节点
        Node* cur = *head;
        while(cur->next)  //当cur->next == NULL,则cur是最后一个节点
        {
            cur = cur->next;
        }
        
        cur->next = NewSListNode(data);
    }
}

//尾删
void SListPopBack(Node** head)
{
    assert(head);

    if(NULL == *head)   //空链表,什么都没有
        return;
    else if(NULL == (*head)->next)  //链表中只有一个节点
    {
        free(*head);
        *head = NULL;
    }
    else  //链表中有多个节点 
    {
        //找到链表中最后一个节点,并保存其前一个节点,让其的下一个节点指向空
        Node* cur = *head;
        Node* pre = NULL; //用来保存最后一个节点的前一个节点
        while(cur->next)
        {
            pre = cur; //pre是cur的前一个节点
            cur = cur->next; //cur是最后一个节点
        }

        free(cur); // 释放掉最后一个节点
        pre->next = NULL; //让pre的下一个节点指向空
    }
}

//头插
void SListPushFront(Node** head, DataType data)
{
    assert(head);

    Node* newNode = NewSListNode(data);

    newNode->next = *head;  //第一步:让新节点的下一个节点指向第一个元素的节点
    *head = newNode;  //第二步:让新的节点成为第一个节点
    
}

//头删
void SListPopFront(Node** head)
{
    
    Node* delNode = NULL; //声明变量delNode,不声明会出错
    
    assert(head);

    if(NULL == *head)
        return;
    
    delNode = *head; //先把第一个节点标记出来
    *head = delNode->next; //让下一个节点成为第一个节点
    free(delNode); //释放第一个元素的节点
}

//任意位置的插入,注意:只能往pos位置的后面插入,不能在pos位置之前插入,因为pos位置之前的节点并不知道
//如果要插入到pos之前,在执行上面的操作之后,只需交换两个节点的值域就可以
void SListInsert(Node* pos, DataType data)
{
    Node* newNode = NULL;
    if(NULL == pos)
        return;

    newNode = NewSListNode(data);
    newNode->next = pos->next;
    pos->next = newNode;
}

//任意位置的删除,只能删除pos位置之后的一个节点
//如果pos位置删除之后,就无法链接前面的节点
void SListErase(Node* pos)
{
    Node* delNode = NULL;
    if(NULL == pos || NULL == pos->next)
        return;

    delNode = pos->next;
    pos->next = pos->next->next;
    free(delNode);
}

//获取有效元素的大小
int SListSize(Node* head)
{
    int count = 0;
    Node* cur = head;
    while(cur)
    {
        ++count;
        cur = cur->next;
    }
    return count;
}

//查找
Node* SListFind(Node* head, DataType data)
{
    Node* cur  = head;
    while(cur)
    {
        if(data == cur->data)
            return cur;	

        cur = cur->next;
    }
    return NULL; //没有找到这个节点,则返回空
}

//销毁,采用头删法进行销毁
void SListDestroy(Node** head)
{
    Node* delNode = NULL;
    assert(head);
    while(NULL != *head)
    {
        delNode = *head;
        free(delNode);
        *head = delNode->next;
    }
}

//测试
void SListPrint(Node* head)
{
    Node* cur = head;
    while(cur)
    {
        printf("%d--->",cur->data);
        cur = cur->next;
    }

    printf("NULL\n");
}

test.c

#include <stdio.h>

#include "SList.h"

int main()
{
    Node* head;
    SListInit(&head); //head是指针,需要取地址
    SListPushBack(&head, 1);
    SListPushBack(&head, 2);
    SListPushBack(&head, 3);
    SListPushBack(&head, 4);
    SListPushBack(&head, 5);
    SListPushBack(&head, 6);
    SListSize(head);
    SListPrint(head);

    SListPopBack(&head);
    SListSize(head);
    SListPrint(head);

    SListPushFront(&head, 0);
    SListPushFront(&head, 9);
    SListSize(head);
    SListPrint(head);

    SListPopFront(&head);
    SListSize(head);
    SListPrint(head);

    SListInsert(SListFind(head,3),8);
    SListSize(head);
    SListPrint(head);

    SListErase(SListFind(head,2));
    SListSize(head);
    SListPrint(head);

    return 0;
}

链表插入和删除的图例

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值